
#ifndef ETHERCAT_UTILS_ESI_H
#define ETHERCAT_UTILS_ESI_H

#pragma once

#include "../ethercat_types.h"
#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

#define ESI_MAX_NAME       128
#define ESI_MAX_DESC       128
#define ESI_MAX_TYPE       64
#define ESI_MAX_DATATYPE   32
#define ESI_MAX_SM         8
#define ESI_MAX_DC_MODES   8
#define ESI_MAX_PDO        16
#define ESI_MAX_PDO_ENTRY  32
#define ESI_MAX_CONFIG     256

#define ESI_MATCH_EXACT    0
#define ESI_MATCH_MAJOR    1
#define ESI_MATCH_IGNORE   2

typedef struct {
    bool sdoInfo;
    bool pdoAssign;
    bool pdoConfig;
    bool completeAccess;
    bool segmentedSdo;
    bool diagHistory;
} DarraEsiCoEDetails;

typedef struct {
    char     name[ESI_MAX_TYPE];
    char     description[ESI_MAX_DESC];
    uint16_t assignActivate;
    uint32_t cycleTimeSync0;
    int32_t  cycleTimeSync0Factor;
    uint32_t cycleTimeSync1;
    int32_t  cycleTimeSync1Factor;
    int32_t  shiftTimeSync0;
    int32_t  shiftTimeSync1;
} DarraEsiDcOpMode;

typedef struct {
    DarraEsiDcOpMode opModes[ESI_MAX_DC_MODES];
    int              opModeCount;
} DarraEsiDcConfiguration;

typedef struct {
    int      index;
    uint16_t startAddress;
    uint16_t defaultSize;
    uint8_t  controlByte;
    bool     enable;
    char     name[ESI_MAX_TYPE];
} DarraEsiSmInfo;

typedef struct {
    uint16_t index;
    uint8_t  subIndex;
    uint8_t  bitLength;
    char     name[ESI_MAX_TYPE];
    char     dataType[ESI_MAX_DATATYPE];
} DarraEsiPdoEntry;

typedef struct {
    uint16_t        index;
    char            name[ESI_MAX_TYPE];
    uint8_t         syncManager;
    bool            isFixed;
    bool            isMandatory;
    DarraEsiPdoEntry entries[ESI_MAX_PDO_ENTRY];
    int             entryCount;
} DarraEsiPdoInfo;

typedef struct {
    DarraEsiPdoInfo rxPdos[ESI_MAX_PDO];
    int             rxPdoCount;
    DarraEsiPdoInfo txPdos[ESI_MAX_PDO];
    int             txPdoCount;
} DarraEsiPdoConfiguration;

typedef struct {
    int requestTimeout;
    int responseTimeout;
} DarraEsiMailboxTimeout;

typedef struct {
    uint16_t recvMbxOffset;
    uint16_t recvMbxSize;
    uint16_t sendMbxOffset;
    uint16_t sendMbxSize;
} DarraEsiBootstrapInfo;

typedef struct {
    int                  byteSize;
    char                 configData[ESI_MAX_CONFIG];
    DarraEsiBootstrapInfo bootstrap;
    bool                 hasBootstrap;
} DarraEsiEepromConfiguration;

typedef struct {

    uint32_t vendorId;
    uint32_t productId;
    uint32_t revisionId;
    char     productName[ESI_MAX_NAME];
    char     vendorName[ESI_MAX_NAME];
    char     groupType[ESI_MAX_TYPE];

    DarraEsiCoEDetails coeDetails;
    bool     supportsCoE;
    bool     supportsSoE;
    bool     supportsFoE;
    bool     supportsEoE;
    bool     supportsVoE;

    DarraEsiDcConfiguration dcConfig;

    DarraEsiSmInfo syncManagers[ESI_MAX_SM];
    int            smCount;

    DarraEsiPdoConfiguration pdoConfig;

    DarraEsiMailboxTimeout mailboxTimeout;

    DarraEsiEepromConfiguration eepromConfig;

    int      ebusCurrent;
} DarraEsiDeviceInfo;

int esi_load_file(const char* filePath, DarraEsiDeviceInfo* info);

int esi_apply_startup(void* dll, uint16_t mi, uint16_t si, const char* filePath);

uint8_t eeprom_crc(const uint8_t* data, int length);

bool eeprom_validate_crc(const uint8_t* data, int length);

bool esi_match_revision(uint32_t actual, uint32_t expected, int strategy);

#ifdef __cplusplus
}
#endif

#endif
