#include "lora_port.h"
#include "message_list.h"
#include "radio.h"
#include "thread_lora.h"
#include "crc8.h"
#include <ctype.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <sys/epoll.h>
#include "thread_comm.h"

#define LORA_NODES_MAX 100
#define LORA_DTU_POLL_OFFBACK_MAX 30

#define LORA_INFO_FILE "/app/config/.lora"

#define LORA_NODE_INFO_FILE "/app/node/node_reg_info.txt"

#define MAXEPOLLSIZE 2
#define LORA_WAIT_TIMEOUT 130*2
#define LORA_SYNC_WAIT_TIMEOUT 800
typedef struct {

    uint64_t rcv_time;
    uint64_t send_time;
    uint32_t gw_sn_s;
    lora_addr_t gw_addr;
    bool lora_cfg_modify;
} module_lora_t;

typedef struct _lora_var_t {
    char sn_str[SN_MAX_LEN];
    radiodev *rfdev;
    lora_cfg_t lora_cfg;
    nodes_cfg_table_t *nodes_cfg_table; //节点信息
//此处根据模块需要添加
} lora_var_t;

static int get_register_info(uint8_t *data, int len,register_info_t *reg_info);
static bool service_flag = true;
static lora_var_t var = {0};

extern bool exit_sig;

static int Lora_FillPack(PackType *pack,	lora_addr_t addr,	uint8_t code,	uint8_t *data,	uint8_t size)
{
    if(pack == NULL)return -1;
    pack->addr = addr;
    pack->code = code;
    pack->size = size;
    pack->data = data;
    return 0;
}


/**
* @brief  将包里面的内容和数据转为可以发送的报文
* @param  pack：包信息
* @param  ptr：输出buff指针
* @retval 返回输出长度
*/
static int Lora_Pack2Hex(PackType *pack,uint8_t *ptr)
{
  int offset = 0;
  uint8_t *buff=ptr;
  memcpy(&buff[offset],&pack->addr,sizeof(pack->addr)); offset+=sizeof(pack->addr);
  memcpy(&buff[offset],&pack->code,sizeof(pack->code)); offset+=sizeof(pack->code);
  memcpy(&buff[offset],pack->data,pack->size); offset+=pack->size;
  pack->crc8_cal = pack->crc8_transf = my_crc8(buff,offset,LoRa_CRC_INIT);
  memcpy(&buff[offset],&pack->crc8_transf,sizeof(pack->crc8_transf)); offset+=sizeof(pack->crc8_transf);
  return offset;
}

/**
* @brief  将报文消息转换为数据包
* @param  pack：包信息
* @param  ptr：输入buff指针
* @retval 返回输出长度,读取到一包数据的长度，多包只取走前一包
*/
static int Lora_Hex2Pack(PackType *pack,uint8_t *ptr,int size)
{
    int offset = 0;
    uint8_t *buff=ptr;
    memcpy(&pack->addr,&buff[offset],sizeof(pack->addr));offset+=sizeof(pack->addr);
    memcpy(&pack->code,&buff[offset],sizeof(pack->code)); offset+=sizeof(pack->code);
    pack->data = &buff[offset];
    pack->crc8_transf = buff[size-1];
    pack->crc8_cal = my_crc8(buff,size-1,LoRa_CRC_INIT);
    pack->size = size - sizeof(pack->addr) - sizeof(pack->code) - sizeof(pack->crc8_transf);
  return size;
}

static int get_register_info(uint8_t *data, int len,register_info_t *reg_info)
{
    uint8_t *p = data;
    memcpy(&reg_info->protocol_ver,p,sizeof(reg_info->protocol_ver));p+=sizeof(reg_info->protocol_ver);
    memcpy(&reg_info->soft_ver,p,sizeof(reg_info->soft_ver));p+=sizeof(reg_info->soft_ver);
    memcpy(&reg_info->hardware_ver,p,sizeof(reg_info->hardware_ver));p+=sizeof(reg_info->hardware_ver);
    memcpy(&reg_info->sn,p,sizeof(reg_info->sn));p+=sizeof(reg_info->sn);
    memcpy(&reg_info->class,p,sizeof(reg_info->class));p+=sizeof(reg_info->class);
    return 0;
}


/*接收处理*/
static exp_lora_msg_t * msg_handle(exp_lora_msg_t *pram,lora_pkt_info_t *pkt_info) {
    exp_lora_msg_t * ret = NULL;
    register_info_t info;
        time_t now = time(NULL);
        node_status_t *node = dylora_status_serach_by_addr(&pram->addr);
        if(node)
        {
            node->rx++;
            node->last_rcv_time = time(NULL);
            if(pkt_info)node->pak_rssi = pkt_info->rssi;
        }

        if (IS_ACK_PACK(pram->code)) //如果是应答帧
        {
            switch (CODE_MASK(pram->code))
            {
            ///设备主动上报的功能码
            case 0x37:
            case 0x39:
                break;
            default:
                msg_add_tail(GENERAL_UPLINK_LIST,pram);
                break;
            }
        }
        else
        {
            if(pram->code != 0x39 && pram->code != 0x38 && pram->code != 0x37 )
            {
                msg_add_tail(GENERAL_UPLINK_LIST,pram);
            }
                switch (CODE_MASK(pram->code)) {
                case 0x38:
                    get_register_info(pram->data, pram->len,&info);
                    node_cfg_t * cfg = dylora_cfg_serach_by_reginfo(&info);
                    if(!cfg){
                        dy_syslog(LOG_INFO,"lora node [%X] not authority",info.sn);
                        break;
                    }
                    dy_syslog(LOG_INFO,"LoRa node 0x%08X register success", info.sn);
                    dylora_node_register(&info,sizeof(info),cfg->sn);
                    pram->addr.a = var.lora_cfg.gw_lora_addr;
                    pram->addr.b = cfg->term_addr[1];
                    pram->code = SET_ACK_PACK(pram->code);
                    memcpy(pram->data,&info.sn,4);
                    pram->len = 4;
                    ret = pram;
                    break;
                case 0x39:
                    if(dylora_cfg_search_by_addr(&pram->addr) == NULL)break;//设备不存在
                    pram->code = SET_ACK_PACK(pram->code);
                    pram->len = 0;
                    ret = pram;
                    break;
                case 0x40:
                    if(dylora_cfg_search_by_addr(&pram->addr) == NULL)break;//设备不存在
                    pram->code = SET_ACK_PACK(pram->code);
                    memcpy(pram->data, &now, sizeof(now));
                    pram->len = sizeof(now);
                    ret = pram;
                    break;
                case 0x44:
                    if(dylora_cfg_search_by_addr(&pram->addr) == NULL)break;//设备不存在
                    pram->code = SET_ACK_PACK(pram->code);
                    pram->len = 0;
                    ret = pram;
                    break;
                case 0x4D:
                    memcpy(pram->data, &now, sizeof(now));
                    pram->len = sizeof(now);
                    pram->code = SET_ACK_PACK(pram->code);
                    ret = pram;
                    break;
                case 0x37:
                case 0x73:
                case 0x50:
                case 0x3f: //DTU透传
                break;
                default:
                    break;
                }

        }
    return ret;
}


void heart_beat_pkt(exp_lora_msg_t *pram)
{
    uint32_t sn = strtoull(var.sn_str,NULL,16);
    memcpy(pram->data,&sn,4);
    pram->len = 4;
    pram->addr.a= var.lora_cfg.gw_lora_addr;
    pram->addr.b = 0xff;
    pram->code = 0xB7;
    pram->retry = 0;
}


//--------------------------------------------
//** main thread

//--------------------------------------------
void service_flag_set(bool enable)
{

}

static void *thread_launcher(void *opts)
{
    int i;
    static time_t last_beacon  =  0;
    exp_lora_msg_t pram={0};
    lora_pkt_info_t pkt_info;
    int rcv_len = 0;
    char rcv_buff[256];
    char send_buff[256];
    PackType pack;
    struct epoll_event events[MAXEPOLLSIZE];
    led_init();
    post_lora_led(LED_LIGHT_OFF);
    while (!exit_sig) {
        time_t now_time = time(NULL);
        /* 等待有事件发生 */
        LoRa_WaitRx();
        int nfds = epoll_wait(var.rfdev->efd, events, MAXEPOLLSIZE, LORA_WAIT_TIMEOUT);
        if (nfds == -1)  continue;
        else
        {
            /* 处理所有事件 */
            for (i = 0; i < nfds; ++i)
            {
                if ((events[i].data.fd == var.rfdev->iofd) && (digitalState(var.rfdev->iofd) == 1))/* read IO if RXDONE */
                {
                    LoRa_received();
                }
            }
        }
        int ret = LoRa_get_first(rcv_buff, &rcv_len, &pkt_info);
        if (ret > 0)
        {
            PackType pack;
            dy_syslog_hex(LOG_INFO, rcv_buff,rcv_len,"网关<-DyLoRa");
            Lora_Hex2Pack(&pack, rcv_buff, rcv_len);
            post_lora_led(LED_TWINKLE_ONCE);
            if(pack.crc8_transf != pack.crc8_cal)
            {

                dy_syslog(LOG_ERR,"user data crc error");
                continue;
            }
            memcpy(&pram.addr, &pack.addr, sizeof(pack.addr));
            pram.code = pack.code;
            pram.len = pack.size;
            memcpy(pram.data, pack.data, pram.len);
            if ((pram.addr.a == 255 && pram.addr.b == 1)
                    || (pram.addr.a == var.lora_cfg.gw_lora_addr))
            {
                PackType pack;
                exp_lora_msg_t *ack = msg_handle(&pram,&pkt_info);
                if(!ack)continue;
                Lora_FillPack(&pack, ack->addr, ack->code, ack->data, ack->len);
                int send_len = Lora_Pack2Hex(&pack, send_buff);
                dy_syslog_hex(LOG_INFO, send_buff,send_len,"网关->DyLoRa");
                LoRa_transfer(send_buff, send_len);
            }
        }
        else if(service_flag && (now_time > last_beacon + 4))
        {
            post_lora_led(LED_LIGHT_OFF);
            last_beacon = now_time;
            heart_beat_pkt(&pram);
            Lora_FillPack(&pack, pram.addr, pram.code, pram.data, pram.len);
            int send_len = Lora_Pack2Hex(&pack, send_buff);
            LoRa_transfer(send_buff, send_len);
            post_lora_led(LED_LIGHT_ON);
        }
        else if(list_size(GENERAL_DOWNLINK_LIST) > 0)
        {
            int ret = msg_get_first(GENERAL_DOWNLINK_LIST, &pram);
            if (!ret)
            {
                continue;
            }
            if(pram.addr.b != 0xFF)
            {
                node_status_t *status = dylora_status_serach_by_addr(&pram.addr);
                if (!status) {
                    dy_syslog(LOG_WARNING,"node addr [%d,%d] can't find", pram.addr.a,pram.addr.b);
                    continue;
                }
            }
            if(CODE_MASK(pram.code) == 0x50)memcpy(pram.data,&now_time,sizeof(now_time));//如果使唤醒命令当前时间必须在这里填充
            pram.addr.a = var.lora_cfg.gw_lora_addr;//compatible term_addr 2 bytes,now modify device config term_add is 1 bytes
            Lora_FillPack(&pack, pram.addr, pram.code, pram.data, pram.len);
            int send_len = Lora_Pack2Hex(&pack, send_buff);
            int i;
            if(pram.retry > 10)pram.retry = 1;
            for(i = 0;i < pram.retry;i++)
            {
                int index;
                post_lora_led(LED_LIGHT_OFF);
                dy_syslog_hex(LOG_INFO, send_buff,send_len,"网关->DyLoRa");
                LoRa_transfer(send_buff, send_len);//send
                post_lora_led(LED_LIGHT_ON);
                if(pram.addr.b == 0xFF)
                {
                    i = pram.retry;
                    break;
                }
                LoRa_WaitRx();
                uint64_t last_time = clock_get_ms();
                uint64_t time_ms = last_time;
                while((long)time_ms - (long)last_time <= LORA_SYNC_WAIT_TIMEOUT)
                {
                    time_ms = clock_get_ms();
                    int nfds = epoll_wait(var.rfdev->efd, events, MAXEPOLLSIZE, LORA_WAIT_TIMEOUT);
                    if (nfds > 0)
                    {
                        /* 处理所有事件 */
                        for (i = 0; i < nfds; ++i)
                        {
                            if ((events[i].data.fd == var.rfdev->iofd) && (digitalState(var.rfdev->iofd) == 1))/* read IO if RXDONE */
                            {
                                LoRa_received();
                            }
                        }
                    }
                    if(Lora_peek_and_compare(send_buff,2,&index))
                    {
                        int ret = LoRa_get_index(rcv_buff, &rcv_len,index, &pkt_info);
                        if (ret > 0)
                        {
                            PackType pack;
                            dy_syslog_hex(LOG_INFO, rcv_buff,rcv_len,"网关<-DyLoRa");
                            Lora_Hex2Pack(&pack, rcv_buff, rcv_len);
                            if(pack.crc8_transf != pack.crc8_cal)
                            {
                                dy_syslog(LOG_ERR,"user data crc error");
                                continue;
                            }
                            memcpy(&pram.addr, &pack.addr, sizeof(pack.addr));
                            pram.code = pack.code;
                            pram.len = pack.size;
                            memcpy(pram.data, pack.data, pram.len);
                            msg_handle(&pram,&pkt_info);
                        }
                        LoRa_clean(index);
                        break;
                    }
                }
            }
            if(i == pram.retry)
            {
                msg_add_tail(GENERAL_DOWNLINK_RESP_LIST,&pram);
            }
            continue;
        }
        else
        {

        }

    }

clean:
    post_lora_led(LED_LIGHT_OFF);
    dy_syslog(LOG_INFO, "INFO~ Exiting Lora service program\n");
    exit(EXIT_SUCCESS);
}

//--------------------------------------------
int thread_lora_start(void *opt)
{
    pthread_t thread;

    get_board_sn(var.sn_str);
    if((var.rfdev = LoRa_dev_init()) == NULL)
    {
        dy_syslog(LOG_ERR, "sx1276 drvier fault");
        dy_syslog(LOG_ERR, "lora service will be exit");
        exit(1);
    }
    if(opt)
    {
        lora_cfg_t *cfg = opt;
        LoRa_set_frq(cfg->frq_band,cfg->frq_code);//用配置文件中的通道
        var.lora_cfg.gw_lora_addr = cfg->gw_lora_addr;
    }
    if (load_nodes_cfg(&var.nodes_cfg_table, NODES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load nodes cfg fail");
    }

    thread_begin(thread_launcher, NULL, &thread);
    return 0;
}

//--------------------------------------------
void thread_lora_stop(void)
{
    exit_sig = true;
}

//--------------------------------------------
void service_lora_enable(bool enable)
{
    service_flag = enable;
}
