#include "user_server.h"
#include "user_nfc.h"
#include "user_elect.h"
#include "user_led.h"
#include "dip_sw.h"
#include "elect_sw.h"

tmosTaskID user_server_task_id = INVALID_TASK_ID;

static uint32_t offline_timeout = CAN_OFFLINE_TIMEOUT_DEFAULT / USER_SERVER_INTERVAL;
static bool offline_stat = false;
static uint8_t can_idx = 0xFF;
static lock_data_s lock_data = {
	.lock_stat = 0,
    .elect_act = 0,
	.elect_stat = 0,
	.lock_id = {0},
};

static can_open_data_s can_open_data;

/*******************************************************************************
  * @函数名称   prvUser_server_dev_type_protocol
  * @函数说明   设备类型索引解析
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_dev_type_protocol(void)
{
    if(can_open_data.subidx == REG_DEV_TYPE_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_WORD;
            s_data.idx = REG_DEV_TYPE_IDX;
            s_data.subidx = REG_DEV_TYPE_SUBIDX;
            s_data.data[0] = DEV_TYPE;
            s_data.data[1] = DEV_TYPE >> 8;
            s_data.data[2] = 0;
            s_data.data[3] = 0;
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_DEV_TYPE_IDX;
            s_data.subidx = REG_DEV_TYPE_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
}

/*******************************************************************************
  * @函数名称   prvUser_server_version_protocol
  * @函数说明   版本号索引解析
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_version_protocol(void)
{
    if(can_open_data.subidx == REG_VERSION_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_DWORD;
            s_data.idx = REG_VERSION_IDX;
            s_data.subidx = REG_VERSION_SUBIDX;
            s_data.data[0] = HARDWARE_VERSION;
            s_data.data[1] = HARDWARE_VERSION >> 8;
            s_data.data[2] = SOFTWARE_VERSION;
            s_data.data[3] = SOFTWARE_VERSION >> 8;
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_VERSION_IDX;
            s_data.subidx = REG_VERSION_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
}

/*******************************************************************************
  * @函数名称   prvUser_server_lock_stat_protocol
  * @函数说明   挂锁索引解析
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_lock_stat_protocol(void)
{
    if(can_open_data.subidx == REG_LOCK_STAT_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_BYTE;
            s_data.idx = REG_LOCK_STAT_IDX;
            s_data.subidx = REG_LOCK_STAT_SUBIDX;
            memset(s_data.data, 0, 4);
            memcpy(s_data.data,(uint8_t *)&(lock_data.lock_stat), 1);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_LOCK_STAT_IDX;
            s_data.subidx = REG_LOCK_STAT_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
}

/*******************************************************************************
  * @函数名称   prvUser_server_elect_stat_protocol
  * @函数说明   电磁锁控制索引解析
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_elect_stat_protocol(void)
{
    if(can_open_data.subidx == REG_ELECT_STAT_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_WORD;
            s_data.idx = REG_ELECT_STAT_IDX;
            s_data.subidx = REG_ELECT_STAT_SUBIDX;
            memset(s_data.data, 0, 4);
            memcpy(s_data.data,(uint8_t *)&(lock_data.elect_stat), 2);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else if(can_open_data.ins == S_INS_WR_WORD)
        {
            uint16_t temp = 0;
            memcpy((uint8_t *)&temp, (uint8_t *)&can_open_data.data, 2);

            can_open_data_s s_data;
            s_data.ins = R_INS_WR_SUCC;
            s_data.idx = REG_ELECT_STAT_IDX;
            s_data.subidx = REG_ELECT_STAT_SUBIDX;
            memset(s_data.data, 0, 4);
            memcpy(s_data.data,(uint8_t *)&temp, 2);
            vUser_can_send_data((uint8_t *)&s_data, 8);

            for(int i = 0; i < LOCK_COUNT; i++)
            {
                if((temp & (1 << (i + 8))) != 0)
                {
                    if((temp & (1 << i)) != 0)
                    {
                        set_elect_work_stat(i, true);
                    }
                    else{
                        set_elect_work_stat(i, false);
                    }
                }
            } 
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_ELECT_STAT_IDX;
            s_data.subidx = REG_ELECT_STAT_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
}

/*******************************************************************************
  * @函数名称   prvUser_server_lock_id_protocol
  * @函数说明   挂锁NFC号索引解析
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_lock_id_protocol(void)
{
    if(can_open_data.subidx == REG_LOCK_01_ID_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_DWORD;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_01_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            s_data.data[0] = lock_data.lock_id[0][3];
            s_data.data[1] = lock_data.lock_id[0][2];
            s_data.data[2] = lock_data.lock_id[0][1];
            s_data.data[3] = lock_data.lock_id[0][0];
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_01_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
    else if(can_open_data.subidx == REG_LOCK_02_ID_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_DWORD;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_02_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            s_data.data[0] = lock_data.lock_id[1][3];
            s_data.data[1] = lock_data.lock_id[1][2];
            s_data.data[2] = lock_data.lock_id[1][1];
            s_data.data[3] = lock_data.lock_id[1][0];
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_02_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
    else if(can_open_data.subidx == REG_LOCK_03_ID_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_DWORD;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_03_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            s_data.data[0] = lock_data.lock_id[2][3];
            s_data.data[1] = lock_data.lock_id[2][2];
            s_data.data[2] = lock_data.lock_id[2][1];
            s_data.data[3] = lock_data.lock_id[2][0];
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_03_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
    else if(can_open_data.subidx == REG_LOCK_04_ID_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_DWORD;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_04_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            s_data.data[0] = lock_data.lock_id[3][3];
            s_data.data[1] = lock_data.lock_id[3][2];
            s_data.data[2] = lock_data.lock_id[3][1];
            s_data.data[3] = lock_data.lock_id[3][0];
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_04_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
    else if(can_open_data.subidx == REG_LOCK_05_ID_SUBIDX)
    {
        if(can_open_data.ins == S_INS_RD)
        {
            can_open_data_s s_data;
            s_data.ins = R_INS_RD_DWORD;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_05_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            s_data.data[0] = lock_data.lock_id[4][3];
            s_data.data[1] = lock_data.lock_id[4][2];
            s_data.data[2] = lock_data.lock_id[4][1];
            s_data.data[3] = lock_data.lock_id[4][0];
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
        else{
            can_open_data_s s_data;
            s_data.ins = R_INS_WR_FAIL;
            s_data.idx = REG_LOCK_ID_IDX;
            s_data.subidx = REG_LOCK_05_ID_SUBIDX;
            memset(s_data.data, 0, 4);
            vUser_can_send_data((uint8_t *)&s_data, 8);
        }
    }
}

/*******************************************************************************
  * @函数名称   prvUser_server_can_protocol
  * @函数说明   can总线协议解析
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_can_protocol(void)
{
    bool stat = false;
    switch(can_open_data.idx)
    {
        case REG_DEV_TYPE_IDX:{
            prvUser_server_dev_type_protocol();
            stat = true;
        }break;
        case REG_VERSION_IDX:{
            prvUser_server_version_protocol();
            stat = true;
        }break;
        case REG_LOCK_STAT_IDX:{
            prvUser_server_lock_stat_protocol();
            stat = true;
        }break;
        case REG_ELECT_STAT_IDX:{
            prvUser_server_elect_stat_protocol();
            stat = true;
        }break;
        case REG_LOCK_ID_IDX:{
            prvUser_server_lock_id_protocol();
            stat = true;
        }break;
        default:break;
    }

    if(stat == true)
    {
        offline_timeout = CAN_OFFLINE_TIMEOUT_DEFAULT / USER_SERVER_INTERVAL;
        if(offline_stat == true)
        {
            offline_stat = false;
            vUser_led_set_alarm_view(LED_ALL_ALARM_OFFLINE, false);
        }
    }
}

/*******************************************************************************
  * @函数名称   ble_action_rst_pro
  * @函数说明   重启倒计时
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static uint8_t rst_timeout = 5;
static void ble_action_rst_pro(void)
{
    if(rst_timeout == 0)
    {
        /* Software reset */
        NVIC_SystemReset();
    }
    else{
	    rst_timeout--;
	    PRINT("Restart countdown %d second\n", rst_timeout);
    }
}

/*******************************************************************************
  * @函数名称   prvUser_server_can_offline_check
  * @函数说明   CAN总线离线检测
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_can_offline_check(void)
{
    if(offline_timeout > 0)
    {
        if(offline_timeout == 1)
        {
            if(offline_stat == false)
            {
                offline_stat = true;
                vUser_led_set_alarm_view(LED_ALL_ALARM_OFFLINE, true);
            }
        }
        offline_timeout--;
    }
}

/*******************************************************************************
  * @函数名称   user_server_task_process_event
  * @函数说明   task的event处理回调函数,需要在注册task时候,传进去
  * @输入参数  	task_id：任务ID
               events：事件
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static uint16_t user_server_task_process_event(uint8_t task_id, uint16_t events)
{
    //event 处理
    if(events & (1 << SERVER_QUEUE_TIME))
    {
        prvUser_server_can_offline_check();
        return (events ^ (1 << SERVER_QUEUE_TIME)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    if(events & (1 << SERVER_QUEUE_CAN))
    {
        prvUser_server_can_protocol();
        return (events ^ (1 << SERVER_QUEUE_CAN)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    if(events & (1 <<SERVER_BLE_RST))
    {
        ble_action_rst_pro();
        return (events ^ (1 << SERVER_BLE_RST)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    return 0;
}

/*******************************************************************************
  * @函数名称   vUser_server_task_start
  * @函数说明   定时任务开始
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_server_task_start(void)
{
    bStatus_t stat = tmos_start_reload_task(user_server_task_id, (1 << SERVER_QUEUE_TIME), MS1_TO_SYSTEM_TIME(USER_SERVER_INTERVAL));
}

/*******************************************************************************
  * @函数名称   vUser_server_set_led_stat
  * @函数说明   设置LED灯变化
  * @输入参数  	idx：底座号
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void vUser_server_set_led_stat(uint8_t idx)
{
    if(((lock_data.elect_stat & (1 << (idx + 8))) != 0 ))
    {
        vUser_led_set_view_stat(idx, LED_VIEW_ELECT_FAUIL);
        bElectsw_set_fail(idx);
    }
    else if(((lock_data.elect_stat & (1 << idx)) != 0 ) && ((lock_data.lock_stat & (1 << idx)) != 0))
    {
        vUser_led_set_view_stat(idx, LED_VIEW_LOCK_ELECT);
    }
    else if(((lock_data.elect_stat & (1 << idx)) == 0 ) && ((lock_data.lock_stat & (1 << idx)) == 0))
    {
        vUser_led_set_view_stat(idx, LED_VIEW_NOLOCK_NOELECT);
    }
    else if(((lock_data.elect_stat & (1 << idx)) == 0 ) && ((lock_data.lock_stat & (1 << idx)) != 0))
    {
        vUser_led_set_view_stat(idx, LED_VIEW_LOCK_NOELECT);
    }
    else if(((lock_data.elect_stat & (1 << idx)) != 0 ) && ((lock_data.lock_stat & (1 << idx)) == 0))
    {
        vUser_led_set_view_stat(idx, LED_VIEW_NOLOCK_ELECT);
    }
}

/*******************************************************************************
  * @函数名称   vUser_server_get_lock_data
  * @函数说明   获取挂锁底座数据变量
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   挂锁底座数据变量指针
*******************************************************************************/
lock_data_s *vUser_server_get_lock_data(void)
{
    return &lock_data;
}

/*******************************************************************************
  * @函数名称   vUser_can_recv_data_callback
  * @函数说明   can接收数据上报回调
  * @输入参数  	data：数据指针
               size：数据长度
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_can_recv_data_callback(uint8_t *data, uint8_t size)
{
    memcpy(&can_open_data, data, sizeof(can_open_data_s));
    bStatus_t stat = tmos_start_task(user_server_task_id, (1 << SERVER_QUEUE_CAN), MS1_TO_SYSTEM_TIME(1));
}

/*******************************************************************************
  * @函数名称   prvUser_server_check_elect_stat
  * @函数说明   检测电磁锁状态是否正常
  * @输入参数  	idx：挂锁底座号
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_server_check_elect_stat(uint8_t idx)
{
    if((lock_data.elect_act & (1 << (idx + 8))) != 0)
    {
        lock_data.elect_stat |= (1 << (idx + 8));
    }
    else{
        lock_data.elect_stat &= ~(1 << (idx + 8));
    }
    // PRINT("elect stat=0x%04X,0x%04X\n", lock_data.elect_stat, lock_data.elect_act);
    vUser_server_set_led_stat(idx);
}

/*******************************************************************************
  * @函数名称   vUser_nfc_upload_card_callback
  * @函数说明   钥匙nfc标签读取上报回调
  * @输入参数  	idx：挂锁底座号
               stat：是否有挂锁
               card：挂锁RFID号
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_nfc_upload_card_callback(uint8_t idx, bool stat, unsigned char *card)
{
    if(stat == true)
    {
        lock_data.lock_stat |= (1 << idx);
        memcpy(lock_data.lock_id[idx], &card[4], 4);
        set_elect_work_stat(idx, true);
    }
    else{
        lock_data.lock_stat &= ~(1 << idx);
        memcpy(lock_data.lock_id[idx], &card[4], 4);
    }
    vUser_server_set_led_stat(idx);
}

/*******************************************************************************
  * @函数名称   vUser_elect_upload_stat_callback
  * @函数说明   设置挂锁位电磁锁状态回调
  * @输入参数   idx：挂锁底座号
                stat：电磁锁是否锁死
                finish：电磁锁工作状态
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void vUser_elect_upload_stat_callback(uint8_t idx, bool stat, bool finish)
{
	if(stat == true)
	{
		lock_data.elect_act |= (1 << idx);
	}
	else{
		lock_data.elect_act &= ~(1 << idx);
	}

    if(finish == false)
    {
        if((lock_data.elect_act & (1 << idx)) != (lock_data.elect_stat & (1 << idx)))
        {
            lock_data.elect_act |= (1 << (idx + 8));
        }
    }
    else{
        prvUser_server_check_elect_stat(idx);
    }
}

/*******************************************************************************
  * @函数名称   prvDipsw_upload_callback
  * @函数说明   地址读取回调
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvDipsw_upload_callback(uint8_t addr)
{
    vUser_can_set_addr(addr);
    elect_start(addr);

    if(addr != can_idx)
    {
        can_idx = addr;
        if(addr > 0)
        {
            vUser_led_set_alarm_view(LED_ALL_ALARM_CAN_IDX_ERROR, false);
        }
        else{
            vUser_led_set_alarm_view(LED_ALL_ALARM_CAN_IDX_ERROR, true);
        }
    }
}

/*******************************************************************************
  * @函数名称   prvDipsw_upload_callback
  * @函数说明   地址读取回调
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvElectsw_upload_callback(uint8_t idx, bool stat)
{
    if(stat == true)
	{
		lock_data.elect_stat |= (1 << idx);
	}
	else{
		lock_data.elect_stat &= ~(1 << idx);
	}

    lock_data.elect_act &= ~(1 << (idx + 8));
    prvUser_server_check_elect_stat(idx);
}

/*******************************************************************************
  * @函数名称   vUser_server_init
  * @函数说明   初始化
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_server_init(void)
{
    vUser_can_set_recv_data_func(prvUser_can_recv_data_callback);
    vUser_nfc_set_upload_key_stat_func(prvUser_nfc_upload_card_callback);
    vUser_elect_set_upload_stat_func(vUser_elect_upload_stat_callback);
    vDipsw_set_upload_func(prvDipsw_upload_callback);
    vElectsw_set_upload_func(prvElectsw_upload_callback);

    user_server_task_id  = TMOS_ProcessEventRegister(user_server_task_process_event);
    PRINT("user_server_task_id=%d\n", user_server_task_id);
}