
#ifndef ETHERCAT_PROTOCOL_CODES_H
#define ETHERCAT_PROTOCOL_CODES_H

#pragma once

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifndef EC_API
#  ifdef _WIN32
#    ifdef BUILD_CORE
#      define EC_API __declspec(dllexport)
#    else
#      define EC_API __declspec(dllimport)
#    endif
#  else
#    define EC_API
#  endif
#endif

typedef enum {
    AL_SEVERITY_NONE    = 0,
    AL_SEVERITY_INFO    = 1,
    AL_SEVERITY_WARNING = 2,
    AL_SEVERITY_ERROR   = 3,
    AL_SEVERITY_FATAL   = 4
} al_status_severity_t;

EC_API const char* AL_StatusCode_GetDescription(uint16_t code);

EC_API al_status_severity_t AL_StatusCode_GetSeverity(uint16_t code);

EC_API const char* AL_StatusCode_GetRecoveryHint(uint16_t code);

EC_API int AL_StatusCode_IsVendorSpecific(uint16_t code);

typedef enum {
    SDO_ABORT_CAT_TRANSFER = 0,
    SDO_ABORT_CAT_ACCESS   = 1,
    SDO_ABORT_CAT_VALUE    = 2,
    SDO_ABORT_CAT_HARDWARE = 3,
    SDO_ABORT_CAT_GENERAL  = 4
} sdo_abort_category_t;

EC_API const char* dx_sdo_abort_get_description(uint32_t abort_code);

EC_API sdo_abort_category_t dx_sdo_abort_get_category(uint32_t abort_code);

EC_API int dx_sdo_abort_is_retryable(uint32_t abort_code);

EC_API const char* dx_sdo_abort_get_hint(uint32_t abort_code);

typedef enum {
    EMCY_CLASS_NO_ERROR           = 0x0000,
    EMCY_CLASS_GENERIC            = 0x1000,
    EMCY_CLASS_CURRENT            = 0x2000,
    EMCY_CLASS_VOLTAGE            = 0x3000,
    EMCY_CLASS_TEMPERATURE        = 0x4000,
    EMCY_CLASS_HARDWARE           = 0x5000,
    EMCY_CLASS_SOFTWARE           = 0x6000,
    EMCY_CLASS_ADDITIONAL_MODULES = 0x7000,
    EMCY_CLASS_MONITORING         = 0x8000,
    EMCY_CLASS_EXTERNAL           = 0x9000,
    EMCY_CLASS_ADDITIONAL_FUNC    = 0xF000,
    EMCY_CLASS_DEVICE_SPECIFIC    = 0xFF00
} emcy_class_t;

#define EMCY_ER_GENERIC          0x01
#define EMCY_ER_CURRENT          0x02
#define EMCY_ER_VOLTAGE          0x04
#define EMCY_ER_TEMPERATURE      0x08
#define EMCY_ER_COMMUNICATION    0x10
#define EMCY_ER_DEVICE_PROFILE   0x20
#define EMCY_ER_RESERVED         0x40
#define EMCY_ER_MANUFACTURER     0x80

EC_API const char* EmcyCode_GetDescription(uint16_t error_code);

EC_API emcy_class_t EmcyCode_GetClass(uint16_t error_code);

EC_API const char* EmcyCode_GetClassName(emcy_class_t class_code);

EC_API void EmcyCode_FormatErrorRegister(uint8_t error_register, char* buf, int buf_size);

EC_API int EmcyCode_IsRecovery(uint16_t error_code);

typedef enum {
    EC_TRANSITION_INVALID    = 0,
    EC_TRANSITION_UP         = 1,
    EC_TRANSITION_DOWN       = 2,
    EC_TRANSITION_SAME       = 3,
    EC_TRANSITION_BOOTSTRAP  = 4,
    EC_TRANSITION_JUMP_UP    = 5,
    EC_TRANSITION_JUMP_DOWN  = 6
} ec_transition_type_t;

EC_API int EcState_IsValidTransition(uint16_t from, uint16_t to);

EC_API ec_transition_type_t EcState_GetTransitionType(uint16_t from, uint16_t to);

EC_API int EcState_GetTransitionPath(uint16_t from, uint16_t to,
                                           uint16_t* path, int path_capacity);

EC_API int EcState_IsBootstrapRequired(uint16_t state);

EC_API const char* EcState_GetName(uint16_t state);

EC_API const char* EcState_GetNameEn(uint16_t state);

EC_API int EcState_HasErrorAck(uint16_t state);

EC_API uint16_t EcState_StripErrorAck(uint16_t state);

typedef enum {
    EC_DT_NONE             = 0x0000,
    EC_DT_BOOL             = 0x0001,
    EC_DT_INT8             = 0x0002,
    EC_DT_INT16            = 0x0003,
    EC_DT_INT32            = 0x0004,
    EC_DT_UINT8            = 0x0005,
    EC_DT_UINT16           = 0x0006,
    EC_DT_UINT32           = 0x0007,
    EC_DT_REAL32           = 0x0008,
    EC_DT_VISIBLE_STRING   = 0x0009,
    EC_DT_OCTET_STRING     = 0x000A,
    EC_DT_UNICODE_STRING   = 0x000B,
    EC_DT_TIME_OF_DAY      = 0x000C,
    EC_DT_TIME_DIFFERENCE  = 0x000D,
    EC_DT_DOMAIN           = 0x000F,
    EC_DT_INT24            = 0x0010,
    EC_DT_REAL64           = 0x0011,
    EC_DT_INT40            = 0x0012,
    EC_DT_INT48            = 0x0013,
    EC_DT_INT56            = 0x0014,
    EC_DT_INT64            = 0x0015,
    EC_DT_UINT24           = 0x0016,
    EC_DT_UINT40           = 0x0018,
    EC_DT_UINT48           = 0x0019,
    EC_DT_UINT56           = 0x001A,
    EC_DT_UINT64           = 0x001B,
    EC_DT_BIT1             = 0x0030,
    EC_DT_BIT2             = 0x0031,
    EC_DT_BIT3             = 0x0032,
    EC_DT_BIT4             = 0x0033,
    EC_DT_BIT5             = 0x0034,
    EC_DT_BIT6             = 0x0035,
    EC_DT_BIT7             = 0x0036,
    EC_DT_BIT8             = 0x0037
} ec_pdo_datatype_t;

typedef enum {
    EC_PDO_TOPO_UNKNOWN = 0,
    EC_PDO_TOPO_LINE    = 1,
    EC_PDO_TOPO_PASS    = 2,
    EC_PDO_TOPO_BRANCH  = 3,
    EC_PDO_TOPO_CROSS   = 4
} ec_pdo_topology_t;

EC_API int EcPdoCodec_DataTypeBitSize(ec_pdo_datatype_t dt);

EC_API const char* EcPdoCodec_DataTypeName(ec_pdo_datatype_t dt);

EC_API int EcPdoCodec_ExtractU64(const uint8_t* src, int src_size,
                                       int bit_offset, int bit_length, uint64_t* out);

EC_API int EcPdoCodec_ExtractI64(const uint8_t* src, int src_size,
                                       int bit_offset, int bit_length, int64_t* out);

EC_API int EcPdoCodec_InsertU64(uint8_t* dst, int dst_size,
                                      int bit_offset, int bit_length, uint64_t value);

EC_API int EcPdoCodec_InsertI64(uint8_t* dst, int dst_size,
                                      int bit_offset, int bit_length, int64_t value);

EC_API int EcPdoCodec_ExtractReal32(const uint8_t* src, int src_size,
                                          int bit_offset, float* out);

EC_API int EcPdoCodec_ExtractReal64(const uint8_t* src, int src_size,
                                          int bit_offset, double* out);

EC_API int EcPdoCodec_InsertReal32(uint8_t* dst, int dst_size,
                                         int bit_offset, float value);

EC_API int EcPdoCodec_InsertReal64(uint8_t* dst, int dst_size,
                                         int bit_offset, double value);

EC_API int EcPdoCodec_CountActivePorts(uint8_t active_ports);

EC_API ec_pdo_topology_t EcPdoCodec_GetTopology(uint8_t active_ports);

EC_API const char* EcPdoCodec_GetTopologyName(ec_pdo_topology_t topo);

EC_API const char* EcPdoCodec_GetTopologyNameEn(ec_pdo_topology_t topo);

EC_API int EcPdoCodec_IsPortActive(uint8_t active_ports, int port);

typedef enum {
    CIA402_OPMODE_NONE  = 0,
    CIA402_OPMODE_PP    = 1,
    CIA402_OPMODE_VL    = 2,
    CIA402_OPMODE_PV    = 3,
    CIA402_OPMODE_PT    = 4,
    CIA402_OPMODE_HM    = 6,
    CIA402_OPMODE_IP    = 7,
    CIA402_OPMODE_CSP   = 8,
    CIA402_OPMODE_CSV   = 9,
    CIA402_OPMODE_CST   = 10,
    CIA402_OPMODE_CSTCA = 11
} cia402_op_mode_t;

typedef enum {
    HOMING_TRIGGER_NEGATIVE_LIMIT = 0,
    HOMING_TRIGGER_POSITIVE_LIMIT = 1,
    HOMING_TRIGGER_HOME_SWITCH    = 2,
    HOMING_TRIGGER_INDEX_PULSE    = 3,
    HOMING_TRIGGER_HARD_STOP      = 4,
    HOMING_TRIGGER_CURRENT_POS    = 5,
    HOMING_TRIGGER_VENDOR         = 6
} homing_trigger_t;

EC_API int CiA402Modes_ModeToSupportedBit(cia402_op_mode_t mode);

EC_API int CiA402Modes_IsModeSupportedInMask(uint32_t supported_mask, cia402_op_mode_t mode);

EC_API int CiA402Modes_ExpandSupportedMask(uint32_t supported_mask, int8_t* modes, int capacity);

EC_API const char* CiA402Modes_GetModeName(cia402_op_mode_t mode);

EC_API const char* CiA402Modes_GetModeNameEn(cia402_op_mode_t mode);

EC_API const char* CiA402Modes_GetModeDescription(cia402_op_mode_t mode);

EC_API int CiA402Modes_IsCyclicSyncMode(cia402_op_mode_t mode);

EC_API int CiA402Modes_RequiresDC(cia402_op_mode_t mode);

EC_API int CiA402Modes_IsStandardHomingMethod(int8_t method);

EC_API const char* CiA402Modes_GetHomingMethodName(int8_t method);

EC_API homing_trigger_t CiA402Modes_GetHomingTrigger(int8_t method);

EC_API int CiA402Modes_GetHomingDirection(int8_t method);

EC_API int CiA402Modes_ListStandardHomingMethods(int8_t* array, int capacity);

typedef enum {
    EC_MBX_TYPE_ERROR = 0x00,
    EC_MBX_TYPE_AOE   = 0x01,
    EC_MBX_TYPE_EOE   = 0x02,
    EC_MBX_TYPE_COE   = 0x03,
    EC_MBX_TYPE_FOE   = 0x04,
    EC_MBX_TYPE_SOE   = 0x05,
    EC_MBX_TYPE_VOE   = 0x0F
} ec_mbx_type_t;

EC_API const char* EcMailbox_GetTypeName(ec_mbx_type_t type);

EC_API const char* EcMailbox_GetTypeNameEn(ec_mbx_type_t type);

EC_API const char* EcMailbox_GetErrorDescription(uint16_t mbx_error_code);

EC_API uint8_t EcMailbox_NextCounter(uint8_t current);

EC_API const char* EcSoE_GetErrorDescription(uint16_t soe_error);

typedef enum {
    EC_SII_CAT_NONE       = 0,
    EC_SII_CAT_STRINGS    = 10,
    EC_SII_CAT_DATATYPES  = 20,
    EC_SII_CAT_GENERAL    = 30,
    EC_SII_CAT_FMMU       = 40,
    EC_SII_CAT_SYNCMGR    = 41,
    EC_SII_CAT_TXPDO      = 50,
    EC_SII_CAT_RXPDO      = 51,
    EC_SII_CAT_DC         = 60,
    EC_SII_CAT_CYCLIC     = 62,
    EC_SII_CAT_END        = 0xFFFF
} ec_sii_category_t;

typedef struct {
    uint8_t  group_idx;
    uint8_t  image_idx;
    uint8_t  order_idx;
    uint8_t  name_idx;
    uint8_t  coe_details;
    uint8_t  foe_details;
    uint8_t  eoe_details;
    uint8_t  soe_channels;
    uint8_t  ds402_channels;
    uint8_t  sysman_class;
    uint8_t  flags;
    uint16_t current_on_ebus;
    uint16_t physical_port;
    uint16_t physical_mem_addr;
} ec_sii_general_t;

EC_API int EcSii_CoeEnabled(uint8_t coe_details);
EC_API int EcSii_CoeSdoInfo(uint8_t coe_details);
EC_API int EcSii_CoePdoAssign(uint8_t coe_details);
EC_API int EcSii_CoePdoConfig(uint8_t coe_details);
EC_API int EcSii_CoeUploadAtStartup(uint8_t coe_details);
EC_API int EcSii_CoeCompleteAccess(uint8_t coe_details);

EC_API int EcSii_FoeEnabled(uint8_t foe_details);
EC_API int EcSii_EoeEnabled(uint8_t eoe_details);

EC_API const char* EcSii_GetCategoryName(ec_sii_category_t cat);

EC_API int EcSii_FindCategory(const uint8_t* sii_data, int sii_size,
                                    uint16_t cat_type, int* out_size_bytes);

EC_API int EcSii_EnumerateCategories(const uint8_t* sii_data, int sii_size,
                                           uint16_t* cat_types, int capacity);

EC_API int EcSii_ParseGeneral(const uint8_t* cat_data, int cat_size,
                                    ec_sii_general_t* out);

EC_API int EcSii_GetStringByIndex(const uint8_t* cat_data, int cat_size,
                                        int idx, char* out_buf, int buf_size);

EC_API int EcSii_GetStringCount(const uint8_t* cat_data, int cat_size);

EC_API uint32_t EcSii_GetVendorId(const uint8_t* sii_data, int sii_size);

EC_API uint32_t EcSii_GetProductCode(const uint8_t* sii_data, int sii_size);

EC_API uint32_t EcSii_GetRevision(const uint8_t* sii_data, int sii_size);

EC_API uint32_t EcSii_GetSerialNumber(const uint8_t* sii_data, int sii_size);

EC_API uint16_t EcSii_GetConfiguredAlias(const uint8_t* sii_data, int sii_size);

typedef enum {
    EC_DEV_UNKNOWN    = 0,
    EC_DEV_COUPLER    = 1,
    EC_DEV_TERMINAL   = 2,
    EC_DEV_DRIVE      = 3,
    EC_DEV_SENSOR     = 4,
    EC_DEV_GATEWAY    = 5,
    EC_DEV_SAFETY     = 6,
    EC_DEV_CONTROLLER = 7
} ec_device_type_t;

#define EC_VID_BECKHOFF       0x00000002u
#define EC_VID_SIEMENS        0x0000002Au
#define EC_VID_BALLUFF        0x00000083u
#define EC_VID_PHOENIX        0x000000A9u
#define EC_VID_MURR           0x000000ABu
#define EC_VID_BOSCH_REXROTH  0x000000F5u
#define EC_VID_PANASONIC      0x0000010Cu
#define EC_VID_SMC            0x00000114u
#define EC_VID_IFM            0x000001C0u
#define EC_VID_FESTO          0x0000022Du
#define EC_VID_TURCK          0x0000047Fu
#define EC_VID_OMRON          0x00000539u
#define EC_VID_WAGO           0x0000066Fu
#define EC_VID_SCHNEIDER      0x00000800u

EC_API ec_device_type_t EcCouplerId_DetectDeviceType(uint32_t vendor_id, uint32_t product_code);

EC_API int EcCouplerId_IsCoupler(uint32_t vendor_id, uint32_t product_code);

EC_API int EcCouplerId_IsTerminal(uint32_t vendor_id, uint32_t product_code);

EC_API const char* EcCouplerId_GetVendorName(uint32_t vendor_id);

EC_API const char* EcCouplerId_GetVendorNameEn(uint32_t vendor_id);

EC_API const char* EcCouplerId_GetDeviceTypeName(ec_device_type_t type);

EC_API const char* EcCouplerId_GetCouplerModel(uint32_t vendor_id, uint32_t product_code);

EC_API int EcCouplerId_GetVendorCount(void);

EC_API int EcCouplerId_GetEntryCount(void);

typedef enum {
    EC_DIAG_TOPO_LINEAR      = 0,
    EC_DIAG_TOPO_RING        = 1,
    EC_DIAG_TOPO_RING_BRANCH = 2,
    EC_DIAG_TOPO_UNKNOWN     = 0xFF
} ec_diag_topology_t;

typedef enum {
    EC_DIAG_TIMING_UNKNOWN  = 0,
    EC_DIAG_TIMING_HW_TIMER = 1,
    EC_DIAG_TIMING_SW_TIMER = 2,
    EC_DIAG_TIMING_DEGRADED = 3,
    EC_DIAG_TIMING_RT_READY = 4,
    EC_DIAG_TIMING_RT_ERROR = 5
} ec_diag_timing_t;

typedef enum {
    EC_DIAG_BP_LINK_LOST = 0,
    EC_DIAG_BP_CRC_FAULT = 1,
    EC_DIAG_BP_UNKNOWN   = 0xFF
} ec_diag_breakpoint_t;

EC_API const char* EcDiagStrings_TopologyDescription(ec_diag_topology_t topo);

EC_API const char* EcDiagStrings_TimingMode(ec_diag_timing_t mode);

EC_API const char* EcDiagStrings_BreakpointType(ec_diag_breakpoint_t bp);

EC_API void EcDiagStrings_FormatBreakpoint(uint16_t slave_idx,
                                                 uint8_t port,
                                                 ec_diag_breakpoint_t bp,
                                                 char* buf,
                                                 int buf_size);

#ifdef __cplusplus
}
#endif

#endif
