
#ifndef ETHERCAT_TYPES_H
#define ETHERCAT_TYPES_H

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef BOOL
typedef int BOOL;
#endif

#ifndef TRUE
#define TRUE  1
#define FALSE 0
#endif

#define EC_MAXSLAVE  512
#define EC_MAXGROUP  8

typedef enum {
    EC_STATE_NONE     = 0x00,
    EC_STATE_INIT     = 0x01,
    EC_STATE_PRE_OP   = 0x02,
    EC_STATE_BOOT     = 0x03,
    EC_STATE_SAFE_OP  = 0x04,
    EC_STATE_OPERATIONAL = 0x08,
    EC_STATE_ACK      = 0x10,
    EC_STATE_ERROR    = 0x10
} ec_state_t;

typedef enum {
    EC_LINK_DOWN          = 0,
    EC_LINK_UP            = 1,
    EC_LINK_PRIMARY_ONLY  = 3,
    EC_LINK_SECONDARY_ONLY = 4
} ec_link_state_t;

#define EC_TRANS_IP   0
#define EC_TRANS_PS   1
#define EC_TRANS_SO   2
#define EC_TRANS_OS   3
#define EC_TRANS_SP   4
#define EC_TRANS_PI   5

#define EC_TIMING_BEFORE  0
#define EC_TIMING_AFTER   1

#define EC_STARTUP_PARAM_MAX_DATA  256
#define EC_MAX_STARTUP_PARAMS      128

#pragma pack(push, 1)
typedef struct {
    uint16_t index;
    uint8_t  sub_index;
    uint8_t  data[EC_STARTUP_PARAM_MAX_DATA];
    uint16_t data_len;
    uint8_t  transition;
    uint8_t  timing;
    uint16_t priority;
    uint8_t  complete_access;
    uint8_t  is_register_write;
} ec_startup_param_t;
#pragma pack(pop)

typedef enum {
    FOE_ERR_NOT_DEFINED        = 0x8000,
    FOE_ERR_NOT_FOUND          = 0x8001,
    FOE_ERR_ACCESS_DENIED      = 0x8002,
    FOE_ERR_DISK_FULL          = 0x8003,
    FOE_ERR_ILLEGAL            = 0x8004,
    FOE_ERR_PACKET_NUMBER_WRONG = 0x8005,
    FOE_ERR_ALREADY_EXISTS     = 0x8006,
    FOE_ERR_NO_USER            = 0x8007,
    FOE_ERR_BOOTSTRAP_ONLY     = 0x8008,
    FOE_ERR_NOT_BOOTSTRAP      = 0x8009,
    FOE_ERR_NO_RIGHTS          = 0x800A,
    FOE_ERR_PROGRAM_ERROR      = 0x800B
} ec_foe_error_code_t;

#pragma pack(push, 1)
typedef struct {
    uint8_t  enable_crc;
    uint8_t  strict_mode;
    uint8_t  auto_append_crc;
    uint32_t expected_crc;
    void (*crc_progress_callback)(uint32_t bytes_processed, uint32_t total_bytes, void* userdata);
    void*    crc_callback_userdata;
    uint32_t reserved[8];
} ec_foe_options_t;
#pragma pack(pop)

typedef enum {
    LOG_CATEGORY_ERROR   = 0,
    LOG_CATEGORY_WARNING = 1,
    LOG_CATEGORY_MESSAGE = 2,
    LOG_CATEGORY_MAILBOX = 3,
    LOG_CATEGORY_PDO     = 4,
    LOG_CATEGORY_DEBUG   = 5
} log_category_t;

typedef enum {
    EC_ERROR_FRAME_LOST    = 0,
    EC_ERROR_OUT_OF_ORDER  = 1,
    EC_ERROR_CHECKSUM      = 2,
    EC_ERROR_TIMEOUT       = 3,
    EC_ERROR_WKC_MISMATCH  = 4,
    EC_ERROR_LINK_LOST     = 5
} ec_error_type_t;

typedef void (*log_callback_t)(int category, const char* message);

typedef void (*crash_callback_t)(int exception_code, const char* message);

typedef void (*license_expired_callback_t)(uint16_t master_index, int reason_code,
    const char* message);

typedef void (*pdo_cyclic_callback_t)(uint16_t master_index);

typedef void (*state_change_callback_t)(uint16_t master_index, uint16_t slave_index,
    int old_state, int new_state);

typedef void (*emergency_callback_t)(uint16_t master_index, uint16_t slave_index,
    uint16_t error_code, uint16_t error_reg, uint8_t b1, uint16_t w1, uint16_t w2);

typedef void (*discovery_callback_t)(uint16_t master_index, uint16_t slave_index, BOOL is_found);

typedef void (*frame_loss_callback_t)(uint16_t master_index, uint8_t group,
    uint32_t consecutive_lost, uint32_t total_lost);

typedef void (*redundancy_changed_callback_t)(uint16_t master_index, int old_mode, int new_mode);

typedef void (*preop_reconfig_callback_t)(uint16_t master_index, uint16_t slave_index);

typedef void (*identity_mismatch_callback_t)(uint16_t master_index, uint16_t slave_index,
    uint32_t expected_vendor, uint32_t expected_product, uint32_t expected_revision,
    uint32_t actual_vendor,   uint32_t actual_product,   uint32_t actual_revision);

typedef void (*port_link_changed_callback_t)(uint16_t master_index, uint16_t slave_index,
    uint8_t port, BOOL is_up);

typedef void (*foe_progress_callback_t)(uint16_t slave, int packet_number, int data_size);

typedef void (*dc_sync_lost_callback_t)(uint16_t master_index, uint16_t slave_index, int diff_ns);

typedef void (*aoe_notification_callback_t)(uint16_t slave, uint32_t handle, uint64_t timestamp,
    const uint8_t* data, uint32_t data_size, void* user_data);

typedef void (*eoe_frame_cb_t)(uint16_t master_index, uint16_t slave,
                                      const uint8_t* frame_data, int frame_size);

typedef void (*voe_notification_callback_t)(uint16_t slave, uint32_t vendor_id,
                                                   uint16_t vendor_type,
                                                   const uint8_t* data, uint32_t data_size,
                                                   void* user_data);

typedef void (*foe_busy_callback_ffi_t)(uint16_t slave, uint16_t done, uint16_t entire,
                                               const char* text, int retry_idx);

typedef struct {
    uint16_t major;
    uint16_t minor;
    uint16_t patch;
    uint16_t build;
    char     build_date[32];
} version_info_t;

typedef struct {
    uint32_t total_cycles;
    uint32_t successful_cycles;
    uint32_t failed_cycles;
    uint32_t timeout_cycles;
    double   average_cycle_time_us;
    double   max_cycle_time_us;
    double   min_cycle_time_us;
} ec_communication_stats_t;

typedef struct {
    uint16_t wd_divider;
    uint16_t wd_time_pdi;
    uint16_t wd_time_pd;
} ec_watchdog_config_t;

typedef struct {
    uint8_t  wd_status;
    uint8_t  wd_counter;
    uint16_t wd_divider;
    uint16_t wd_time_pd;
} ec_watchdog_status_t;

typedef struct {
    uint32_t VendorId;
    uint32_t ProductCode;
    uint32_t RevisionNo;
    uint32_t SerialNo;
    char     DeviceName[64];
    char     HwVersion[32];
    char     SwVersion[32];
} ec_master_identity_t;

typedef struct {
    uint32_t CyclicLostFrames;
    uint32_t AcyclicLostFrames;
    uint32_t CyclicFramesPerSec;
    uint32_t AcyclicFramesPerSec;
    uint16_t MasterState;
} ec_master_diag_data_t;

typedef struct {
    uint32_t IP;
    uint32_t PS;
    uint32_t SO;
    uint32_t OS;
    uint32_t SP;
    uint32_t PI;
    uint32_t BI;
    uint32_t IB;
} ec_esm_timeouts_t;

typedef struct {
    uint32_t VendorId;
    uint32_t ProductCode;
    uint32_t RevisionNo;
    uint32_t SerialNo;
} ec_slave_identity_t;

typedef enum {
    EC_MAILBOX_HEALTH_UNKNOWN  = 0,
    EC_MAILBOX_HEALTH_HEALTHY  = 1,
    EC_MAILBOX_HEALTH_DEGRADED = 2
} ec_mailbox_health_t;

typedef enum {
    EC_REDUNDANCY_NONE      = 0,
    EC_REDUNDANCY_PRIMARY   = 1,
    EC_REDUNDANCY_SECONDARY = 2,
    EC_REDUNDANCY_BOTH      = 3
} ec_redundancy_state_t;

typedef struct {
    ec_redundancy_state_t state;
    BOOL     primary_link_up;
    BOOL     secondary_link_up;
    uint32_t primary_tx_frames;
    uint32_t primary_rx_frames;
    uint32_t secondary_tx_frames;
    uint32_t secondary_rx_frames;
    uint32_t failover_count;
    uint32_t last_failover_time;
} ec_redundancy_status_t;

typedef enum {
    CIA402_NOT_READY          = 0,
    CIA402_SWITCH_ON_DISABLED = 1,
    CIA402_READY_TO_SWITCH_ON = 2,
    CIA402_SWITCHED_ON        = 3,
    CIA402_OPERATION_ENABLED  = 4,
    CIA402_QUICK_STOP_ACTIVE  = 5,
    CIA402_FAULT_REACTION     = 6,
    CIA402_FAULT              = 7,
    CIA402_UNKNOWN            = 99
} cia402_state_t;

typedef enum {
    CIA402_PP  = 1,
    CIA402_VL  = 2,
    CIA402_PV  = 3,
    CIA402_PT  = 4,
    CIA402_HM  = 6,
    CIA402_IP  = 7,
    CIA402_CSP = 8,
    CIA402_CSV = 9,
    CIA402_CST = 10
} cia402_mode_t;

typedef enum {
    CIA402_READ_NOT_ATTEMPTED = 0,
    CIA402_READ_SUCCESS       = 1,
    CIA402_READ_NOT_SUPPORTED = 2,
    CIA402_READ_FAILED        = 3
} cia402_read_status_t;

typedef struct {
    cia402_read_status_t status;
    uint32_t             abort_code;
    uint64_t             value64;
    int                  byte_len;
} cia402_read_result_t;

#pragma pack(push, 1)
typedef struct {
    uint16_t error_code;
    uint8_t  error_register;
    uint8_t  data[5];
    uint16_t slave_index;
    uint32_t timestamp_ms;
} ec_emcy_record_t;
#pragma pack(pop)

#pragma pack(push, 1)
typedef struct {
    uint16_t slave_index;
    uint16_t config_addr;
    uint16_t parent_index;
    uint8_t  entry_port;
    uint8_t  active_ports;
    uint8_t  topology;
    uint8_t  port_type;
} ec_topology_node_t;
#pragma pack(pop)

typedef struct {

    uint32_t FrameErrors;
    uint32_t LostFrames;
    uint32_t ChecksumErrors;
    uint32_t TimeoutFrames;

    uint32_t RxErrorCount[EC_MAXSLAVE];
    uint32_t TxErrorCount[EC_MAXSLAVE];
    uint16_t LostLinkCount[EC_MAXSLAVE];
    uint16_t InvalidFrameCount[EC_MAXSLAVE];

    uint16_t WorkingCounterErrors;
    uint16_t ConsecutiveWkcErrors;
    uint32_t TotalWkcMismatches;

    uint32_t PdoLostFrames[EC_MAXGROUP];
    uint32_t PdoConsecutiveLost[EC_MAXGROUP];
    uint32_t PdoMaxConsecutiveLost[EC_MAXGROUP];

    int16_t  LinkQualityPercent[EC_MAXSLAVE];

    uint32_t PrimaryPortTxCount;
    uint32_t PrimaryPortRxCount;
    uint32_t SecondaryPortTxCount;
    uint32_t SecondaryPortRxCount;
    uint32_t PrimaryPortErrors;
    uint32_t SecondaryPortErrors;
} ec_diagnostics_data_t;

typedef struct {
    uint8_t  RxErrorCount[4];
    uint8_t  InvalidFrameCount[4];
    uint8_t  LostLinkCount[4];
    uint8_t  FwdRxErrorCount[4];
} ec_esc_port_error_stats_t;

typedef enum {
    FSOE_STATE_RESET      = 0x100,
    FSOE_STATE_SESSION    = 0x101,
    FSOE_STATE_CONNECTION = 0x102,
    FSOE_STATE_PARAMETER  = 0x103,
    FSOE_STATE_DATA       = 0x104,
    FSOE_STATE_FAILSAFE   = 0x105
} fsoe_state_t;

typedef enum {
    FSOE_ERROR_NONE               = 0x0000,
    FSOE_ERROR_WRONG_COMMAND      = 0x0001,
    FSOE_ERROR_UNKNOWN_COMMAND    = 0x0002,
    FSOE_ERROR_WRONG_CONN_ID      = 0x0003,
    FSOE_ERROR_CRC                = 0x0004,
    FSOE_ERROR_WATCHDOG           = 0x0005,
    FSOE_ERROR_WRONG_ADDRESS      = 0x0006,
    FSOE_ERROR_WRONG_DATA         = 0x0007,
    FSOE_ERROR_COMM_PARAM_LENGTH  = 0x0008,
    FSOE_ERROR_COMM_PARAM         = 0x0009,
    FSOE_ERROR_APP_PARAM_LENGTH   = 0x000A,
    FSOE_ERROR_APP_PARAM          = 0x000B,
    FSOE_ERROR_UNEXPECTED_SESSION = 0x000C,
    FSOE_ERROR_FAILSAFE_DATA      = 0x000D,
    FSOE_ERROR_NOT_INITIALIZED    = 0x0100,
    FSOE_ERROR_MAX_CONNECTIONS    = 0x0101,
    FSOE_ERROR_INVALID_STATE      = 0x0102
} fsoe_error_t;

typedef struct {
    uint16_t ConnectionId;
    uint16_t SafetyAddress;
    uint32_t WatchdogTimeMs;
    uint16_t SafeInputSize;
    uint16_t SafeOutputSize;
    uint32_t PdoInputOffset;
    uint32_t PdoOutputOffset;
} fsoe_config_t;

typedef struct {
    fsoe_state_t State;
    fsoe_error_t LastError;
    uint32_t ErrorCount;
    uint32_t FramesSent;
    uint32_t FramesReceived;
    uint32_t CrcErrors;
    uint32_t WatchdogErrors;
    uint8_t  WatchdogExpired;
    uint8_t  InFailsafe;
    uint8_t  ToggleBit;
    uint8_t  Initialized;
} fsoe_status_t;

typedef struct {
    uint16_t ConnectionId;
    uint16_t SafetyAddress;
    uint32_t WatchdogTimeMs;
    uint16_t SafeInputSize;
    uint16_t SafeOutputSize;
    uint32_t PdoInputOffset;
    uint32_t PdoOutputOffset;
    uint16_t ModuleNumber;
    uint16_t ModuleProfile;
    uint16_t AxisNumber;
    uint16_t ConnectionType;
} fsoe_mdp_config_t;

typedef enum {
    EC_AL_NO_ERROR                  = 0x0000,
    EC_AL_UNSPECIFIED_ERROR         = 0x0001,
    EC_AL_NO_MEMORY                 = 0x0002,
    EC_AL_INVALID_DEVICE_SETUP      = 0x0003,
    EC_AL_INVALID_REVISION          = 0x0004,
    EC_AL_SII_EEPROM_MISMATCH      = 0x0006,
    EC_AL_FIRMWARE_UPDATE_FAILED    = 0x0007,
    EC_AL_LICENSE_ERROR             = 0x000E,
    EC_AL_INVALID_STATE_CHANGE      = 0x0011,
    EC_AL_UNKNOWN_REQUESTED_STATE   = 0x0012,
    EC_AL_BOOTSTRAP_NOT_SUPPORTED   = 0x0013,
    EC_AL_NO_VALID_FIRMWARE         = 0x0014,
    EC_AL_INVALID_MAILBOX_CONFIG    = 0x0015,
    EC_AL_INVALID_SM_CONFIG         = 0x0017,
    EC_AL_NO_VALID_INPUTS           = 0x0018,
    EC_AL_NO_VALID_OUTPUTS          = 0x0019,
    EC_AL_SYNC_ERROR                = 0x001A,
    EC_AL_SM_WATCHDOG               = 0x001B,
    EC_AL_INVALID_OUTPUT_CONFIG     = 0x001D,
    EC_AL_INVALID_INPUT_CONFIG      = 0x001E,
    EC_AL_INVALID_WATCHDOG_CONFIG   = 0x001F,
    EC_AL_NEEDS_COLD_START          = 0x0020,
    EC_AL_NEEDS_INIT                = 0x0021,
    EC_AL_NEEDS_PREOP               = 0x0022,
    EC_AL_NEEDS_SAFEOP              = 0x0023,
    EC_AL_INVALID_INPUT_MAPPING     = 0x0024,
    EC_AL_INVALID_OUTPUT_MAPPING    = 0x0025,
    EC_AL_INCONSISTENT_SETTINGS     = 0x0026,
    EC_AL_FREERUN_NOT_SUPPORTED     = 0x0027,
    EC_AL_SYNC_NOT_SUPPORTED        = 0x0028,
    EC_AL_FREERUN_NEEDS_3BUFFER     = 0x0029,
    EC_AL_BACKGROUND_WATCHDOG       = 0x002A,
    EC_AL_NO_VALID_IO               = 0x002B,
    EC_AL_FATAL_SYNC_ERROR          = 0x002C,
    EC_AL_NO_SYNC_ERROR             = 0x002D,
    EC_AL_CYCLE_TIME_TOO_SMALL      = 0x002E,
    EC_AL_INVALID_DC_SYNC_CONFIG    = 0x0030,
    EC_AL_INVALID_DC_LATCH          = 0x0031,
    EC_AL_PLL_ERROR                 = 0x0032,
    EC_AL_DC_SYNC_IO_ERROR          = 0x0033,
    EC_AL_DC_SYNC_TIMEOUT           = 0x0034,
    EC_AL_INVALID_DC_SYNC_CYCLE     = 0x0035,
    EC_AL_INVALID_SYNC0_CYCLE       = 0x0036,
    EC_AL_INVALID_SYNC1_CYCLE       = 0x0037,
    EC_AL_MAILBOX_AOE               = 0x0041,
    EC_AL_MAILBOX_EOE               = 0x0042,
    EC_AL_MAILBOX_COE               = 0x0043,
    EC_AL_MAILBOX_FOE               = 0x0044,
    EC_AL_MAILBOX_SOE               = 0x0045,
    EC_AL_MAILBOX_VOE               = 0x004F,
    EC_AL_EEPROM_NO_ACCESS          = 0x0050,
    EC_AL_EEPROM_ERROR              = 0x0051,
    EC_AL_EXTERNAL_HW_NOT_READY     = 0x0052,
    EC_AL_SLAVE_RESTARTED           = 0x0060,
    EC_AL_DEVICE_ID_UPDATED         = 0x0061,
    EC_AL_MODULE_IDENT_MISMATCH     = 0x0070,
    EC_AL_SUPPLY_VOLTAGE_TOO_LOW    = 0x0080,
    EC_AL_SUPPLY_VOLTAGE_TOO_HIGH   = 0x0081,
    EC_AL_TEMPERATURE_TOO_LOW       = 0x0082,
    EC_AL_TEMPERATURE_TOO_HIGH      = 0x0083,
    EC_AL_APP_CONTROLLER_AVAILABLE  = 0x00F0,
    EC_AL_UNKNOWN                   = 0xFFFF
} ec_al_state_t;

typedef enum {
    EC_SDO_NO_ERROR                 = 0x00000000,
    EC_SDO_TOGGLE_BIT_NOT_CHANGED   = 0x05030000,
    EC_SDO_PROTOCOL_TIMEOUT         = 0x05040000,
    EC_SDO_INVALID_COMMAND          = 0x05040001,
    EC_SDO_OUT_OF_MEMORY            = 0x05040005,
    EC_SDO_UNSUPPORTED_ACCESS       = 0x06010000,
    EC_SDO_READ_WRITE_ONLY          = 0x06010001,
    EC_SDO_WRITE_READ_ONLY          = 0x06010002,
    EC_SDO_SUBINDEX_WRITE_ERROR     = 0x06010003,
    EC_SDO_COMPLETE_ACCESS_NOT_SUPPORTED = 0x06010004,
    EC_SDO_OBJECT_LENGTH_EXCEEDED   = 0x06010005,
    EC_SDO_OBJECT_MAPPED_TO_RXPDO   = 0x06010006,
    EC_SDO_OBJECT_DOES_NOT_EXIST    = 0x06020000,
    EC_SDO_CANNOT_MAP_TO_PDO        = 0x06040041,
    EC_SDO_EXCEEDS_PDO_LENGTH       = 0x06040042,
    EC_SDO_PARAMETER_INCOMPATIBILITY = 0x06040043,
    EC_SDO_INTERNAL_INCOMPATIBILITY = 0x06040047,
    EC_SDO_HARDWARE_ACCESS_ERROR    = 0x06060000,
    EC_SDO_DATA_TYPE_MISMATCH       = 0x06070010,
    EC_SDO_DATA_TYPE_TOO_HIGH       = 0x06070012,
    EC_SDO_DATA_TYPE_TOO_LOW        = 0x06070013,
    EC_SDO_SUBINDEX_DOES_NOT_EXIST  = 0x06090011,
    EC_SDO_VALUE_RANGE_EXCEEDED     = 0x06090030,
    EC_SDO_VALUE_TOO_HIGH           = 0x06090031,
    EC_SDO_VALUE_TOO_LOW            = 0x06090032,
    EC_SDO_MODULE_IDENT_MISMATCH    = 0x06090033,
    EC_SDO_MAX_LESS_THAN_MIN        = 0x06090036,
    EC_SDO_GENERAL_ERROR            = 0x08000000,
    EC_SDO_DATA_TRANSFER_ERROR      = 0x08000020,
    EC_SDO_LOCAL_CONTROL_ERROR      = 0x08000021,
    EC_SDO_DEVICE_STATE_ERROR       = 0x08000022,
    EC_SDO_DICTIONARY_ERROR         = 0x08000023,
    EC_SDO_UNKNOWN_ERROR            = 0xFFFFFFFF
} ec_sdo_error_t;

typedef enum {
    EC_MBX_ERROR     = 0x00,
    EC_MBX_AOE       = 0x01,
    EC_MBX_EOE       = 0x02,
    EC_MBX_COE       = 0x03,
    EC_MBX_FOE       = 0x04,
    EC_MBX_SOE       = 0x05,
    EC_MBX_VOE       = 0x0F
} ec_mailbox_type_t;

typedef enum {
    EC_MBX_ERR_NO_ERROR             = 0x0000,
    EC_MBX_ERR_SYNTAX               = 0x0001,
    EC_MBX_ERR_PROTOCOL_NOT_SUPPORTED = 0x0002,
    EC_MBX_ERR_WRONG_CHANNEL        = 0x0003,
    EC_MBX_ERR_SERVICE_NOT_SUPPORTED = 0x0004,
    EC_MBX_ERR_INVALID_HEADER       = 0x0005,
    EC_MBX_ERR_DATA_TOO_SHORT       = 0x0006,
    EC_MBX_ERR_NO_MEMORY            = 0x0007,
    EC_MBX_ERR_INCONSISTENT_LENGTH  = 0x0008,
    EC_MBX_ERR_UNKNOWN              = 0xFFFF
} ec_mailbox_error_t;

typedef enum {
    EC_PORT_NOT_USED    = 0,
    EC_PORT_MII         = 1,
    EC_PORT_EBUS        = 2,
    EC_PORT_EBUS_ENH    = 3
} ec_port_type_t;

typedef enum {
    EC_TOPO_NO_LINK   = 0,
    EC_TOPO_END_POINT = 1,
    EC_TOPO_LINE      = 2,
    EC_TOPO_FORK      = 3,
    EC_TOPO_CROSS     = 4
} ec_topology_type_t;

typedef enum {
    EC_RING_INACTIVE  = 0,
    EC_RING_DUAL      = 1,
    EC_RING_DEGRADED  = 2
} ec_ring_mode_t;

#ifdef __cplusplus
}
#endif

#endif
