
#ifndef ETHERCAT_SLAVE_AOE_H
#define ETHERCAT_SLAVE_AOE_H

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

#ifdef __cplusplus
extern "C" {
#endif

typedef enum {
    AOE_RC_NO_ERROR                       = 0x0000,
    AOE_RC_INTERNAL_ERROR                 = 0x0001,
    AOE_RC_NO_REALTIME                    = 0x0002,
    AOE_RC_ALLOCATION_LOCKED_MEMORY_ERROR = 0x0003,
    AOE_RC_INSERT_MAILBOX_ERROR           = 0x0004,
    AOE_RC_WRONG_RECEIVE_HMSG             = 0x0005,
    AOE_RC_TARGET_PORT_NOT_FOUND          = 0x0006,
    AOE_RC_TARGET_MACHINE_NOT_FOUND       = 0x0007,
    AOE_RC_UNKNOWN_COMMAND_ID             = 0x0008,
    AOE_RC_BAD_TASK_ID                    = 0x0009,
    AOE_RC_NO_IO                          = 0x000A,
    AOE_RC_UNKNOWN_AMS_COMMAND            = 0x000B,
    AOE_RC_WIN32_ERROR                    = 0x000C,
    AOE_RC_PORT_NOT_CONNECTED             = 0x000D,
    AOE_RC_INVALID_AMS_LENGTH             = 0x000E,
    AOE_RC_INVALID_AMS_NETID              = 0x000F,
    AOE_RC_LOW_INST_LEVEL                 = 0x0010,
    AOE_RC_NO_DEBUG_AVAILABLE             = 0x0011,
    AOE_RC_PORT_DISABLED                  = 0x0012,
    AOE_RC_PORT_ALREADY_CONNECTED         = 0x0013,
    AOE_RC_AMS_SYNC_WIN32_ERROR           = 0x0014,
    AOE_RC_AMS_SYNC_TIMEOUT               = 0x0015,
    AOE_RC_AMS_SYNC_AMS_ERROR             = 0x0016,
    AOE_RC_AMS_SYNC_NO_INDEX_MAP          = 0x0017,
    AOE_RC_INVALID_AMS_PORT               = 0x0018,
    AOE_RC_NO_MEMORY                      = 0x0019,
    AOE_RC_TCP_SEND_ERROR                 = 0x001A,
    AOE_RC_HOST_UNREACHABLE               = 0x001B,
    AOE_RC_INVALID_AMS_FRAGMENT           = 0x001C,
    AOE_RC_WSA_SERVICE_NOT_STARTED        = 0x274D,

    AOE_RC_DEVICE_INVALID_GROUP           = 0x0700,
    AOE_RC_DEVICE_INVALID_OFFSET          = 0x0701,
    AOE_RC_DEVICE_INVALID_ACCESS          = 0x0702,
    AOE_RC_DEVICE_INVALID_SIZE            = 0x0703,
    AOE_RC_DEVICE_INVALID_DATA            = 0x0704,
    AOE_RC_DEVICE_NOT_READY               = 0x0705,
    AOE_RC_DEVICE_BUSY                    = 0x0706,
    AOE_RC_DEVICE_INVALID_CONTEXT         = 0x0707,
    AOE_RC_DEVICE_NOT_FOUND               = 0x0708,
    AOE_RC_DEVICE_ALREADY_EXISTS          = 0x0709,
    AOE_RC_DEVICE_SYMBOL_NOT_FOUND        = 0x070A,
    AOE_RC_DEVICE_SYMBOL_VERSION_INVALID  = 0x070B,
    AOE_RC_DEVICE_INVALID_STATE           = 0x070C,
    AOE_RC_DEVICE_TIMEOUT                 = 0x0712,
    AOE_RC_DEVICE_NO_INTERFACE_QUERY      = 0x0713,
    AOE_RC_DEVICE_INVALID_INTERFACE       = 0x0714,
    AOE_RC_DEVICE_INVALID_CLASS_ID        = 0x0715,
    AOE_RC_DEVICE_INVALID_OBJECT_ID       = 0x0716,
    AOE_RC_DEVICE_PENDING                 = 0x0717,
    AOE_RC_DEVICE_ABORTED                 = 0x0718,
    AOE_RC_DEVICE_WARNING                 = 0x0719,
    AOE_RC_DEVICE_INVALID_ARRAY_INDEX     = 0x071A,
    AOE_RC_DEVICE_SYMBOL_NOT_ACTIVE       = 0x071B,
    AOE_RC_DEVICE_ACCESS_DENIED           = 0x071C,

    AOE_RC_CLIENT_ERROR                   = 0x0740,
    AOE_RC_CLIENT_INVALID_PARAM           = 0x0741,
    AOE_RC_CLIENT_LIST_EMPTY              = 0x0742,
    AOE_RC_CLIENT_VAR_ALREADY_IN_USE      = 0x0743,
    AOE_RC_CLIENT_INVOKE_TIMEOUT          = 0x0744,
    AOE_RC_CLIENT_PORT_NOT_OPEN           = 0x0745,
    AOE_RC_CLIENT_NOT_STARTED             = 0x0746,
    AOE_RC_CLIENT_QUEUE_FULL              = 0x0750
} aoe_result_code_t;

#ifndef DYNAMIC_LOAD

BOOL     dx_aoe_send_command(uint16_t master_index, uint16_t slave, uint16_t target_port,
                         uint16_t command_id, const uint8_t* data, uint32_t size,
                         uint8_t** response, uint32_t* response_size, int timeout);

BOOL     dx_aoe_read_write(uint16_t master_index, uint16_t slave,
                       uint32_t index_group, uint32_t index_offset,
                       uint32_t read_len, uint32_t write_len, const uint8_t* write_data,
                       uint8_t** read_data, uint32_t* bytes_read, int timeout);
BOOL     dx_aoe_read_device_info(uint16_t master_index, uint16_t slave,
                            uint8_t* major, uint8_t* minor, uint16_t* build,
                            char* name, int name_size, int timeout);
BOOL     dx_aoe_read_state(uint16_t master_index, uint16_t slave,
                       uint16_t* ads_state, uint16_t* device_state, int timeout);
BOOL     dx_aoe_write_control(uint16_t master_index, uint16_t slave,
                          uint16_t ads_state, uint16_t device_state,
                          const uint8_t* data, int data_size, int timeout);
BOOL     dx_aoe_add_notification(uint16_t master_index, uint16_t slave,
                             uint32_t index_group, uint32_t index_offset, uint32_t length,
                             uint32_t trans_mode, uint32_t max_delay, uint32_t cycle_time,
                             uint32_t* handle, int timeout);
BOOL     dx_aoe_del_notification(uint16_t master_index, uint16_t slave,
                             uint32_t handle, int timeout);
BOOL     dx_aoe_set_config(uint16_t master_index, uint16_t slave,
                       const uint8_t* target_net_id, uint16_t target_port,
                       const uint8_t* source_net_id, uint16_t source_port);
BOOL     dx_aoe_get_config(uint16_t master_index, uint16_t slave,
                       uint8_t* target_net_id, uint16_t* target_port,
                       uint8_t* source_net_id, uint16_t* source_port);

BOOL     dx_aoe_start_notification_listener(uint16_t master_index);
BOOL     dx_aoe_stop_notification_listener(void);
BOOL     dx_aoe_is_notification_listening(void);
int      dx_aoe_register_notification(uint16_t slave, uint32_t handle,
                                  uint32_t index_group, uint32_t index_offset,
                                  uint32_t data_length,
                                  aoe_notification_callback_t callback, void* user_data);
BOOL     dx_aoe_unregister_notification(int subscription_index);

static __inline BOOL aoe_read(uint16_t master_index, uint16_t slave,
                                     uint32_t index_group, uint32_t index_offset,
                                     uint32_t read_len, int timeout,
                                     uint8_t** out_data, uint32_t* out_bytes_read)
{

    return dx_aoe_read_write(master_index, slave, index_group, index_offset,
                        read_len, 0, NULL, out_data, out_bytes_read, timeout);
}

static __inline BOOL aoe_write(uint16_t master_index, uint16_t slave,
                                      uint32_t index_group, uint32_t index_offset,
                                      const uint8_t* data, uint32_t data_len, int timeout)
{

    uint8_t* read_ptr = NULL;
    uint32_t bytes_read = 0;
    BOOL ok = dx_aoe_read_write(master_index, slave, index_group, index_offset,
                           0, data_len, data, &read_ptr, &bytes_read, timeout);
    if (read_ptr) {
        FreeMemory(read_ptr);
    }
    (void)bytes_read;
    return ok;
}

#endif

#ifdef __cplusplus
}
#endif

#endif
