Skip to content
Snippets Groups Projects
libwrtd.c 65.7 KiB
Newer Older
/**
 * @file libwrtd.c
 *
 * Copyright (c) 2018-2019 CERN (home.cern)
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#include "mockturtle/libmockturtle.h"
#include "libwrtd.h"
#include "libwrtd-private.h"

Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Functions to manage the basic Node and library configuration.
/**
 * Retrieve the number of detected WRTD Nodes.
 *
 * @param[out] count number of detected WRTD Nodes
 * @return #wrtd_status
 */
wrtd_status wrtd_get_node_count(uint32_t *count)
{
        int i;
        uint32_t dev_count = 0;
        struct trtl_dev *trtl;
        const struct trtl_config_rom *cfgrom;

        char **dev_list = trtl_list();

        if (!dev_list)
                return WRTD_ERROR_INTERNAL;


        for (i = 0; dev_list[i]; i++) {
                trtl = trtl_open(dev_list[i]);
                if (trtl == NULL) {
                        trtl_list_free(dev_list);
                        return WRTD_ERROR_RESOURCE_UNKNOWN;
                }
                cfgrom = trtl_config_get(trtl);
                if (wrtd_node_id_match(cfgrom->app_id))
                        dev_count++;
                trtl_close(trtl);
        }

        trtl_list_free(dev_list);

        *count = dev_count;

        return WRTD_SUCCESS;
}

/**
 * Retrieve the ID of a WRTD Node.
 *
 * Before calling this function, you should probably call #wrtd_get_node_count to know the
 * number of Nodes.
 *
 * @param[in]  index The index of the Node ("1" for the first Node, etc.)
 * @param[out] node_id The retrieved ID of the Node
 * @return #wrtd_status
 */
wrtd_status wrtd_get_node_id(uint32_t index, uint32_t *node_id)
{
        int i;
        uint32_t dev_count = 0;
        struct trtl_dev *trtl;
        const struct trtl_config_rom *cfgrom;

        char **dev_list = trtl_list();

        if (!dev_list)
                return WRTD_ERROR_INTERNAL;

        *node_id = 0;

        for (i = 0; dev_list[i]; i++) {
                trtl = trtl_open(dev_list[i]);
                if (trtl == NULL) {
                        trtl_list_free(dev_list);
                        return WRTD_ERROR_RESOURCE_UNKNOWN;
                }
                cfgrom = trtl_config_get(trtl);
                if (wrtd_node_id_match(cfgrom->app_id))
                        dev_count++;
                if (dev_count == index) {
                        char *eptr;
                        /* expecting string in the form of "trtl-xxxx, where
                         xxxx is a hex integer */
                        *node_id = strtoul(dev_list[i]+5, &eptr, 16);
                        if (*eptr != 0) {
                                trtl_list_free(dev_list);
                                trtl_close(trtl);
                                return WRTD_ERROR_INTERNAL;
                        }
                }
                trtl_close(trtl);
        }

        trtl_list_free(dev_list);

        if (*node_id == 0)
                return WRTD_ERROR_RESOURCE_UNKNOWN;

       return WRTD_SUCCESS;
}

Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Initialize the WRTD Node and obtain the WRTD device token.
 * @param[in]  node_id       WRTD Node ID
Tristan Gingold's avatar
Tristan Gingold committed
 * @param[in]  reset         Reset node.
 * @param[in]  options_str   Reserved for future use.
 * @param[out] wrtd          Pointer to WRTD device token.
 * @return #wrtd_status
 */
wrtd_status wrtd_init(uint32_t node_id,
                      bool reset,
                      const char *options_str,
                      wrtd_dev **wrtd)
        int i;
        struct trtl_dev *trtl;
        const struct trtl_config_rom *cfgrom;
        struct wrtd_config_msg msg;
        wrtd_status status;

        /* In case of error...  */
        *wrtd = NULL;
        trtl = trtl_open_by_id(node_id);
        if (trtl == NULL)
                return WRTD_ERROR_RESOURCE_UNKNOWN;

        wrtd_dev *res;
        res = malloc(sizeof(wrtd_dev));
        if (res == NULL)
                return WRTD_ERROR_OUT_OF_MEMORY;
        memset(res, 0, sizeof(*res));

        res->trtl = trtl;

        cfgrom = trtl_config_get(res->trtl);

        if (cfgrom->n_cpu > WRTD_MAX_CPUS)
                return wrtd_return_error(res, WRTD_ERROR_INTERNAL,
                                         "%s: Too many CPUs detected.", __func__);

        /* Set HMQ words.  */
        for (i = 0; i < cfgrom->n_cpu; i++) {
                if (cfgrom->n_hmq[i] > 0)
                        res->hmq_words[i] = TRTL_CONFIG_ROM_MQ_SIZE_PAYLOAD
                                (cfgrom->hmq[i][0].sizes);

        for (i = 0; i < cfgrom->n_cpu; i++) {
                status = wrtd_msg_get_config(res, i, &msg, __func__);
                WRTD_RETURN_IF_ERROR(status);
                res->root_addr[i] = msg.root_addr;
        }

        for (i = 0; i < cfgrom->n_cpu; i++) {
                if (trtl_fw_version(res->trtl, i, WRTD_HMQ, &res->fw_version[i]) < 0)
                        return wrtd_return_error(
                                res, WRTD_ERROR_INTERNAL,
                                "%s: Could not retrieve firmware vesion info (%s)",
                                __func__, trtl_strerror(errno));
        }

        res->nbr_cpus = cfgrom->n_cpu;

        *wrtd = res;
        if (reset) {
                status = wrtd_reset(res);
                if (status != WRTD_SUCCESS)
                        return status;
        }

        return WRTD_SUCCESS;
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Close a WRTD Node and release all resources.
 *
 * @param[in]  wrtd        Device token.
 * @return #wrtd_status
 */
wrtd_status wrtd_close(wrtd_dev *wrtd)
Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
        trtl_close(wrtd->trtl);
        free(wrtd->alarms);
        free(wrtd->rules);
        free(wrtd);
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Reset a WRTD Node. This will remove all defined Alarms and Rules.
 *
 * @param[in]  wrtd        Device token.
 * @return #wrtd_status
 */
wrtd_status wrtd_reset(wrtd_dev *wrtd)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_disable_all_alarms(wrtd);
        WRTD_RETURN_IF_ERROR(status);
        status = wrtd_disable_all_rules(wrtd);
        WRTD_RETURN_IF_ERROR(status);
        status = wrtd_remove_all_alarms(wrtd);
        WRTD_RETURN_IF_ERROR(status);
        status = wrtd_remove_all_rules(wrtd);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Retrieve and clear the last error from the device.
 *
 * Modelled after the IVI-C GetError function.
 *
 * This function complies with IVI-3.2, section 3.1.2.1 (Additional Compliance Rules
 * for C Functions with ViChar Array Output Parameters), with the exception of
 * the buffer_size < 0 case, which produces an error instead of allowing a potential
 * buffer overflow.
 *
 * @param[in]  wrtd        Device token.
 * @param[out] error_code  #wrtd_status pointer to return the error code. Ignored if NULL.
 * @param[in]  error_description_buffer_size Size of pre-allocated `error_description` buffer.
 * @param[out] error_description Buffer to store the detailed error message string.
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * @return #wrtd_status. However, if the buffer size parameter is 0, then this function returns
 * instead a positive value, indicating the minimum buffer size necessary to fit the full message.
 * See also IVI-3.2, section 3.1.2.1.
wrtd_status wrtd_get_error(wrtd_dev *wrtd,
                           wrtd_status *error_code,
                           int32_t error_description_buffer_size,
                           char *error_description)
        wrtd_status status;
Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        char error_message[WRTD_ERR_MSG_BUF_SIZE];
        memset(error_message, 0, WRTD_ERR_MSG_BUF_SIZE);
        status = wrtd_error_message(wrtd, wrtd->err, error_message);
                strlen(error_message) + strlen(wrtd->error_msg) + 2;
        /* If buffer_size is zero, just report on necessary
           buffer size. According to IVI-3.2, section 3.1.2.1. */
        if (error_description_buffer_size == 0)
                return required_buffer_size;
Tristan Gingold's avatar
Tristan Gingold committed
        if (error_description == NULL) {
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_NULL_POINTER,
                         "Null pointer passed for function %s, "
                         "parameter error_description", __func__);
        /* This violates IVI-3.2, section 3.1.2.1 which dictates to
           ignore overflow if buffer_size is negative. Still, it is
           the safer thing to do.*/
        if (error_description_buffer_size < 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter error_description_buffer_size",
                                         error_description_buffer_size, __func__);

Tristan Gingold's avatar
Tristan Gingold committed
        if (error_code != NULL)
                *error_code = wrtd->err;

        ret = snprintf(error_description, error_description_buffer_size,
                       "%s %s", error_message, wrtd->error_msg);
        if (ret < error_description_buffer_size)
                status = WRTD_SUCCESS;
        else
                status = ret + 1;
        wrtd->err = 0;

        memset(wrtd->error_msg, 0, sizeof(wrtd->error_msg));

        return status;
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Convert a #wrtd_status error code to a string.
 *
 * Modelled after the IVI-C ErrorMessage function.
 * @param[in]  wrtd        Device token. Can be NULL to allow calling this function
 * even when initialisation has failed.
 * @param[in]  err_code    #wrtd_status error code to convert.
 * @param[out] err_message Buffer of at least #WRTD_ERR_MSG_BUF_SIZE bytes
 * to store the resulting string.
 * @return #wrtd_status
 */
wrtd_status wrtd_error_message(wrtd_dev *wrtd,
                               wrtd_status err_code,
                               char *err_message)
        if (err_message == NULL) {
                if (wrtd != NULL)
                        return wrtd_return_error
                                (wrtd, WRTD_ERROR_NULL_POINTER,
                                 "Null pointer passed for function %s, "
                                 "parameter err_message", __func__);

                return WRTD_ERROR_NULL_POINTER;
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE, "WRTD_SUCCESS");
                break;
        case WRTD_ERROR_INVALID_ATTRIBUTE:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_INVALID_ATTRIBUTE");
                break;
        case WRTD_ERROR_ATTR_NOT_WRITEABLE:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_ATTR_NOT_WRITEABLE");
                break;
        case WRTD_ERROR_ATTR_NOT_READABLE:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_ATTR_NOT_READABLE");
                break;
        case WRTD_ERROR_INVALID_VALUE:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
                break;
        case WRTD_ERROR_NOT_INITIALIZED:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
        case WRTD_ERROR_UNKNOWN_CHANNEL_NAME:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_UNKNOWN_CHANNEL_NAME");
                break;
        case WRTD_ERROR_OUT_OF_MEMORY:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
                break;
        case WRTD_ERROR_UNEXPECTED_RESPONSE:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_UNEXPECTED_RESPONSE");
                break;
        case WRTD_ERROR_RESOURCE_UNKNOWN:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_RESOURCE_UNKNOWN");
        case WRTD_ERROR_BADLY_FORMED_SELECTOR:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_BADLY_FORMED_SELECTOR");
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
        case WRTD_ERROR_ALARM_DOES_NOT_EXIST:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_ALARM_DOES_NOT_EXIST");
        case WRTD_ERROR_VERSION_MISMATCH:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_VERSION_MISMATCH");
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
        case WRTD_ERROR_UNKNOWN_LOG_TYPE:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_UNKNOWN_LOG_TYPE");
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
        case WRTD_ERROR_OUT_OF_RESOURCES:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_OUT_OF_RESOURCES");
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
                break;
        case WRTD_ERROR_RULE_DOES_NOT_EXIST:
                snprintf(err_message, WRTD_ERR_MSG_BUF_SIZE,
				"WRTD_ERROR_RULE_DOES_NOT_EXIST");
                if (wrtd != NULL)
                        return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                                 "Invalid value (%d) for function %s, "
                                                 "parameter err_code",
                                                 err_code, __func__);

                return WRTD_ERROR_INVALID_VALUE;
/**
 *@} End group Base
 */

/**
 * @defgroup Attributes
 * Functions to get/set WRTD attributes.
 * @{
 */

/**
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Set an attribute of type `bool`.
 *
 * Modelled after the IVI-C SetAttribute family of functions.
 *
 * @param[in]  wrtd       Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[in] value       Value to write to the attribute.
 * @return #wrtd_status
 */
wrtd_status wrtd_set_attr_bool(wrtd_dev *wrtd,
                               const char *rep_cap_id,
                               wrtd_attr id,
                               bool value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
        switch(id) {
        case WRTD_ATTR_EVENT_LOG_ENABLED:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                return wrtd_attr_set_log_enable
                        (wrtd, value);
        case WRTD_ATTR_ALARM_ENABLED:
                return wrtd_attr_set_alarm_enable
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_ENABLED:
                return wrtd_attr_set_rule_enable
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_SEND_LATE:
                return wrtd_attr_set_rule_send_late
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_EVENT_LOG_EMPTY:
        case WRTD_ATTR_IS_TIME_SYNCHRONIZED:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_ATTR_NOT_WRITEABLE,
                         "Attribute %u is read only.", id);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Get an attribute of type `bool`.
 *
 * Modelled after the IVI-C GetAttribute family of functions.
 *
 * @param[in]  wrtd     Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[out] value      Retrieved attribute value.
 * @return #wrtd_status
 */
wrtd_status wrtd_get_attr_bool(wrtd_dev *wrtd,
                               const char *rep_cap_id,
                               wrtd_attr id,
                               bool *value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
Tristan Gingold's avatar
Tristan Gingold committed
        if (value == NULL) {
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_NULL_POINTER,
                         "Null pointer passed for function %s, "
                         "parameter value", __func__);
        switch(id) {
        case WRTD_ATTR_EVENT_LOG_ENABLED:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                return wrtd_attr_get_log_enable
                        (wrtd, value);
        case WRTD_ATTR_EVENT_LOG_EMPTY:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                return wrtd_attr_get_log_empty
                        (wrtd, value);
        case WRTD_ATTR_IS_TIME_SYNCHRONIZED:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                return wrtd_attr_get_time_sync
                        (wrtd, value);
        case WRTD_ATTR_ALARM_ENABLED:
                return wrtd_attr_get_alarm_enable
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_ENABLED:
                return wrtd_attr_get_rule_enable
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_SEND_LATE:
                return wrtd_attr_get_rule_send_late
                        (wrtd, rep_cap_id, value);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Set an attribute of type `int32`.
 *
 * Modelled after the IVI-C SetAttribute family of functions.
 *
 * @param[in]  wrtd       Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[in] value       Value to write to the attribute.
 * @return #wrtd_status
 */
wrtd_status wrtd_set_attr_int32(wrtd_dev *wrtd,
                                const char *rep_cap_id,
                                wrtd_attr id,
                                int32_t value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
        switch(id) {
        case WRTD_ATTR_ALARM_REPEAT_COUNT:
                return wrtd_attr_set_alarm_repeat_count
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_REPEAT_COUNT:
                return wrtd_attr_set_rule_repeat_count
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_RESYNC_FACTOR:
                return wrtd_attr_set_rule_resync_factor
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_FW_COUNT:
        case WRTD_ATTR_FW_MAJOR_VERSION:
        case WRTD_ATTR_FW_MINOR_VERSION:
        case WRTD_ATTR_FW_MAJOR_VERSION_REQUIRED:
        case WRTD_ATTR_FW_MINOR_VERSION_REQUIRED:
        case WRTD_ATTR_FW_MAX_RULES:
        case WRTD_ATTR_FW_MAX_ALARMS:
        case WRTD_ATTR_FW_CAPABILITIES:
        case WRTD_ATTR_FW_LOCAL_INPUTS:
        case WRTD_ATTR_FW_LOCAL_OUTPUTS:
        case WRTD_ATTR_ALARM_COUNT:
        case WRTD_ATTR_RULE_COUNT:
        case WRTD_ATTR_STAT_RULE_RX_EVENTS:
        case WRTD_ATTR_STAT_RULE_TX_EVENTS:
        case WRTD_ATTR_STAT_RULE_MISSED_LATE:
        case WRTD_ATTR_STAT_RULE_MISSED_HOLDOFF:
        case WRTD_ATTR_STAT_RULE_MISSED_NOSYNC:
        case WRTD_ATTR_STAT_RULE_MISSED_OVERFLOW:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_ATTR_NOT_WRITEABLE,
                         "Attribute %u is read only.", id);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
        }
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Get an attribute of type `int32`.
 *
 * Modelled after the IVI-C GetAttribute family of functions.
 *
 * @param[in]  wrtd     Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[out] value      Retrieved attribute value.
 * @return #wrtd_status
 */
wrtd_status wrtd_get_attr_int32(wrtd_dev *wrtd,
                                const char *rep_cap_id,
                                wrtd_attr id,
                                int32_t *value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
Tristan Gingold's avatar
Tristan Gingold committed
        if (value == NULL) {
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_NULL_POINTER,
                         "Null pointer passed for function %s, "
                         "parameter value", __func__);
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                *value = wrtd->nbr_cpus;
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_MAJOR_VERSION:
                status = wrtd_attr_get_fw_major_version
                        (wrtd, rep_cap_id, value);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_MINOR_VERSION:
                status = wrtd_attr_get_fw_minor_version
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_MAJOR_VERSION_REQUIRED:
                status = wrtd_attr_get_fw_major_version_required
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_MINOR_VERSION_REQUIRED:
                status = wrtd_attr_get_fw_minor_version_required
                        (wrtd, rep_cap_id, value);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_MAX_RULES:
                status = wrtd_attr_get_fw_max_rules
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_MAX_ALARMS:
                status = wrtd_attr_get_fw_max_alarms
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_CAPABILITIES:
                status = wrtd_attr_get_fw_capabilities
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_LOCAL_INPUTS:
                status = wrtd_attr_get_fw_local_inputs
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_FW_LOCAL_OUTPUTS:
                status = wrtd_attr_get_fw_local_outputs
                        (wrtd, rep_cap_id, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_ALARM_COUNT:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                status = wrtd_attr_get_alarm_count
                        (wrtd, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_ALARM_REPEAT_COUNT:
                return wrtd_attr_get_alarm_repeat_count
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_COUNT:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                status = wrtd_attr_get_rule_count
                        (wrtd, value);
                WRTD_RETURN_IF_ERROR(status);
                return WRTD_SUCCESS;
        case WRTD_ATTR_RULE_REPEAT_COUNT:
                return wrtd_attr_get_rule_repeat_count
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_RESYNC_FACTOR:
                return wrtd_attr_get_rule_resync_factor
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_RX_EVENTS:
                return wrtd_attr_get_stat_rule_rx_events
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_TX_EVENTS:
                return wrtd_attr_get_stat_rule_tx_events
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_MISSED_LATE:
                return wrtd_attr_get_stat_rule_missed_late
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_MISSED_HOLDOFF:
                return wrtd_attr_get_stat_rule_missed_holdoff
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_MISSED_NOSYNC:
                return wrtd_attr_get_stat_rule_missed_nosync
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_MISSED_OVERFLOW:
                return wrtd_attr_get_stat_rule_missed_overflow
                        (wrtd, rep_cap_id, value);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
        }
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Set an attribute of type `string`.
 *
 * Modelled after the IVI-C SetAttribute family of functions.
 *
 * @param[in]  wrtd       Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[in] value       Value to write to the attribute.
 * @return #wrtd_status
 */
wrtd_status wrtd_set_attr_string(wrtd_dev *wrtd,
                                 const char *rep_cap_id,
                                 wrtd_attr id,
                                 const char *value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
        switch(id) {
        case WRTD_ATTR_RULE_SOURCE:
                return wrtd_attr_set_rule_source
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_DESTINATION:
                return wrtd_attr_set_rule_destination
                        (wrtd, rep_cap_id, value);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
        }
}
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * Get an attribute of type `string`.
 *
 * Modelled after the IVI-C GetAttribute family of functions.
 *
 * This function complies with IVI-3.2 section, 3.1.2.1 (Additional Compliance Rules
 * for C Functions with ViChar Array Output Parameters), with the exception of
 * the buffer_size < 0 case, which produces an error instead of allowing a potential
 * buffer overflow.
 *
 * @param[in]  wrtd     Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[in]  value_buffer_size Size of pre-allocated `value` buffer.
 * @param[out] value      Retrieved attribute value.
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 * @return #wrtd_status. However, if the buffer size parameter is 0, then this function returns
 * instead a positive value, indicating the minimum buffer size necessary to fit the full message.
 * See also IVI-3.2, section 3.1.2.1.
wrtd_status wrtd_get_attr_string(wrtd_dev *wrtd,
                                 const char *rep_cap_id,
                                 wrtd_attr id,
                                 int32_t value_buffer_size,
                                 char *value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);

                return wrtd_return_error
                        (wrtd, WRTD_ERROR_NULL_POINTER,
                         "Null pointer passed for function %s, "
                         "parameter value", __func__);
        switch(id) {
        case WRTD_ATTR_RULE_SOURCE:
                return wrtd_attr_get_rule_source
                        (wrtd, rep_cap_id, value_buffer_size, value);
        case WRTD_ATTR_RULE_DESTINATION:
                return wrtd_attr_get_rule_destination
                        (wrtd, rep_cap_id, value_buffer_size, value);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
 * Set an attribute of type `timestamp` (#wrtd_tstamp).
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 *
 * Modelled after the IVI-C SetAttribute family of functions.
 *
 * @param[in]  wrtd       Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[in] value       Value (#wrtd_tstamp) to write to the attribute.
 * If the `ns` part is greater or equal to 1e9, the `seconds` part will be
 * automatically increased and the `ns` part will be reduced accordingly.
 * @return #wrtd_status
 */
wrtd_status wrtd_set_attr_tstamp(wrtd_dev *wrtd,
                                 const char *rep_cap_id,
                                 wrtd_attr id,
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
Tristan Gingold's avatar
Tristan Gingold committed
        if (value == NULL) {
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_NULL_POINTER,
                         "Null pointer passed for function %s, "
                         "parameter value", __func__);
        while (value->ns >= 1e9) {
                value->seconds++;
                value->ns -= 1e9;
        }

        switch(id) {
        case WRTD_ATTR_ALARM_TIME:
                return wrtd_attr_set_alarm_time
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_ALARM_SETUP_TIME:
                return wrtd_attr_set_alarm_setup_time
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_ALARM_PERIOD:
                return wrtd_attr_set_alarm_period
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_DELAY:
                return wrtd_attr_set_rule_delay
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_HOLDOFF:
                return wrtd_attr_set_rule_holdoff
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_RESYNC_PERIOD:
                return wrtd_attr_set_rule_resync_period
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_SYS_TIME:
        case WRTD_ATTR_STAT_RULE_RX_LAST:
        case WRTD_ATTR_STAT_RULE_TX_LAST:
        case WRTD_ATTR_STAT_RULE_MISSED_LAST:
        case WRTD_ATTR_STAT_RULE_RX_LATENCY_MIN:
        case WRTD_ATTR_STAT_RULE_RX_LATENCY_MAX:
        case WRTD_ATTR_STAT_RULE_RX_LATENCY_AVG:
                        (wrtd, WRTD_ERROR_ATTR_NOT_WRITEABLE,
                         "Attribute %u is read only.", id);
        default:
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INVALID_ATTRIBUTE,
                         "Attribute ID %u is not recognized.", id);
        }
}
 * Get an attribute of type `timestamp` (#wrtd_tstamp).
Dimitris Lampridis's avatar
Dimitris Lampridis committed
 *
 * Modelled after the IVI-C GetAttribute family of functions.
 *
 * @param[in]  wrtd     Device token.
 * @param[in]  rep_cap_id ID (string) of concerned repeated capability.
 * If it is a global attribute, use #WRTD_GLOBAL_REP_CAP_ID
 * @param[in]  id         ID (#wrtd_attr) of concerned attribute.
 * @param[out] value      Retrieved attribute value (#wrtd_tstamp).
 * @return #wrtd_status
 */
wrtd_status wrtd_get_attr_tstamp(wrtd_dev *wrtd,
                                 const char *rep_cap_id,
                                 wrtd_attr id,
                                 wrtd_tstamp *value)
        wrtd_status status;

Tristan Gingold's avatar
Tristan Gingold committed
        if (wrtd == NULL)
                return WRTD_ERROR_NOT_INITIALIZED;
        status = wrtd_validate_id(wrtd, rep_cap_id, __func__);
        WRTD_RETURN_IF_ERROR(status);
Tristan Gingold's avatar
Tristan Gingold committed
        if (value == NULL) {
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_NULL_POINTER,
                         "Null pointer passed for function %s, "
                         "parameter value", __func__);
        case WRTD_ATTR_SYS_TIME:
                status = wrtd_attr_global
                        (wrtd, rep_cap_id);
                WRTD_RETURN_IF_ERROR(status);
                return wrtd_attr_get_sys_time
                        (wrtd, value);
        case WRTD_ATTR_ALARM_TIME:
                return wrtd_attr_get_alarm_time
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_ALARM_SETUP_TIME:
                return wrtd_attr_get_alarm_setup_time
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_ALARM_PERIOD:
                return wrtd_attr_get_alarm_period
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_DELAY:
                return wrtd_attr_get_rule_delay
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_HOLDOFF:
                return wrtd_attr_get_rule_holdoff
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_RULE_RESYNC_PERIOD:
                return wrtd_attr_get_rule_resync_period
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_RX_LAST:
                return wrtd_attr_get_stat_rule_rx_last
                        (wrtd, rep_cap_id, value);
        case WRTD_ATTR_STAT_RULE_TX_LAST: