#ifndef CIFX_COMMUNICATOR_HH
#define CIFX_COMMUNICATOR_HH
#include "cifxlinux.h"
#include "rcX_Public.h"
#include <unistd.h>
#include <iostream>
#include <queue>
#include <mutex>
#include <vector>
#include <thread>
#include <atomic>
#include <chrono>
#include "../error_code/error_code.h"
namespace agv
{
    /*
    * @Description: cifx RE 50 PNS slave, communicate with PLC through Profinet IO
    * @Author: yct
    * @Date: 2020-04-26 13:40:07
    * @LastEditTime: 2020-04-28 17:41:07
    * @LastEditors: yct
    */
    class Cifx_communicator
    {

    // 默认cifx设备名称
    #define CIFX_DEV "cifX0"
    #define MAX_DATA_SIZE 1024
    #define WHEEL_INPUT_AREA 0
    #define WHEEL_INPUT_AREA_SIZE 8
    #define WHEEL_OUTPUT_AREA 0 
    #define WHEEL_OUTPUT_AREA_SIZE 8

    public:
    // cifx 初始化状态，指示已完成几个初始化步骤，用于析构调用
    enum cifx_state
    {
        CIFX_UNINITIALIZED=-1,
        CIFX_INSTANCE_CREATED,
        CIFX_DRIVER_INITAILIZED,
        CIFX_DRIVER_OPENED,
        CIFX_CHANNEL_OPENED,
        CIFX_BUS_IS_ON,
    };

    // 特定区域的数据结构块
    typedef struct area_data_block
    {
    public: 
        area_data_block(uint32_t area_number){
            this->area_number = area_number;
            memset(this->data, 0, MAX_DATA_SIZE);
        }
        area_data_block(uint32_t area_number, uint32_t data_length, char *data){
            this->area_number = area_number;
            memcpy(this->data, data, std::min((uint32_t)MAX_DATA_SIZE, data_length));
        }
        struct area_data_block & operator=(struct area_data_block area_data)
        {
            this->area_number = area_data.area_number;
            memcpy(this->data, area_data.data, (uint32_t)MAX_DATA_SIZE);
        }
        uint32_t area_number;
        char data[MAX_DATA_SIZE];
    } AREA_DATA_BLOCK;

    // 包含所有待写入指令与信息的数据块
    typedef struct write_cmd_data_block
    {
    public:
        write_cmd_data_block(uint32_t area_number, uint32_t offset, uint32_t data_length, char *data)
        {
            this->area_number = area_number;
            this->offset = offset;
            this->data_length = data_length;
            memcpy(this->data, data, std::min((uint32_t)MAX_DATA_SIZE, data_length));
        }
        struct write_cmd_data_block & operator=(struct write_cmd_data_block write_block)
        {
            this->area_number = write_block.area_number;
            this->offset = write_block.offset;
            this->data_length = write_block.data_length;
            memcpy(this->data, write_block.data, write_block.data_length);
            return *this;
        }
        uint32_t area_number;
        uint32_t offset;
        uint32_t data_length;
        char data[MAX_DATA_SIZE];
    } WRITE_CMD_DATA_BLOCK;

    // 读或写异常与时间记录
    typedef struct state_record
    {
    public:
        state_record()
        {
            state = SUCCESS;
            update_time = std::chrono::steady_clock::now();
        }
        Error_manager state;
        std::chrono::steady_clock::time_point update_time;
    }STATE_RECORD;

    typedef void (*CIFX_READ_CALLBACK)(AREA_DATA_BLOCK& read_data, void* pOwner);

    public:
        // 全局获取单例
        static Cifx_communicator* get_instance();
        // 全局释放
        static void release_instance();
        // 初始化函数
        Error_manager cifx_init();
        // 通过cifx将数据从PLC读入
        Error_manager cifx_read(uint32_t area_number, uint32_t offset, uint32_t data_length, char *data);
        // 通过cifx将数据写入PLC
        Error_manager cifx_write(uint32_t area_number, uint32_t offset, uint32_t data_length, char *data);
        // 获取初始化状态
        bool is_initialized();
        // 设置读数据回调，获取到不同数据时激活
        Error_manager set_read_data_callback(CIFX_READ_CALLBACK callback, void* pOwner);

    private:
        // 无参构造函数
        Cifx_communicator();
        // 析构函数
        ~Cifx_communicator();
        // 读写线程函数
        static void data_exchange(Cifx_communicator* cifx_handle);
        

    private:
        static Cifx_communicator* g_cifx_ins; // cifx通信单例句柄
        static std::mutex g_cifx_access_mutex; // cifx访问互斥锁
        struct CIFX_LINUX_INIT m_init_params; // 初始化参数
        CIFXHANDLE m_cifx_driver_handle; // cifx 通道句柄
        // std::mutex m_cifx_read_mutex; // cifx 读互斥锁
        // std::mutex m_cifx_write_mutex; // cifx 写互斥锁
        STATE_RECORD m_read_state; // cifx 读异常标志
        STATE_RECORD m_write_state; // cifx 写异常标志
        std::vector<AREA_DATA_BLOCK> m_cifx_read_data_buffer; // cifx 读数据缓存区, 下标分别代表 area_number 与 offset
        std::queue<WRITE_CMD_DATA_BLOCK> m_write_cmd_queue; // cifx 待写入数据队列

        std::thread* m_data_exchange_thread; // 数据交换线程
        bool mb_exit; // 系统退出标记
        bool mb_thread_exit; // 线程退出标志
        bool mb_initialized; // 系统初始化完成标志
        int m_cifx_state; // 系统状态，即已初始化完成几个步骤
        CIFX_READ_CALLBACK m_read_callback; // 读回调成员
        void * mp_callback_owner; // 回调拥有者
    };
}
#endif //CIFX_COMMUNICATOR_HH