#include "myBase.h"
#include "myLog.h"
#include "myComm.h"
#include "unistd.h"

enum{
    FTU,
    RK,
    END
};

LOCAL stru_uart_para g_uart_para[END] = 
{
    [FTU] = {
        .device = "/dev/ttyUSB0",
        .baudrate = 115200,
        .data_bits = 8,
        .stop_bits = 1,
        .parity = 'N',
    },
    [RK] = {
        .device = "/dev/ttyUSB1",
        .baudrate = 115200,
        .data_bits = 8,
        .stop_bits = 1,
        .parity = 'N',
    },
};

LOCAL struct 
{
    CommType type;
    CommDebugShow debug_show;
    void *para;
    int id;
    int socket_fd;
    pthread_t thread_id;
    void* (*start_cb)(void *arg);
}g_channel_para[END] = 
{
    [FTU] = {
        .type = CommType::uart,
        .debug_show = CommDebugShow::off,
        .para = &g_uart_para[FTU],
        .id = -1,
        .socket_fd = -1,
    },
    [RK] = {
        .type = CommType::uart,
        .debug_show = CommDebugShow::off,
        .para = &g_uart_para[RK],
        .id = -1,
        .socket_fd = -1,
    },
};

LOCAL void recv_callback(int id, int socket_fd, const uint8_t *p_rx, uint16_t rx_len)
{
    int send_id = -1;
    int send_socket_fd = -1;

    if(id == g_channel_para[FTU].id)
    {
        send_id = g_channel_para[RK].id;
        send_socket_fd = g_channel_para[RK].socket_fd;
    }
    else if(id == g_channel_para[RK].id)
    {
        send_id = g_channel_para[FTU].id;
        send_socket_fd = g_channel_para[FTU].socket_fd;
    }
    else
    {
        MY_LOG_E("recv_callback: unknown id %d", id);
        return;
    }


    comm_send(send_id, send_socket_fd, p_rx, rx_len);
}

LOCAL void state_callback(int id, int socket_fd, CommState state)
{
    // printf("state_callback: id %d, socket_fd %d, state %d", id, socket_fd, state);

    for(int i = 0; i < END; i++)
    {
        if(g_channel_para[i].id == id)
        {
            if(state == CommState::connected)
            {
                g_channel_para[i].socket_fd = socket_fd;
            }
            else
            {
                g_channel_para[i].socket_fd = -1;
            }
        }
    }
}


LOCAL int com_channel_create()
{
    for(int i = 0; i < END; i++)
    {
        if((g_channel_para[i].id = comm_create(g_channel_para[i].type, g_channel_para[i].debug_show, g_channel_para[i].para)) < 0)
        {
            MY_LOG_E("create channel %d failed", i);
            return -1;
        }
    
        if(0 != comm_recv_register(g_channel_para[i].id, recv_callback))
        {
            MY_LOG_E("register recv callback for channel %d failed", i);
            return -1;
        }

        if(0 != comm_state_register(g_channel_para[i].id, state_callback))
        {
            MY_LOG_E("register state callback for channel %d failed", i);
            return -1;
        }
    }

    return 0;
}

LOCAL void *com_start(void *arg)
{
    if(NULL == arg)
    {
        MY_LOG_E("arg is NULL");
        return NULL;
    }

    int id = *(int *)arg;

    if(0 != comm_connect(id))
    {
        MY_LOG_E("comm_connect failed, channel id %d", id);
        return NULL;
    }

    return NULL;
}

LOCAL void com_channel_start()
{
    for(int i = 0; i < END; i++)
    {
        if(g_channel_para[i].id >= 0)
        {
            if(0 != pthread_create(&g_channel_para[i].thread_id, NULL, com_start, &g_channel_para[i].id))
            {
                MY_LOG_E("pthread_create failed, channel id %d", i);
                return;
            }
        }
    }
}


int main()
{
    if(0 != com_channel_create())
    {
        MY_LOG_E("create channel failed");
        return -1;
    }
    
    com_channel_start();

    while(1)
    {
        usleep(1000000);
    }

    return 0;
}