
#ifndef ETHERCAT_SLAVE_FSOE_H
#define ETHERCAT_SLAVE_FSOE_H

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

#ifdef __cplusplus
extern "C" {
#endif

#ifndef DYNAMIC_LOAD

BOOL     dx_fsoe_init_connection(uint16_t master_index, uint16_t slave_index, fsoe_config_t* config);

BOOL     dx_fsoe_close_connection(uint16_t master_index, uint16_t slave_index);

BOOL     dx_fsoe_get_status(uint16_t master_index, uint16_t slave_index, fsoe_status_t* status);

BOOL     dx_fsoe_request_state(uint16_t master_index, uint16_t slave_index, int target_state);

int      dx_fsoe_get_state(uint16_t master_index, uint16_t slave_index);

BOOL     dx_fsoe_reset(uint16_t master_index, uint16_t slave_index);

BOOL     dx_fsoe_write_safe_output(uint16_t master_index, uint16_t slave_index,
                              const uint8_t* data, uint32_t size);

BOOL     dx_fsoe_read_safe_input(uint16_t master_index, uint16_t slave_index,
                            uint8_t* data, uint32_t* size);

BOOL     dx_fsoe_download_parameters(uint16_t master_index, uint16_t slave_index,
                                 const uint8_t* param_data, uint32_t param_size, uint32_t* sra_crc);

BOOL     dx_fsoe_set_failsafe_output(uint16_t master_index, uint16_t slave_index,
                                const uint8_t* data, uint32_t size);

BOOL     dx_fsoe_check_watchdog(uint16_t master_index, uint16_t slave_index);

int      dx_fsoe_get_last_error(uint16_t master_index, uint16_t slave_index);

void     dx_fsoe_clear_error(uint16_t master_index, uint16_t slave_index);

BOOL     dx_fsoe_is_slave_capable(uint16_t master_index, uint16_t slave_index);

uint16_t dx_fsoe_get_connection_count(uint16_t master_index);

void     dx_fsoe_process_cycle(uint16_t master_index);

BOOL     DxSafeMdpInitConnection(uint16_t master_index, uint16_t slave_index,
                                uint16_t connection_index, fsoe_mdp_config_t* config);

BOOL     DxSafeMdpCloseConnection(uint16_t master_index, uint16_t slave_index,
                                 uint16_t connection_index);

BOOL     DxSafeMdpGetStatus(uint16_t master_index, uint16_t slave_index,
                           uint16_t connection_index, fsoe_status_t* status);

BOOL     DxSafeMdpRequestState(uint16_t master_index, uint16_t slave_index,
                              uint16_t connection_index, int target_state);

int      DxSafeMdpGetState(uint16_t master_index, uint16_t slave_index,
                          uint16_t connection_index);

BOOL     DxSafeMdpReset(uint16_t master_index, uint16_t slave_index,
                       uint16_t connection_index);

BOOL     DxSafeMdpWriteSafeOutput(uint16_t master_index, uint16_t slave_index,
                                 uint16_t connection_index, const uint8_t* data, uint32_t size);

BOOL     DxSafeMdpReadSafeInput(uint16_t master_index, uint16_t slave_index,
                               uint16_t connection_index, uint8_t* data, uint32_t* size);

BOOL     DxSafeMdpDownloadParameters(uint16_t master_index, uint16_t slave_index,
                                    uint16_t connection_index, const uint8_t* param_data,
                                    uint32_t param_size, uint32_t* sra_crc);

BOOL     DxSafeMdpSetFailsafeOutput(uint16_t master_index, uint16_t slave_index,
                                   uint16_t connection_index, const uint8_t* data, uint32_t size);

BOOL     DxSafeMdpCheckWatchdog(uint16_t master_index, uint16_t slave_index,
                               uint16_t connection_index);

int      DxSafeMdpGetLastError(uint16_t master_index, uint16_t slave_index,
                              uint16_t connection_index);

void     DxSafeMdpClearError(uint16_t master_index, uint16_t slave_index,
                            uint16_t connection_index);

uint16_t DxSafeMdpGetSlaveConnectionCount(uint16_t master_index, uint16_t slave_index);

uint16_t DxSafeMdpDetectConnections(uint16_t master_index, uint16_t slave_index);

BOOL     DxSafeMdpGetDeviceAddress(uint16_t master_index, uint16_t slave_index,
                                  uint16_t* safety_address);

BOOL     DxSafeMdpGetModuleCommParam(uint16_t master_index, uint16_t slave_index,
                                    uint16_t module_number, uint8_t* param_data, uint32_t* param_size);

BOOL     DxSafeMdpGetModuleDiagnosis(uint16_t master_index, uint16_t slave_index,
                                    uint16_t module_number, uint16_t* connection_state,
                                    uint16_t* connection_diagnosis);

BOOL     dx_fsoe_validate_conn_id(uint16_t conn_id);

#endif

uint16_t fsoe_crc16(const uint8_t* data, uint32_t length);

uint16_t fsoe_crc16_with_conn_id(const uint8_t* data, uint32_t length,
                                        uint16_t connection_id);

typedef struct {
    uint16_t command_offset;
    uint16_t safe_data_offset;
    uint16_t safe_data_length;
    uint16_t crc_segment_count;
    uint16_t crc_offsets[8];
    uint16_t conn_id_offset;
    uint16_t total_length;
    uint16_t padding_bytes;
} fsoe_pdo_layout_t;

typedef struct {
    uint8_t  command;
    uint16_t connection_id;
    uint8_t  safe_data[16];
    uint16_t crc_segments[8];
} fsoe_pdo_frame_t;

int      fsoe_pdo_frame_to_bytes(const fsoe_pdo_frame_t* frame,
                                        const fsoe_pdo_layout_t* layout,
                                        uint8_t* out_buffer, uint32_t out_buffer_size);

int      fsoe_pdo_frame_from_bytes(const uint8_t* data, uint32_t data_size,
                                          const fsoe_pdo_layout_t* layout,
                                          fsoe_pdo_frame_t* dx_nic_send);

BOOL     fsoe_pdo_frame_validate_crc_segments(const fsoe_pdo_frame_t* frame,
                                                      const fsoe_pdo_layout_t* layout);

BOOL     fsoe_validate_conn_id(uint16_t conn_id);

#ifdef __cplusplus
}
#endif

#endif
