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

#ifndef __LIBWRTD_PRIVATE__H__
#define __LIBWRTD_PRIVATE__H__

#include "mockturtle/libmockturtle.h"

#define WRTD_RETURN_IF_ERROR(status) if(status != WRTD_SUCCESS) return status

#define WRTD_DEFAULT_TIMEOUT 1000

/* Used to detect WRTD Nodes */
#define WRTD_NODE_ID      0x57544E00
#define WRTD_NODE_ID_MASK 0xFFFFFF00

static inline int wrtd_node_id_match(uint32_t id)
{
        if ((id & WRTD_NODE_ID_MASK) == WRTD_NODE_ID)
                return 1;
        else
                return 0;
}

/* Add nanoseconds to an existing wrtd timestamp */
static inline void wrtd_ts_add_ns(struct wrtd_tstamp *ts, uint32_t ns)
{
        ts->ns += ns;
        while (ts->ns >= 1000000000) {
                ts->ns -= 1000000000;
                ts->seconds++;
        }
}

/* Alarm when in user space.  */
struct wrtd_lib_alarm {
        /* CPU on which the alarm is.  */
        unsigned int cpu;
        /* Alarm index for the cpu.  */
        unsigned int idx;
        /* Alarm data.  */
        struct wrtd_alarm alarm;
};

struct wrtd_lib_rule {
        /* MT CPU on which the rule is placed.  */
        unsigned int cpu;
        /* Rule index on the local MT cpu.  */
        unsigned int local_idx;
        unsigned char modified;
        /* Rule.  */
        struct wrtd_rule rule;
};

struct wrtd_dev {
        /* Associated Mock Turtle device.  */
        struct trtl_dev *trtl;

        /* Last error.  */
        enum wrtd_status err;

        /* Long error message.  */
        char error_msg[256];

        /* Number of cpus. Valid if > 0. */
        uint32_t nbr_cpus;

        /* Firmware version information from Mock Turtle */
        struct trtl_fw_version fw_version[WRTD_MAX_CPUS];

        /* Per-cpu hmq length (from MT config) - this is needed for
           readw/writew. */
        uint32_t hmq_words[WRTD_MAX_CPUS];

        /* Per-cpu root address.  */
        uint32_t root_addr[WRTD_MAX_CPUS];

        /* Roots.
           Valid only when versions are not 0.  */
        struct wrtd_root roots[WRTD_MAX_CPUS];

        /* Rules.  */
        uint32_t nbr_rules;
        struct wrtd_lib_rule *rules;

        /* Alarms.  */
        uint32_t nbr_alarms;
        struct wrtd_lib_alarm *alarms;
};

/* Save the error in DEV and return the error code.  */
enum wrtd_status wrtd_return_error(struct wrtd_dev *dev,
                                   enum wrtd_status error_code,
                                   const char *format, ...)
        __attribute__((format(printf, 3, 4)));

/* Do the get_config action. */
enum wrtd_status wrtd_msg_get_config(struct wrtd_dev *wrtd, unsigned cpu,
                                     struct wrtd_config_msg *res,
                                     const char *caller_func);

/* Read words from CPU space.  */
enum wrtd_status wrtd_msg_readw(struct wrtd_dev *wrtd, unsigned cpu,
                                uint32_t addr, uint32_t count,
                                uint32_t *dest,
                                const char *caller_func);

/* Write words to CPU space.  */
enum wrtd_status wrtd_msg_writew(struct wrtd_dev *wrtd, unsigned cpu,
                                 uint32_t addr, uint32_t count,
                                 const uint32_t *src,
                                 const char *caller_func);

/* Check if rep_cap_id is valid (not null, length). */
enum wrtd_status wrtd_validate_id(struct wrtd_dev *wrtd,
                                  const char *rep_cap_id,
                                  const char *caller_func);

/* Ensure the roots have been fetched from the CPUs.  */
enum wrtd_status wrtd_fill_roots(struct wrtd_dev *wrtd,
                                 const char *caller_func);

enum wrtd_status wrtd_write_root_flags(struct wrtd_dev *wrtd, unsigned cpu,
                                       const char *caller_func);

/* Ensure the alarms have been fetched from the CPUs.  */
enum wrtd_status wrtd_fill_alarms(struct wrtd_dev *wrtd,
                                  const char *caller_func);

/* Write back alarm idx. */
enum wrtd_status wrtd_write_alarm(struct wrtd_dev *wrtd, unsigned idx,
                                  const char *caller_func);

/* Find alarm index by id. */
enum wrtd_status wrtd_find_alarm(struct wrtd_dev *wrtd,
                                 const char *rep_cap_id,
                                 unsigned *idx,
                                 const char *caller_func);

/* Find rule index by id. */
enum wrtd_status wrtd_find_rule(struct wrtd_dev *wrtd,
                                const char *rep_cap_id,
                                unsigned *idx,
                                const char *caller_func);

/* Internal function: allocate rules and set cpu,idx.  */
enum wrtd_status wrtd_alloc_rules(struct wrtd_dev *wrtd,
                                  struct wrtd_lib_rule **rulesp,
                                  const char *caller_func);

/* Write-back rule. */
enum wrtd_status wrtd_write_rule(struct wrtd_dev *wrtd, unsigned idx,
                                 const char *caller_func);

/* Ensure the rules have been fetched from the CPUs.  */
enum wrtd_status wrtd_fill_rules(struct wrtd_dev *wrtd,
                                 const char *caller_func);

/* Find firmware index by id. */
enum wrtd_status wrtd_find_fw(struct wrtd_dev *wrtd,
                              const char *rep_cap_id,
                              unsigned *idx,
                              const char *caller_func);

/* Reconfigure route tables and write-back rules.  */
enum wrtd_status wrtd_reconfigure(struct wrtd_dev *wrtd, const char *caller_func);

bool wrtd_id_eq(const char *l, const char *r);
bool wrtd_id_null(const char *id);
void wrtd_id_copy(char *dst, const char *src);
enum wrtd_status wrtd_alarm_check_disabled(struct wrtd_dev *wrtd, unsigned idx,
                                           const char *caller_func);
enum wrtd_status wrtd_rule_check_disabled(struct wrtd_dev *wrtd, unsigned idx,
                                          const char *caller_func);

/* Copy ID to DST of length BUF_SIZE.  Check length, pad with null.  */
enum wrtd_status wrtd_id_copy_buf(struct wrtd_dev *wrtd,
                                  char *dst, int32_t buf_size, const char *id,
                                  const char *caller_func);

enum wrtd_status wrtd_log_read(struct wrtd_dev *wrtd,
                               struct wrtd_log_entry *log,
                               const char *caller_func);

/* Get/set attribute implementation function prototypes */
enum wrtd_status wrtd_attr_get_fw_major_version(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t *value);
enum wrtd_status wrtd_attr_get_fw_minor_version(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t *value);
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 wrtd_attr_get_fw_minor_version_required(struct wrtd_dev *wrtd,
                                                         const char *rep_cap_id,
                                                         int32_t *value);
enum wrtd_status wrtd_attr_get_fw_max_rules(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            int32_t *value);
enum wrtd_status wrtd_attr_get_fw_max_alarms(struct wrtd_dev *wrtd,
                                             const char *rep_cap_id,
                                             int32_t *value);
enum wrtd_status wrtd_attr_get_fw_capabilities(struct wrtd_dev *wrtd,
                                               const char *rep_cap_id,
                                               int32_t *value);
enum wrtd_status wrtd_attr_get_fw_local_inputs(struct wrtd_dev *wrtd,
                                               const char *rep_cap_id,
                                               int32_t *value);
enum wrtd_status wrtd_attr_get_fw_local_outputs(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                int32_t *value);
enum wrtd_status wrtd_attr_get_alarm_count(struct wrtd_dev *wrtd,
                                           int32_t *value);
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 wrtd_attr_get_alarm_period(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            struct wrtd_tstamp *value);
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 wrtd_attr_get_alarm_setup_time(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                struct wrtd_tstamp *value);
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 wrtd_attr_get_alarm_time(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          struct wrtd_tstamp *value);
enum wrtd_status wrtd_attr_set_alarm_enable(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            bool value);
enum wrtd_status wrtd_attr_get_alarm_enable(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            bool *value);
enum wrtd_status wrtd_attr_set_alarm_repeat_count(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t value);
enum wrtd_status wrtd_attr_get_alarm_repeat_count(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t *value);
enum wrtd_status wrtd_attr_set_rule_repeat_count(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 int32_t value);
enum wrtd_status wrtd_attr_get_rule_repeat_count(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 int32_t *value);
enum wrtd_status wrtd_attr_set_log_enable(struct wrtd_dev *wrtd,
                                          bool value);
enum wrtd_status wrtd_attr_get_log_enable(struct wrtd_dev *wrtd,
                                          bool *value);
enum wrtd_status wrtd_attr_get_log_empty(struct wrtd_dev *wrtd,
                                         bool *value);
enum wrtd_status wrtd_attr_get_time_sync(struct wrtd_dev *wrtd,
                                         bool *value);
enum wrtd_status wrtd_attr_get_rule_count(struct wrtd_dev *wrtd,
                                          int32_t *value);
enum wrtd_status wrtd_attr_set_rule_source(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           const char *src);
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 wrtd_attr_set_rule_destination(struct wrtd_dev *wrtd,
                                                const char *rep_cap_id,
                                                const char *dst);
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 wrtd_attr_set_rule_delay(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          const struct wrtd_tstamp *value);
enum wrtd_status wrtd_attr_get_rule_delay(struct wrtd_dev *wrtd,
                                          const char *rep_cap_id,
                                          struct wrtd_tstamp *value);
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 wrtd_attr_get_rule_holdoff(struct wrtd_dev *wrtd,
                                            const char *rep_cap_id,
                                            struct wrtd_tstamp *value);
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 wrtd_attr_get_rule_resync_period(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  struct wrtd_tstamp *value);
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 wrtd_attr_get_stat_rule_tx_last(struct wrtd_dev *wrtd,
                                                 const char *rep_cap_id,
                                                 struct wrtd_tstamp *value);
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 wrtd_attr_get_stat_rule_rx_latency_min(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        struct wrtd_tstamp *value);
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 wrtd_attr_get_stat_rule_rx_latency_avg(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        struct wrtd_tstamp *value);
enum wrtd_status wrtd_attr_set_rule_resync_factor(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t value);
enum wrtd_status wrtd_attr_get_rule_resync_factor(struct wrtd_dev *wrtd,
                                                  const char *rep_cap_id,
                                                  int32_t *value);
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 wrtd_attr_get_stat_rule_tx_events(struct wrtd_dev *wrtd,
                                                   const char *rep_cap_id,
                                                   int32_t *value);
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 wrtd_attr_get_stat_rule_missed_holdoff(struct wrtd_dev *wrtd,
                                                        const char *rep_cap_id,
                                                        int32_t *value);
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 wrtd_attr_get_stat_rule_missed_overflow(struct wrtd_dev *wrtd,
                                                         const char *rep_cap_id,
                                                         int32_t *value);
enum wrtd_status wrtd_attr_set_rule_enable(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           bool value);
enum wrtd_status wrtd_attr_get_rule_enable(struct wrtd_dev *wrtd,
                                           const char *rep_cap_id,
                                           bool *value);
enum wrtd_status wrtd_attr_set_rule_send_late(struct wrtd_dev *wrtd,
                                              const char *rep_cap_id,
                                              bool value);
enum wrtd_status wrtd_attr_get_rule_send_late(struct wrtd_dev *wrtd,
                                              const char *rep_cap_id,
                                              bool *value);
enum wrtd_status wrtd_attr_get_sys_time(struct wrtd_dev *wrtd,
                                        struct wrtd_tstamp *value);
enum wrtd_status wrtd_attr_global(struct wrtd_dev *wrtd,
                                  const char *rep_cap_id);

#endif /* __LIBWRTD_PRIVATE__H__ */
