/**
 * @file libwrtd-attributes.c
 *
 * Copyright (c) 2018-2019 CERN (home.cern)
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#include <errno.h>
#include "libwrtd.h"
#include "libwrtd-private.h"
#include "mockturtle/libmockturtle.h"

enum wrtd_status wrtd_attr_get_fw_major_version(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = RT_VERSION_MAJ(wrtd->fw_version[idx].rt_version);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_minor_version(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = RT_VERSION_MIN(wrtd->fw_version[idx].rt_version);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_major_version_required(struct wrtd_dev *wrtd,
                                                         const char *rep_cap_id,
                                                         int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->roots[idx].ver_major;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_minor_version_required(struct wrtd_dev *wrtd,
                                                         const char *rep_cap_id,
                                                         int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->roots[idx].ver_minor;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_max_rules(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->roots[idx].nbr_rules;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_max_alarms(struct wrtd_dev *wrtd,
                                             const char *rep_cap_id,
                                             int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->roots[idx].nbr_alarms;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_capabilities(struct wrtd_dev *wrtd,
                                               const char *rep_cap_id,
                                               int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->roots[idx].capabilities;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_local_inputs(struct wrtd_dev *wrtd,
                                               const char *rep_cap_id,
                                               int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;
        int32_t count;
        int i;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        for (count = 0, i = 0; i < wrtd->roots[idx].nbr_devices; i++)
                if (wrtd->roots[idx].devices_chs_dir[i] == WRTD_CH_DIR_IN)
                        count += wrtd->roots[idx].devices_nbr_chs[i];

        *value = count;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_fw_local_outputs(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;
        int32_t count;
        int i;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_fw(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        for (count = 0, i = 0; i < wrtd->roots[idx].nbr_devices; i++)
                if (wrtd->roots[idx].devices_chs_dir[i] == WRTD_CH_DIR_OUT)
                        count += wrtd->roots[idx].devices_nbr_chs[i];

        *value = count;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_alarm_count(struct wrtd_dev *wrtd,
                                           int32_t *value)
{
        enum wrtd_status status;
        unsigned i;
        int32_t res;

        status = wrtd_fill_alarms(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        res = 0;
        for (i = 0; i < wrtd->nbr_alarms; i++)
                if (!wrtd_id_null(wrtd->alarms[i].alarm.event.id))
                        res++;
        *value = res;
        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_alarm_period(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            const struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        if (value->seconds != 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter value.seconds",
                                         value->seconds, __func__);

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_alarm_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->alarms[idx].alarm.period_ns = value->ns;

        status = wrtd_write_alarm(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_alarm_period(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));
        wrtd_ts_add_ns(value, wrtd->alarms[idx].alarm.period_ns);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_alarm_setup_time(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                const struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_alarm_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->alarms[idx].alarm.setup_time = *value;

        status = wrtd_write_alarm(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_alarm_setup_time(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->alarms[idx].alarm.setup_time;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_alarm_time(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          const struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_alarm_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->alarms[idx].alarm.event.ts = *value;

        status = wrtd_write_alarm(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_alarm_time(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->alarms[idx].alarm.event.ts;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_alarm_enable(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            bool value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->alarms[idx].alarm.enabled = value;

        /* FIXME: may modify the rule mapping (eg: alarm is placed on cpu,
           and is needed to trigger a rule initially placed on a different cpu).
        */
        status = wrtd_write_alarm(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_alarm_enable(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            bool *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->alarms[idx].alarm.enabled != 0;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_alarm_repeat_count(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t value)
{
        enum wrtd_status status;
        unsigned int idx;

        if (value < 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter value", value, __func__);

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_alarm_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->alarms[idx].alarm.repeat_count = value;

        status = wrtd_write_alarm(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_alarm_repeat_count(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_alarm(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->alarms[idx].alarm.repeat_count;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_repeat_count(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 int32_t value)
{
        enum wrtd_status status;
        unsigned int idx;

        if (value < 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter value", value, __func__);

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->rules[idx].rule.conf.repeat_count = value;

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_repeat_count(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.conf.repeat_count;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_log_enable(struct wrtd_dev *wrtd,
                                          bool value)
{
        enum wrtd_status status;
        unsigned int cpu;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        for (cpu = 0; cpu < wrtd->nbr_cpus; cpu++) {
                wrtd->roots[cpu].log_flags = value ? 0xff : 0;
                status = wrtd_write_root_flags(wrtd, cpu, __func__);
                WRTD_RETURN_IF_ERROR(status);
        }

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_log_enable(struct wrtd_dev *wrtd,
                                          bool *value)
{
        enum wrtd_status status;

        status = wrtd_fill_roots(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        /* all cpus have the same flags, it's enough to read one */
        *value = wrtd->roots[0].log_flags != 0;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_log_empty(struct wrtd_dev *wrtd,
                                         bool *value)
{
        struct polltrtl p[WRTD_MAX_CPUS];
        int ret, i;

        for (i = 0; i < wrtd->nbr_cpus; ++i) {
                p[i].trtl = wrtd->trtl;
                p[i].idx_hmq = WRTD_HMQ;
                p[i].idx_cpu = i;
                p[i].events = POLLIN;
        }

        ret = trtl_msg_poll(p, wrtd->nbr_cpus, 0);
        if (ret < 0)
                return wrtd_return_error
                        (wrtd, WRTD_ERROR_INTERNAL,
                         "%s: %s", __func__, trtl_strerror(errno));

        *value = (ret == 0);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_time_sync(struct wrtd_dev *wrtd,
                                         bool *value)
{
        struct wrtd_config_msg msg;
        enum wrtd_status status;

        status = wrtd_msg_get_config(wrtd, 0, &msg, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = (msg.sync_flag != 0);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_count(struct wrtd_dev *wrtd,
                                          int32_t *value)
{
        enum wrtd_status status;
        unsigned i;
        int32_t res;

        status = wrtd_fill_rules(wrtd, __func__);
        WRTD_RETURN_IF_ERROR(status);

        res = 0;
        for (i = 0; i < wrtd->nbr_rules; i++)
                if (!wrtd_id_null(wrtd->rules[i].rule.conf.id))
                        res++;
        *value = res;
        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_source(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           const char *src)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_validate_id(wrtd, src, __func__);
        WRTD_RETURN_IF_ERROR(status);

        /* If the source is an alarm, check that it exists */
        if ((strncmp(src, "alarm", 5) == 0) ||
            (strncmp(src, "ALARM", 5) == 0)) {
                status = wrtd_find_alarm(wrtd, src, &idx, __func__);
                WRTD_RETURN_IF_ERROR(status);
        }

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd_id_copy(wrtd->rules[idx].rule.conf.source_id, src);

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_source(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           int32_t buffer_size,
                                           char *dst)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_id_copy_buf(wrtd, dst, buffer_size,
                                  wrtd->rules[idx].rule.conf.source_id,
                                  __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_destination(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                const char *dst)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_validate_id(wrtd, dst, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd_id_copy(wrtd->rules[idx].rule.conf.dest_id, dst);

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_destination(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t buffer_size,
                                                char *dst)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_id_copy_buf(wrtd, dst, buffer_size,
                                  wrtd->rules[idx].rule.conf.dest_id,
                                  __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_delay(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          const struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        if (value->seconds != 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter value.seconds",
                                         value->seconds, __func__);

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->rules[idx].rule.conf.delay_ns = value->ns;

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_delay(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));
        wrtd_ts_add_ns(value, wrtd->rules[idx].rule.conf.delay_ns);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_holdoff(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            const struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        if (value->seconds != 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter value.seconds",
                                         value->seconds, __func__);

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->rules[idx].rule.conf.hold_off_ns = value->ns;

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_holdoff(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));
        wrtd_ts_add_ns(value, wrtd->rules[idx].rule.conf.hold_off_ns);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_resync_period(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  const struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        if (value->seconds != 0)
                return wrtd_return_error(wrtd, WRTD_ERROR_INVALID_VALUE,
                                         "Invalid value (%d) for function %s, "
                                         "parameter value.seconds",
                                         value->seconds, __func__);

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->rules[idx].rule.conf.resync_period_ns = value->ns;

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_resync_period(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));
        wrtd_ts_add_ns(value, wrtd->rules[idx].rule.conf.resync_period_ns);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_rx_last(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.rx_last;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_tx_last(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.tx_last;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_missed_last(struct wrtd_dev *wrtd,
                                                     const char *rep_cap_id,
                                                     struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.miss_last;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_rx_latency_min(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));
        wrtd_ts_add_ns(value, wrtd->rules[idx].rule.stat.lat_min_ns);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_rx_latency_max(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));
        wrtd_ts_add_ns(value, wrtd->rules[idx].rule.stat.lat_max_ns);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_rx_latency_avg(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        unsigned int idx;
        uint64_t latency;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        memset(value, 0, sizeof(struct wrtd_tstamp));

        if (wrtd->rules[idx].rule.stat.lat_nbr != 0) {
                latency   = wrtd->rules[idx].rule.stat.lat_hi_ns;
                latency <<= 32;
                latency  |= wrtd->rules[idx].rule.stat.lat_lo_ns;
                latency  /= wrtd->rules[idx].rule.stat.lat_nbr;
                wrtd_ts_add_ns(value, latency & 0xffffffff);
        }

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_resync_factor(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        wrtd->rules[idx].rule.conf.resync_factor = value;

        status = wrtd_write_rule(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_resync_factor(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.conf.resync_factor;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_rx_events(struct wrtd_dev *wrtd,
                                                   const char *rep_cap_id,
                                                   int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.rx_events;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_tx_events(struct wrtd_dev *wrtd,
                                                   const char *rep_cap_id,
                                                   int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.tx_events;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_missed_late(struct wrtd_dev *wrtd,
                                                     const char *rep_cap_id,
                                                     int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.miss_late;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_missed_holdoff(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.miss_holdoff;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_missed_nosync(struct wrtd_dev *wrtd,
                                                       const char *rep_cap_id,
                                                       int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.miss_nosync;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_stat_rule_missed_overflow(struct wrtd_dev *wrtd,
                                                         const char *rep_cap_id,
                                                         int32_t *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.stat.miss_overflow;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_enable(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           bool value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        if (wrtd->rules[idx].rule.conf.enabled != value) {
                wrtd->rules[idx].rule.conf.enabled = value;
                wrtd->rules[idx].modified = 1;

                status = wrtd_reconfigure(wrtd, __func__);
                WRTD_RETURN_IF_ERROR(status);
        }

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_enable(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           bool *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.conf.enabled != 0;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_set_rule_send_late(struct wrtd_dev *wrtd,
                                              const char *rep_cap_id,
                                              bool value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        status = wrtd_rule_check_disabled(wrtd, idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        if (wrtd->rules[idx].rule.conf.send_late != value) {
                wrtd->rules[idx].rule.conf.send_late = value;

                status = wrtd_write_rule(wrtd, idx, __func__);
                WRTD_RETURN_IF_ERROR(status);
        }

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_rule_send_late(struct wrtd_dev *wrtd,
                                              const char *rep_cap_id,
                                              bool *value)
{
        enum wrtd_status status;
        unsigned int idx;

        status = wrtd_find_rule(wrtd, rep_cap_id, &idx, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = wrtd->rules[idx].rule.conf.send_late != 0;

        return WRTD_SUCCESS;
}

enum wrtd_status wrtd_attr_get_sys_time(struct wrtd_dev *wrtd,
                                        struct wrtd_tstamp *value)
{
        enum wrtd_status status;
        struct wrtd_config_msg msg;

        if(wrtd == NULL){
                return WRTD_ERROR_NOT_INITIALIZED;
        }

        /* Always use CPU #0 (it does exist!).  */
        status = wrtd_msg_get_config(wrtd, 0, &msg, __func__);
        WRTD_RETURN_IF_ERROR(status);

        *value = msg.now;

        return WRTD_SUCCESS;
}

/**
 *@} End group Time
 */

enum wrtd_status wrtd_attr_global(struct wrtd_dev *wrtd,
                                  const char *rep_cap_id)
{
        if (!wrtd_id_eq(rep_cap_id, WRTD_GLOBAL_REP_CAP_ID))
                return wrtd_return_error(wrtd, WRTD_ERROR_ATTR_GLOBAL,
                                         "Global attributes require the "
                                         "global repeated capability ID");
        return WRTD_SUCCESS;
}
