
#include "tcp.h"
// #include "tcp_settings.h"
// #include "ltimer.h"
#include "dbg_printf.h"
// #include "lta_private.h"

#include "flash_mem.h"
#include "fpga_cmn.h"
#include "lboot_port.h"

#include "tcp_protocol.h"

// // размер имени экземпляра сервиса dns-sd
// #define TCP_INSTANCE_NAME_SIZE          (64U)



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

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


// Заводской IP крейт-контроллера
#define TCP_STNGS_IP_CRAIT      (17U)

// Адрес по умолчанию
#define TCP_STNGS_IP_DEFAULT    (1U)



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

// Указатель на пользовательские настройки
extern fm_user_settings_data_t* fm_user_settings_data;
// Указатель на заводскую информацию
extern fm_factory_mem_data_t* fm_factory_mem_data;
// Указатель на калибровки
extern uint8_t* fm_cbr_data;

// Версия проекта FPGA
extern u32 fpga_prj_ver;
// Идентификатор установленной ПЛИС
extern u32 fpga_id;

// Информация об устройстве и прошивке	
extern t_lboot_devinfo lboot_dev_info;



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


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

// Резервные сетевые настройки
static const tcp_eth_stngs_t st_default_eth_stngs = 
{
    .flags         = FM_US_FLAGS_EMPTY,
    .mac           = {0x00, 0x05, 0xF7, 0xFF, 0xFF, 0xFA},
    .ipv4_addr     = {192,168,0,1},
    .ipv4_mask     = {255,255,255,0},
    .ipv4_gate     = {192,168,0,100},
    .tcp_cmd_port  = TCP_DEFAULT_CMD_PORT,
    .tcp_data_port = TCP_DEFAULT_DATA_PORT,
};


static const tcp_info_t st_default_dev_info = 
{
    .name          = "LTA\0",
    .serial_dev    = "0\0",
    .serial_crate  = "0\0",
    .brd_rev       = "0\0",
    .pos_num       = "200\0",
    .fpga_ver      = 0,
    .mcu_ver       = 0,
    .dev_flags     = 0,
    .cur_settings  = st_default_eth_stngs,
};

// Номер посадочного места в крейте
static u8 unit_slot_num = FPGA_UNIT_NUM_ERR;



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

// Чтение настроек модуля в глобальную структуру
void tcp_read_settings(void);



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

// Установить IP адрес равный номеру посадочного места в крейте
static void f_set_ip_addr_as_slot_num(void)
{
    uint8_t ipv4_addr[LTA_IPV4_ADDR_SIZE] = {192,168,0,1};

    switch(unit_slot_num)
    {
        case(0U):
            // Крейт-контроллер
            ipv4_addr[3] = TCP_STNGS_IP_CRAIT;
        break;

        case(1):
        case(2):
        case(3):
        case(4):
        case(5):
        case(6):
        case(7):
        case(8):
        case(9):
        case(10):
        case(11):
        case(12):
        case(13):
        case(14):
        case(15):
        case(16):
            // Модуль в крейте
            ipv4_addr[3] = unit_slot_num;
        break;

        case(FPGA_UNIT_NUM_ERR):
            // Ошибка получения адреса
            ipv4_addr[3] = TCP_STNGS_IP_DEFAULT;
        break;

        case(FPGA_UNIT_IS_SINGLE):
            // Модуль одиночный
            ipv4_addr[3] = TCP_STNGS_IP_DEFAULT;
        break;
    }

    memcpy(tsp_dev_info.cur_settings.ipv4_addr, ipv4_addr, LTA_IPV4_ADDR_SIZE);
    memcpy(tsp_dev_info.cur_settings.ipv4_mask, st_default_eth_stngs.ipv4_mask, LTA_IPV4_ADDR_SIZE);
    memcpy(tsp_dev_info.cur_settings.ipv4_gate, st_default_eth_stngs.ipv4_gate, LTA_IPV4_ADDR_SIZE);
}



// Установить MAC адрес (заводской или резервный)
static void f_set_mac_addr(void)
{
    bool factory_settings_init = (fm_factory_mem_data == NULL) ? (false) : (true);

    if (factory_settings_init == true)
    {
        memcpy(tsp_dev_info.cur_settings.mac, fm_factory_mem_data->mac, LTA_MAC_ADDR_SIZE);
    }
    else
    {
        memcpy(tsp_dev_info.cur_settings.mac, st_default_eth_stngs.mac, LTA_MAC_ADDR_SIZE);
    }
}



// Установить пользовательские сетевые настройки
static void f_set_user_settings(void)
{
    tsp_dev_info.cur_settings.flags = fm_user_settings_data->flags;

    // IP 
    // if (false != (fm_user_settings_data->flags & FM_US_FLAGS_USER_IP)) 
    if (fm_user_settings_data != NULL)
    {
        memcpy(tsp_dev_info.cur_settings.ipv4_addr, fm_user_settings_data->ipv4_addr, LTA_IPV4_ADDR_SIZE);
        memcpy(tsp_dev_info.cur_settings.ipv4_mask, fm_user_settings_data->ipv4_mask, LTA_IPV4_ADDR_SIZE);
        memcpy(tsp_dev_info.cur_settings.ipv4_gate, fm_user_settings_data->ipv4_gate, LTA_IPV4_ADDR_SIZE);
    } 
    else 
    {
        // Заводской
        f_set_ip_addr_as_slot_num();        
    }

    // Ports 
    // if (false != (fm_user_settings_data->flags & FM_US_FLAGS_USER_PORTS)) 
    if (fm_user_settings_data != NULL)
    {
        tsp_dev_info.cur_settings.tcp_cmd_port  = fm_user_settings_data->tcp_cmd_port;
        tsp_dev_info.cur_settings.tcp_data_port = fm_user_settings_data->tcp_data_port;
    } 
    else 
    {
        tsp_dev_info.cur_settings.tcp_cmd_port  = TCP_DEFAULT_CMD_PORT;
        tsp_dev_info.cur_settings.tcp_data_port = TCP_DEFAULT_DATA_PORT;
    }

    // MAC
    if (false != (fm_user_settings_data->flags & FM_US_FLAGS_USER_MAC)) 
    {
        memcpy(tsp_dev_info.cur_settings.mac, fm_user_settings_data->mac, LTA_MAC_ADDR_SIZE);
    } 
    else 
    {
        // Заводской или резервный
        f_set_mac_addr();
    }
}



// Установить заводские сетевые настройки
static void f_set_factory_settings(void)
{
    tsp_dev_info.cur_settings.flags = FM_US_FLAGS_EMPTY;
    
    // IP
    f_set_ip_addr_as_slot_num();

    // Ports 
    tsp_dev_info.cur_settings.tcp_cmd_port  = TCP_DEFAULT_CMD_PORT;
    tsp_dev_info.cur_settings.tcp_data_port = TCP_DEFAULT_DATA_PORT;

    // MAC - Заводской или резервный
    f_set_mac_addr();
}



// Установить резервные сетевые настройки
static void f_set_reserv_settings(void)
{
    // Flags
    // tsp_dev_info.cur_settings.flags = FM_US_FLAGS_EMPTY;
    
    // // IP
    // memcpy(tsp_dev_info.cur_settings.ipv4_addr, st_default_eth_stngs.ipv4_addr, LTA_IPV4_ADDR_SIZE);
    // memcpy(tsp_dev_info.cur_settings.ipv4_mask, st_default_eth_stngs.ipv4_mask, LTA_IPV4_ADDR_SIZE);
    // memcpy(tsp_dev_info.cur_settings.ipv4_gate, st_default_eth_stngs.ipv4_gate, LTA_IPV4_ADDR_SIZE);
    
    // // PORT
    // tsp_dev_info.cur_settings.tcp_cmd_port  = TCP_DEFAULT_CMD_PORT;
    // tsp_dev_info.cur_settings.tcp_data_port = TCP_DEFAULT_DATA_PORT;

    // // MAC
    // memcpy(tsp_dev_info.cur_settings.mac, st_default_eth_stngs.mac, LTA_MAC_ADDR_SIZE);


    memcpy(tsp_dev_info.name,           st_default_dev_info.name, sizeof(st_default_dev_info.name));
    memcpy(tsp_dev_info.serial_dev,     st_default_dev_info.serial_dev, sizeof(st_default_dev_info.serial_dev));
    memcpy(tsp_dev_info.serial_crate,   st_default_dev_info.serial_crate, sizeof(st_default_dev_info.serial_crate));
    memcpy(tsp_dev_info.brd_rev,        st_default_dev_info.brd_rev, sizeof(st_default_dev_info.brd_rev));
    memcpy(tsp_dev_info.pos_num,        st_default_dev_info.pos_num, sizeof(st_default_dev_info.pos_num));
    memcpy(&tsp_dev_info.fpga_ver,      &st_default_dev_info.fpga_ver, sizeof(st_default_dev_info.fpga_ver));
    memcpy(&tsp_dev_info.mcu_ver,       &st_default_dev_info.mcu_ver, sizeof(st_default_dev_info.mcu_ver));
    memcpy(&tsp_dev_info.dev_flags,     &st_default_dev_info.dev_flags, sizeof(st_default_dev_info.dev_flags));
    memcpy(&tsp_dev_info.cur_settings,  &st_default_dev_info.cur_settings, sizeof(st_default_dev_info.cur_settings));
}



// Получить номер посадочного места
static u8 f_get_slot_pos_num(void)
{
    u8 slot = FPGA_UNIT_NUM_ERR;
    bool fpga_init = fpga_is_init();

    if (fpga_init == true)
    {
        err_or_res_t res = fpga_get_slot_num();
        
        if (res >= ERR_OK)
        {
            slot = res;
        }
    }

    return slot;
}



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

void tcp_read_settings(void)
{
    bool user_settings_init    = (fm_user_settings_data == NULL) ? (false) : (true);
    bool factory_settings_init = (fm_factory_mem_data == NULL) ? (false) : (true);
    
    // Номер посадочного места в крейте
    unit_slot_num = f_get_slot_pos_num();

    // Сетевые настройкиа
    // Запись резервных настроек, а затем перезапись
    f_set_reserv_settings();

    if (user_settings_init == true)
    {
        f_set_user_settings();
    }
    else if (factory_settings_init == true)
    {
        f_set_factory_settings();
    }

    // Информация о модуле
    if (factory_settings_init == true)
    {
        memcpy(tsp_dev_info.name,       fm_factory_mem_data->name,    (LTA_DEVNAME_SIZE));
        memcpy(tsp_dev_info.serial_dev, fm_factory_mem_data->serial,  (LTA_SERIAL_SIZE));
        memcpy(tsp_dev_info.brd_rev,    fm_factory_mem_data->brd_rev, (LTA_REVISION_SIZE));
    }
    // Pos num
    snprintf(tsp_dev_info.pos_num, sizeof(tsp_dev_info.pos_num), "%d", unit_slot_num);

    // FPGA Version
    memcpy(&tsp_dev_info.fpga_ver,      &fpga_prj_ver, sizeof(tsp_dev_info.fpga_ver));

    // MCU Version
    uint32_t major = lboot_dev_info.soft_ver[0];
    uint32_t minor = lboot_dev_info.soft_ver[2];
    uint32_t patch = lboot_dev_info.soft_ver[4];
    tsp_dev_info.mcu_ver = ((major & 0xFF) << 24) |
                            ((minor & 0xFF) << 16) |
                            ((patch & 0xFF) << 8)  |
                            (0);
    
    // Dev flags
    uint32_t nDevFlagsCurrentFpga = 0U;
    if (fpga_id == FPGA_FPGA_ID_GOWIN)
    {
        nDevFlagsCurrentFpga = DEV_FLAGS_FPGA_GW1N9;
    }
    uint32_t nIsFactoryInfoEmpty = (factory_settings_init == true) ? (0) : (DEV_FLAGS_FACTORY_INFO_IS_EMPTY);
    uint32_t nIsNetInfoEmpty = (user_settings_init == true) ? (0) : (DEV_FLAGS_NET_INFO_IS_EMPTY);

    tsp_dev_info.dev_flags = (TCP_DEV_FLAGS_CURRENT_MCU) | 
                              (nDevFlagsCurrentFpga) |
                              (nIsFactoryInfoEmpty) |
                              (nIsNetInfoEmpty);
}



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


#if 0

        // Какой MAC использовать - заводской или из структуры сетевых настроек:
        // 1) заводского нет, флаг = -        -> сетевой (1е включение после прошивки)
        // 2) заводского нет, флаг = юзер_мак -> сетевой (есть сетевая настройка)
        // 3) заводской есть, флаг = -        -> заводской (была записана заводская информация)
        // 2) заводской есть, флаг = юзер_мак -> сетевой (есть сетевая настройка)
        if (TRUE == (TCP_stEthConfig.flags & ETH_FLAGS_USER_MAC))
        {
            // Используем MAC из структуры сетевых настроек
            memcpy(TCP_pCurrentMac, TCP_stEthConfig.mac, ETH_CFG_MAC_ADDR_SIZE);
        }
        else
        {
            if (TRUE == bFactoryMacValid)
            {
                // Используем MAC из структуры заводских настроек
                memcpy(TCP_pCurrentMac, FM_stFactInfo.mac, ETH_CFG_MAC_ADDR_SIZE);
            }
            else
            {
                // Используем MAC из структуры сетевых настроек (дефолтный mac)
                memcpy(TCP_pCurrentMac, TCP_stEthConfig.mac, ETH_CFG_MAC_ADDR_SIZE);
            }
        }


//! примечание - флаги включения айпи полезны если мы хотим сохранить настройки пользователя и 
//!              оперативно сброситься до заводских! Например, полезно при ремонте
/**
 * Функция обновляет структуру st_dev_info.cur_settings.
 * Варианты настроек по приоритету:
 * 1) Пользовательские настройки (должны быть установлены соответствующие флаги)
 * 2) Заводские настройки
 * 3) Заводские (резервные)
 * 
 */
static void tcp_update_net_settings(void)
{
    if (UNIT_INIT_DONE == US_GetStatus())
    {
        memcpy(&st_user_settings, &US_stSettings, sizeof(US_stSettings));

        st_dev_info.cur_settings.flags = US_stSettings.flags;
        
        // IP 
        if (true == (US_stSettings.flags & US_FLAGS_USER_IP)) {
            memcpy(st_dev_info.cur_settings.ipv4_addr, US_stSettings.ipv4_addr, LTA_IPV4_ADDR_SIZE);
            memcpy(st_dev_info.cur_settings.ipv4_mask, US_stSettings.ipv4_mask, LTA_IPV4_ADDR_SIZE);
            memcpy(st_dev_info.cur_settings.ipv4_gate, US_stSettings.ipv4_gate, LTA_IPV4_ADDR_SIZE);
        } else {
            memcpy(st_dev_info.cur_settings.ipv4_addr, FM_stFactoryMemData.ipv4_addr, LTA_IPV4_ADDR_SIZE);
            memcpy(st_dev_info.cur_settings.ipv4_mask, FM_stFactoryMemData.ipv4_mask, LTA_IPV4_ADDR_SIZE);
            memcpy(st_dev_info.cur_settings.ipv4_gate, FM_stFactoryMemData.ipv4_gate, LTA_IPV4_ADDR_SIZE);
        }

        // Ports 
        if (true == (US_stSettings.flags & US_FLAGS_USER_PORTS)) {
            st_dev_info.cur_settings.tcp_cmd_port  = US_stSettings.tcp_cmd_port;
            st_dev_info.cur_settings.tcp_data_port = US_stSettings.tcp_data_port;
        } else {
            st_dev_info.cur_settings.tcp_cmd_port  = FM_stFactoryMemData.tcp_cmd_port;
            st_dev_info.cur_settings.tcp_data_port = FM_stFactoryMemData.tcp_data_port;
        }

        // MAC
        if (true == (US_stSettings.flags & US_FLAGS_USER_MAC)) {
            memcpy(st_dev_info.cur_settings.mac, US_stSettings.mac, LTA_MAC_ADDR_SIZE);
        } else {
            memcpy(st_dev_info.cur_settings.mac, FM_stFactoryMemData.mac, LTA_MAC_ADDR_SIZE);
        }
    }
    else
    {
        memset(&st_user_settings, 0, sizeof(US_stSettings));

        st_dev_info.cur_settings.flags = US_FLAGS_EMPTY;
        memcpy(st_dev_info.cur_settings.mac,       FM_stFactoryMemData.mac, LTA_MAC_ADDR_SIZE);
        memcpy(st_dev_info.cur_settings.ipv4_addr, FM_stFactoryMemData.ipv4_addr, LTA_IPV4_ADDR_SIZE);
        memcpy(st_dev_info.cur_settings.ipv4_mask, FM_stFactoryMemData.ipv4_mask, LTA_IPV4_ADDR_SIZE);
        memcpy(st_dev_info.cur_settings.ipv4_gate, FM_stFactoryMemData.ipv4_gate, LTA_IPV4_ADDR_SIZE);
        st_dev_info.cur_settings.tcp_cmd_port  = FM_stFactoryMemData.tcp_cmd_port;
        st_dev_info.cur_settings.tcp_data_port = FM_stFactoryMemData.tcp_data_port;
    }
}


/**
 * Обновление внутренней структуры с параметрами модуля (tcp_lta_info_t)
 */
static void tcp_update_lta_info_struct(void)
{
    // name
    memcpy(st_dev_info.name, FM_stFactoryMemData.name, sizeof(FM_stFactoryMemData.name));

    // serial_dev
    memcpy(st_dev_info.serial_dev, FM_stFactoryMemData.serial, sizeof(FM_stFactoryMemData.serial));

    // serial_crate
    // todo - реализовать в ПЛИС
    // memcpy(st_dev_info.serial_dev, FM_stFactInfo.serial, sizeof(FM_stFactInfo.serial));

    // brd_rev
    memcpy(st_dev_info.brd_rev, FM_stFactoryMemData.brd_rev, sizeof(FM_stFactoryMemData.brd_rev));

    // pos_num
    U8 pos_num = FPGA_GetSlotNum();
    snprintf(st_dev_info.pos_num, sizeof(st_dev_info.pos_num), "%d", pos_num);

    // fpga_ver
    st_dev_info.fpga_ver = (uint16_t) FPGA_PrjVer;

    // mcu_ver
    uint32_t major = AU_stDevInfo.soft_ver[0];
    uint32_t minor = AU_stDevInfo.soft_ver[2];
    uint32_t patch = AU_stDevInfo.soft_ver[4];
    st_dev_info.mcu_ver = ((major & 0xFF) << 24) |
                            ((minor & 0xFF) << 16) |
                            ((patch & 0xFF) << 8)  |
                            (0);

    // dev_flags
    uint32_t nDevFlagsCurrentFpga = 0U;
    if (FPGA_FpgaID == FPGA_FPGA_ID_GOWIN)
    {
        nDevFlagsCurrentFpga = DEV_FLAGS_FPGA_GW1N9;
    }
    uint32_t nIsFactoryInfoEmpty = (FM_GetStatus() == UNIT_INIT_DONE) ? (0) : (DEV_FLAGS_FACTORY_INFO_IS_EMPTY);
    uint32_t nIsNetInfoEmpty = (US_GetStatus() == UNIT_INIT_DONE) ? (0) : (DEV_FLAGS_NET_INFO_IS_EMPTY);

    st_dev_info.dev_flags = (TCP_DEV_FLAGS_CURRENT_MCU) | 
                              (nDevFlagsCurrentFpga) |
                              (nIsFactoryInfoEmpty) |
                              (nIsNetInfoEmpty);
}


#endif