//******************************************** Включаемые файлы *********************************************

#include "tcp.h"
// #include "tcp_settings.h"
// #include "tcp_data.h"

//******************************************* Локальные константы *******************************************

//******************************************* Проверка параметров *******************************************

//******************************************** Определения типов ********************************************

//************************************ Глобальные (публичные) переменные ************************************

// Структура с параметрами модуля 
extern tcp_info_t tsp_dev_info;

//************************************* Локальные (приватные) переменные ************************************

static t_lsock_id data_socks[TCP_DATA_SOCK_CNT];

// static int n_cur_data_sock = LIP_TCP_INVALID_SOCKET_ID;


//**************************************** Объявления глобальных функций ************************************

// Инициализация модуля 
fun_res_t tcp_data_init(void);
// Деинициализация модуля 
void tcp_data_deinit(void);
// Периодический опрос сокетов данных
void tcp_data_loop(void);

// Создание и начало прослушивания сокета данных
// num - номер сокета (от 0 до TCP_DATA_SOCK_CNT - 1)
fun_res_t tcp_data_create_socket(u8 num);
// Закрытие и удаление сокета данных
fun_res_t tcp_data_delete_socket(u8 num);



//***********************************************************************************************************
//******************************** Определения локальных (приватных) функций ********************************
//***********************************************************************************************************


// Команда создания сокета данных
static tcp_resp_errs_t f_cmd_create_data_sock(u32 param, const u8* buf, u32 length)
{
    tcp_resp_errs_t err = TCP_ERR_OK;
    fun_res_t fun_res = ERR_OK;
    L_UNUSED(buf);
    L_UNUSED(length);

    fun_res = tcp_data_create_socket(param);
    
    if (fun_res != ERR_OK) 
    {
        err = TCP_ERR_INVALID_CMD_PARAMS;
    }

    return err;
}


// Команда закрытия сокета данных
static tcp_resp_errs_t f_cmd_delete_data_sock(u32 param, const u8* buf, u32 length)
{
    tcp_resp_errs_t err = TCP_ERR_OK;
    fun_res_t fun_res = ERR_OK;
    L_UNUSED(buf);
    L_UNUSED(length);

    fun_res = tcp_data_delete_socket(param);
    
    if (fun_res != ERR_OK) 
    {
        err = TCP_ERR_INVALID_CMD_PARAMS;
    }

    return err;
}


//***********************************************************************************************************
//******************************** Определения процедур обработки прерываний ********************************
//***********************************************************************************************************


//***********************************************************************************************************
//******************************* Определения глобальных (публичных) функций ********************************
//***********************************************************************************************************

fun_res_t tcp_data_init(void)
{
    fun_res_t err = ERR_OK;

    for (u8 i = 0; i < TCP_DATA_SOCK_CNT; i++) 
    {
        data_socks[i] = LIP_TCP_INVALID_SOCKET_ID;
    }

    // n_cur_data_sock = LIP_TCP_INVALID_SOCKET_ID;

    // Инициализация команд TCP для текущего модуля

    // Команда создания\закрытия сокета данных
    tcp_cmd_set_rx_callback(TCP_CMD_CREATE_DATA_SOCKET, f_cmd_create_data_sock);
    tcp_cmd_set_rx_callback(TCP_CMD_DELETE_DATA_SOCKET, f_cmd_delete_data_sock);


    return err;
}



void tcp_data_deinit(void)
{
    for (u8 i = 0; i < TCP_DATA_SOCK_CNT; i++) 
    {
        tcp_data_delete_socket(i);
    }
}



void tcp_data_loop(void)
{

#if 0
for (U8 i=0; i < TCP_DATA_SOCK_CNT; i++) 
    {
        int dstate = lsock_state(data_socks[i]);
        
        if (data_socks[i] == n_cur_data_sock) {
            if (dstate != LIP_TCP_SOCK_STATE_ESTABLISHED) {
                lprintf("[tcp_poll_data_soctets] data sock %d: closed, state = %d\n", i, dstate);
                lsock_close(data_socks[i], TCP_SOCKETS_CLOSE_TIMEOUT);
                                
                // f_rx_dd_size_done = 0;
                // stream_out_iface_closed(&f_out_iface);
                // stream_in_iface_closed(&f_in_iface);
                n_cur_data_sock = LIP_TCP_INVALID_SOCKET_ID;
            } 
            else {
                // ! запуск задачи на прием
                // t_lip_tcp_dd dd;
                // if (lsock_recv_cur_dd(n_cur_data_sock, &dd) == LIP_ERR_SUCCESS) {
                    // int32_t new_transfered = (dd.trans_cnt - f_rx_dd_size_done)/4;
                    // if (new_transfered > 0) {
                        // stream_out_recv_done((uint32_t*)&dd.buf[f_rx_dd_size_done],
                        //                       new_transfered);
                        // f_rx_dd_size_done += new_transfered * sizeof(out_buf[0]);
                    // }
                // }
            }
        } 
        else if (dstate == LIP_TCP_SOCK_STATE_ESTABLISHED) {
            /* если нет активного соединения по данным - используем новое */
            if (n_cur_data_sock == LIP_TCP_INVALID_SOCKET_ID) {
                lprintf("[tcp_poll_data_soctets] data sock %d: new active connection\n", i);
                n_cur_data_sock = data_socks[i];
                
                // f_rx_dd_size_done = 0;
            } else {
                /* иначе - закрываем его (больше одного быть не может) */
                lsock_close(data_socks[i], TCP_SOCKETS_CLOSE_TIMEOUT);
                n_cur_data_sock = LIP_TCP_INVALID_SOCKET_ID;
            }
        } 
        else if (dstate == LIP_TCP_SOCK_STATE_CLOSED) {
            lsock_listen(data_socks[i], tsp_dev_info.cur_settings.tcp_data_port);
            lprintf("[tcp_poll_data_soctets] data sock %d: restart listen\n", i);
        } 
        else if (dstate == LIP_TCP_SOCK_STATE_CLOSE_WAIT) {
            lsock_close(data_socks[i], TCP_SOCKETS_CLOSE_TIMEOUT);
            n_cur_data_sock = LIP_TCP_INVALID_SOCKET_ID;
            lprintf("[tcp_poll_data_soctets] data sock %d: closed\n", i);
        }

        //!   b_data_socket_established = false; 
              // b_data_socket_established = true;

    } // for


#endif
}



fun_res_t tcp_data_create_socket(u8 num)
{
    fun_res_t err = ERR_OK;
    int val = 1;

    err = L_ASSERT(num < TCP_DATA_SOCK_CNT);
    L_CHECK_ERR(err);
    err = L_ASSERT(data_socks[num] == LIP_TCP_INVALID_SOCKET_ID);
    L_CHECK_ERR(err);

    data_socks[num] = lsock_create();
    lsock_listen(data_socks[num], tsp_dev_info.cur_settings.tcp_data_port + num);
    lsock_set_opt(data_socks[num], SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val));
    lsock_set_opt(data_socks[num], IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));

    L_EXIT;
    return err;
}



fun_res_t tcp_data_delete_socket(u8 num)
{
    fun_res_t err = ERR_OK;
    
    err = L_ASSERT(num < TCP_DATA_SOCK_CNT);
    L_CHECK_ERR(err);
    err = L_ASSERT(data_socks[num] != LIP_TCP_INVALID_SOCKET_ID);
    L_CHECK_ERR(err);

    lsock_close(data_socks[num], TCP_SOCKETS_CLOSE_TIMEOUT);
    data_socks[num] = LIP_TCP_INVALID_SOCKET_ID;

    L_EXIT;
    return err;
}


//*********************************************** КОНЕЦ ФАЙЛА ***********************************************
