#include "uart.h"
#include<stdio.h>      /*标准输入输出定义*/
#include<stdlib.h>     /*标准函数库定义*/
#include<unistd.h>     /*Unix 标准函数定义*/
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>      /*文件控制定义*/
#include<termios.h>    /*PPSIX 终端控制定义*/
#include<errno.h>      /*错误号定义*/
#include<string.h>
#include<pthread.h>

static const char *optString = "m:d:p:i:h";

int mode = -1;
int interval = 0;

int format_hex(void *p, size_t l, char *hex_buff, int size)
{
    char symbol[5];
    char line_size = 16;
    char *ptr = p;
    int i, k;
    int n = 0;
    char *pad = "|            | ";

    memset(hex_buff, 0, sizeof(hex_buff));
    strncat(hex_buff, "\n", size);
    n++;
    for (i = 0; i < l; i += line_size)
    {
        strncat(hex_buff, "| ", size > n ? size - n : 0);
        n += 2;
        for (k = 0; k < line_size; k++)
        {
            if (i + k < l)
            {
                sprintf(symbol, "%02X ", (uint8_t)ptr[i + k]);
            }
            else
            {
                sprintf(symbol, "   ");
            }
            strncat(hex_buff, symbol, size > n ? size - n : 0);
            n += strlen(symbol);
        }
        strncat(hex_buff, pad, size > n ? size - n : 0);
        n += strlen(pad);

        for (k = 0; k < line_size; k++)
        {
            if (0x20 <= ptr[i + k] && ptr[i + k] <= 0x7E)
            {
                sprintf(symbol, "%c", (uint8_t)ptr[i + k]);
            }
            else
            {
                sprintf(symbol, ".");
            }
            strncat(hex_buff, symbol, size > n ? size - n : 0);
            n += strlen(symbol);
        }
        strncat(hex_buff, "|\n", size > n ? size - n : 0);
        n += 2;
        if (n >= size)
            break;
    }
}
#define SELECT_INIT()   \
    do                  \
    {                   \
        maxfd = 0;      \
        FD_ZERO(&rset); \
    } while (0)

#define SELECT_ADD_FD(fd)      \
    do                         \
    {                          \
        if (fd > 0)            \
        {                      \
            FD_SET(fd, &rset); \
            if (maxfd < fd)    \
                maxfd = fd;    \
        }                      \
    } while (0)

void *recv_loop(void *param)
{
    int fd = *((int*)param);
    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);
                while (1)
                {
                    ret = read(fd, rcv_buf + len, 1024 - len);
                    if (ret > 0)
                    {
                        len += ret;
                        count = 0;
                    }
                    else
                    {
                        count++;
                        if (count < 10)
                        {
                            usleep(20 * 1000);
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                format_hex(rcv_buf, len, print_buf, 2048);
                printf("Receive:%s", print_buf); 

                len = 0;
                if (interval == 0) break;
            }
        }
    }

    return NULL;
}

int main(int argc, char **argv)
{
    int fd = -1;           //文件描述符，先定义一个与程序无关的值，防止fd为任意值导致程序出bug
    int err;               //返回调用函数的状态
    int len = 0;
    int i;
    
    unsigned char send_buf[256];
    int opt;
    char dev[32];
    char tmp[256];
    pthread_t thread_rcv;

    opt = getopt(argc, argv, optString);
    while (opt != -1)
    {
        switch (opt)
        {
            case 'm':
                //printf("receive m with argument :%s\n", optarg);
                if (strcmp(optarg, "hex") == 0)
                {
                    mode = 1;
                }
                else if (strcmp(optarg, "string") == 0)
                {
                    mode = 0;
                }
                break;

            case 'd':
                //printf("receive d with argument :%s\n", optarg);
                strcpy(dev, optarg);
                break;

            case 'p':
                //printf("receive p with argument :%s\n", optarg);
                strcpy(tmp, optarg);
                break;

            case 'h':
                printf("Usage: help %s [options]\n", argv[0]);
                printf("\t -m\tmode,send hex data or string\n");
                printf("\t -d\tdevice to use(e.g. /dev/ttyS1)\n");
                printf("\t -p\tpacket data(e.g. 1234)\n");
                printf("\t -i\tinterval seconds(e.g. 1234)\n");
                return -1;
                break;
            
            case 'i':
                //printf("receive i with argument :%s\n", optarg);
                interval = atoi(optarg);
                break;

            default:
                printf("*** can't recognize input char!!! \n");
                return -1;
                break;
        }

        opt = getopt(argc, argv, optString);
    }

    if (mode == -1)
    {
        return -1;
    }


    fd = uart_init(dev, 115200, 1, 0, 8, 1);
    if (fd > 0)
    {
        sleep(1);
    }
    else
    {
        printf("dev:%s open failed\n", dev);
    }

    pthread_create(&thread_rcv, NULL, recv_loop, (void *)&fd);

    len = 0;
    if (mode == 1)
    {
        char *p = NULL;
        i = 0;
        while (i < strlen(tmp))
        {
            char c = 0;

            if (tmp[i] >= '0' && tmp[i] <= '9')
            {
                c = (tmp[i] - '0');
            }
            else if (tmp[i] >= 'A' && tmp[i] <= 'F')
            {
                c = (tmp[i] - 'A' + 10);
            }
            else if (tmp[i] >= 'a' && tmp[i] <= 'f')
            {
                c = (tmp[i] - 'a' + 10);
            }

            c = c << 4;

            i++;
            if (tmp[i] >= '0' && tmp[i] <= '9')
            {
                c += (tmp[i] - '0');
            }
            else if (tmp[i] >= 'A' && tmp[i] <= 'F')
            {
                c += (tmp[i] - 'A' + 10);
            }
            else if (tmp[i] >= 'a' && tmp[i] <= 'f')
            {
                c += (tmp[i] - 'a' + 10);
            }
            i++;

            send_buf[len] = c;
            len++;
        }
    }
    else
    {
        sprintf(send_buf, "%s", tmp);
        len = strlen(send_buf);
    }

    if (interval > 0)
    {
        while(1)
        {
            printf("send\n");
            len = write(fd, send_buf, len);
            if (len > 0)
            {
                //printf("send %d data successful\n", len);
            }
            else
            {
                printf("send data failed!\n");
            }
            sleep(interval);
        }
    }
    else
    {
        len = write(fd, send_buf, len);
        if (len > 0)
        {
            //printf("send %d data successful\n", len);
        }
        else
        {
            printf("send data failed!\n");
        }
    }


    pthread_join(thread_rcv, NULL);

    uart_uninit(fd);
}

