#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 <termios.h>

#include "zigbee_common.h"

static unsigned char CMD_ENT = 0; ///<写入命令（AT）等待返回的时间段置为1

static int zigbee_read_msg(int fd, char *rcv_buf, int max_len)
{
    int len = 0;
    int ret = 0;
    int count = 0;

    while (1)
    {
        ret = read(fd, rcv_buf + len, max_len - len);
        if (ret > 0)
        {
            len += ret;
            count = 0;
        }
        else
        {
            count++;
            if (count < 2)
            {
                usleep(10 * 1000);
            }
            else
            {
                break;
            }
        }
    }

    return len;
}

static int ViolentMatch(unsigned char *s, int sLen, unsigned char *p, int pLen)
{
    int i = 0;
    int j = 0;
    while (i < sLen && j < pLen)
    {
        if (s[i] == p[j])
        {
            //①如果当前字符匹配成功（即S[i] == P[j]），则i++，j++
            i++;
            j++;
        }
        else
        {
            //②如果失配（即S[i]! = P[j]），令i = i - (j - 1)，j = 0
            i = i - j + 1;
            j = 0;
        }
    }
    //匹配成功，返回模式串p在文本串s中的位置，否则返回-1
    if (j == pLen)
        return i - j;
    else
        return -1;
}

static int __set_zigbee_AT_enter(int fd)
{
    char send_buf[4] = "+++";
    int len = strlen(send_buf);
    char rcv_buf[64] = {0};
    int ret = 0;

    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set AT instruction enter  failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1 ||
                    ViolentMatch(rcv_buf, len, "+ERROR\r\n", strlen("+ERROR\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_AT_enter(int fd)
{
    char send_buf[4] = "+++";
    int len = strlen(send_buf);
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    CMD_ENT = 1;
    ret = __set_zigbee_AT_enter(fd);

    return ret;
}

static int __set_zigbee_AT_exit(int fd)
{
    char send_buf[8] = "AT+EXIT";
    int len = strlen(send_buf);
    char rcv_buf[64] = {0};
    int ret = 0;

    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set AT instruction enter  failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_AT_exit(int fd)
{
    char send_buf[8] = "AT+EXIT";
    int len = strlen(send_buf);
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;
    ret = __set_zigbee_AT_exit(fd);
    CMD_ENT = 0;

    return ret;
}


int set_zigbee_dev_type(int fd, dev_type_e type)
{
    char send_buf[32] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;
    switch (type)
    {
        case COORDINATOR:
            snprintf(send_buf, 32, "AT+DEV=C");
            break;
        case ROUTER:
            snprintf(send_buf, 32, "AT+DEV=R");
            break;
        case END_DEVICE:
            snprintf(send_buf, 32, "AT+DEV=E");
            break;
    }

    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set dev type failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_trans_mode(int fd, trans_mode_e mode)
{
    char send_buf[32] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;
    switch (mode)
    {
        case TRANSPARENT:
            snprintf(send_buf, 32, "AT+MODE=1");
            break;
        case SEMI_TRANSPARENT:
            snprintf(send_buf, 32, "AT+MODE=2");
            break;
        case PROTOCOL:
            snprintf(send_buf, 32, "AT+MODE=3");
            break;
    }

    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set transmit mode failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_PAN_ID(int fd, char *PAN)
{
    char send_buf[32] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 32, "AT+PANID=%s", PAN);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set PAN ID failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_key(int fd, char *key)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+KEY=%s", key);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set KEY failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_group_id(int fd, int group)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+GROUP=%d", group);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set group failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_channel(int fd, int ch)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+CH=%d", ch);

    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set channel failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_tx_power(int fd, int tx_power)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+TXPOWER=%d", tx_power);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len < 0)
    {
        dy_syslog(LOG_ERR, "set TX power failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_data_time(int fd, int data_time)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+DATA_TIME=%d", data_time);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set data time failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_rmode(int fd, int rmode)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+RMODE=%d", rmode);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "set rmode failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int set_zigbee_reset(int fd)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    int ret = 0;

    if (fd < 0) return -1;

    snprintf(send_buf, 64, "AT+RESET");
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len <= 0)
    {
        dy_syslog(LOG_ERR, "reset failed");
        ret = -1;
    }
    else
    {
        len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
        if (len > 0)
        {
            if (ViolentMatch(rcv_buf, len, "+OK\r\n", strlen("+OK\r\n")) != -1)
            {
                ret = 0;
            }
            else
            {
                ret = -1;
            }
        }
    }

    return ret;
}

int send_zigbee_data(zigbee_var_t *var, char *send_buf, int len, unsigned char *mac, int group_id, send_method_e method)
{
    int fd = var->zigbee_cfg.tty_fd;
    int ret = 0;
    int send_by_protcol = 0;

    dy_syslog_hex(LOG_DEBUG, send_buf, len, "ZIGBEE send data to mac %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", 
            mac[0], mac[1], mac[2], mac[3], 
            mac[4], mac[5], mac[6], mac[7]);

    switch (var->zigbee_cfg.mode)
    {
        case TRANSPARENT:
            // 透传模式直接将数据发送到空中
            switch (var->zigbee_cfg.type)
            {
                case COORDINATOR:
                // 通过广播将串口数据透传到网络中的非休眠设备。
                case ROUTER:
                case END_DEVICE:
                    // 通过点播将串口数据透传到协调器。
                    // 注意：终端在休眠模式下不能接收模式1的透传数据
                    len = UART0_Send(fd, send_buf, len);
                    if (len <= 0)
                    {
                        dy_syslog(LOG_ERR, "send failed");
                        ret = -1;
                    }
                    break;
            }
            break;
        case SEMI_TRANSPARENT:
            switch (var->zigbee_cfg.type)
            {
                case COORDINATOR:
                    // 模块按照数据传输的固定格式全协议传输。可进行点播，广播，组播通。
                    send_by_protcol = 1;
                    break;
                case ROUTER:
                case END_DEVICE:
                    // 该类型节点为透传模式，通过点播将串口数据透传到协调器。
                    len = UART0_Send(fd, send_buf, len);
                    if (len <= 0)
                    {
                        dy_syslog(LOG_ERR, "send failed");
                        ret = -1;
                    }
                    break;
                default:
                    break;
            }
            break;
        case PROTOCOL:
            send_by_protcol = 1;
            break;
        default:
            break;
    }

    if (send_by_protcol == 1)
    {
        // 按照协议格式发送数据
        char *buf = malloc(len + 6);
        if (buf != NULL)
        {
            int i = 0;
            unsigned short addr = 0;

            buf[i++] = 0xFC;
            switch (method)
            {
                case BROADCAST1:
                    // 该消息广播到全网络中所有设备
                    buf[i++] = len + 2; // len
                    buf[i++] = 1; // 指令
                    buf[i++] = 1; // type
                    memcpy(buf + i, send_buf, len);
                    i += len;
                    break;
                case BROADCAST2:
                    // 该消息广播到只对打开了接收（除休眠模式）的设备
                    buf[i++] = len + 2; //len
                    buf[i++] = 1; // 指令
                    buf[i++] = 2; // type
                    memcpy(buf + i, send_buf, len);
                    i += len;
                    break;
                case BROADCAST3:
                    // 该消息广播到所有全功能设备（路由器和协调器）
                    buf[i++] = len + 2; //len
                    buf[i++] = 1; // 指令
                    buf[i++] = 3; // type
                    memcpy(buf + i, send_buf, len);
                    i += len;
                    break;
                case MULTICAST:
                    // 在加入网络的情况下，用户可对全网非休眠设备进行组播。
                    buf[i++] = len + 2; //len
                    buf[i++] = 2; // 指令
                    buf[i++] = group_id; // group
                    memcpy(buf + i, send_buf, len);
                    i += len;
                    break;
                    break;
                case UNICAST_NO:
                    // 在加入网络的情况下，用户可以根据指令在以短地址方式单独与网络中的设备通信 透传方式——（无携带信息）
                    addr = get_short_addr_by_mac(fd, mac);
                    if (addr != 0)
                    {
                        buf[i++] = len + 4; //len
                        buf[i++] = 3; // 指令
                        buf[i++] = 1; // type
                        buf[i++] = ((addr >> 8) & 0xFF);
                        buf[i++] = (addr & 0xFF);
                        memcpy(buf + i, send_buf, len);
                    }
                    break;
                case UNICAST_SHORT:
                    // 短地址方式——（携带信息为短地址）
                    addr = get_short_addr_by_mac(fd, mac);
                    if (addr != 0)
                    {
                        buf[i++] = len + 4; //len
                        buf[i++] = 3; // 指令
                        buf[i++] = 2; // type
                        buf[i++] = ((addr >> 8) & 0xFF);
                        buf[i++] = (addr & 0xFF);
                        memcpy(buf + i, send_buf, len);
                    }
                    break;
                case UNICAST_MAC:
                    // MAC 地址方式——（携带信息为MAC 地址)
                    addr = get_short_addr_by_mac(fd, mac);
                    if (addr != 0)
                    {
                        buf[i++] = len + 4; //len
                        buf[i++] = 3; // 指令
                        buf[i++] = 3; // type
                        buf[i++] = ((addr >> 8) & 0xFF);
                        buf[i++] = (addr & 0xFF);
                        memcpy(buf + i, send_buf, len);
                    }
                    break;
                default:
                    break;
            }

            if (i > 3)
            {
                len = UART0_Send(fd, buf, i);
                if (len <= 0)
                {
                    dy_syslog(LOG_ERR, "send failed");
                    ret = -1;
                }
            }
        }
        else
        {
            dy_syslog(LOG_ERR, "malloc failed");
            ret = -1;
        }
    }

    return ret;
}

unsigned short get_short_addr_by_mac(int fd, unsigned char *mac)
{
    char send_buf[64] = {0};
    int len = 0;
    char rcv_buf[64] = {0};
    unsigned short addr = 0;

    if (mac == NULL)
    {
        return 0;
    }

    if (fd < 0)
    {
        printf("fd is invalid\n");
        return 0;
    }
    CMD_ENT = 1;
    __set_zigbee_AT_enter(fd);
    snprintf(send_buf, 64, "AT+GET_SHORT_ADDR=%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
             mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], mac[6], mac[7]);
    len = strlen(send_buf);
    tcflush(fd, TCIFLUSH);
    len = UART0_Send(fd, send_buf, len);
    if (len > 0)
    {
        int ret = 0;
        struct timeval timeout;
        int maxfd, i;
        fd_set rset;
        int count = 0;

        while (1)
        {
            len = UART0_Recv(fd, rcv_buf, sizeof(rcv_buf));
            if (len > 0)
            {
                char short_addr_str[8] = {0};

                #if 1
                dy_syslog_hex(LOG_DEBUG, rcv_buf, len, "get MAC rcv");
                #endif

                int index = ViolentMatch(rcv_buf, len, "GET_SHORT_ADDR=", strlen("GET_SHORT_ADDR="));
                if (index >= 0)
                {
                    sscanf(rcv_buf + index, "GET_SHORT_ADDR=%s", short_addr_str);
                    addr = strtoul(short_addr_str, NULL, 16);
                    break;
                }
                else
                {
                    count++;
                    if (count > 3)
                        break;
                }
            }
            else
            {
                count++;
                if (count > 3)
                    break;
            }
        }
    }
    
    if (addr == 0)
    {
        dy_syslog(LOG_ERR, "get short addr failed");
    }

    __set_zigbee_AT_exit(fd);
    CMD_ENT = 0;
    return addr;
}


/* data fromat: |-----------data-----------|----mac(8 bytes)----|----short addr(2 bytes)----|------RSSI----|
 * | 49 61 6D 45 74 72 B2 1F 00 4B 12 00 D2 E9 E6    |            | IamEtr...K......|
 * MAC is 74 72 B2 1F 00 4B 12 00
 * Short addr is D2 E9
 * RSSI is E6
 * */
int handle_zigbee_msg(zigbee_var_t *var, char *buf, int len)
{
    dy_syslog_hex(LOG_DEBUG, buf, len, "%s:%d", __FUNCTION__, __LINE__);
    #if 0
    {
        unsigned char print_buf[2048];
        format_hex(buf, len, print_buf, 2048);
        printf("=========%s:%d rcv:%s", __FUNCTION__, __LINE__, print_buf);
    }
    #endif
}

void *recv_loop(void *param)
{
    zigbee_var_t *var = (zigbee_var_t *)param;
    int fd = var->zigbee_cfg.tty_fd;
    int ret = -1, maxfd, i;
    fd_set rset;
    struct timeval timeout;
    unsigned char rcv_buf[1024];
    unsigned char print_buf[2048];
    int len = 0;
    int count = 0;

    while (1)
    {
        SELECT_INIT();
        SELECT_ADD_FD(fd);

        timeout.tv_usec = 0;
        timeout.tv_sec = 10;

        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            break;
        }
        else if (ret > 0)
        {
            if (fd > 0 && FD_ISSET(fd, &rset))
            {
                FD_CLR(fd, &rset);
                if (CMD_ENT == 0)
                {
                    len = zigbee_read_msg(fd, rcv_buf, 1024);
                    handle_zigbee_msg(var, rcv_buf, len);
                }
            }
        }
    }

    return NULL;
}


