#include "lip.h"
#include <string.h>

/* счетчик, используемый при передачу */
static uint32_t f_snd_cntr = 0;
/* разрешение на передачу */
static int f_snd_en = 0;
/* информация UDP-уровня для передачи */
static t_lip_udp_info f_snd_udp_info;
/* буфер для сохранения адреса удаленного хоста */
static uint8_t f_host_addr[LIP_IP_ADDR_SIZE_MAX];



#ifdef LIP_DHCPC_CONFIGURED_CB
    /* Вызывается при успешном получении адреса по DHCP, если в
     * lip_conf.h определено LIP_DHCPC_CONFIGURED_CB */
    void lip_dhcpc_configured_cb(t_lip_dhcp_info *info) {

    }

#endif
#ifdef LIP_DHCPC_FAILED_CB
    /* Вызывается в случае, если получить адрес адрес по DHCP не удалось, если в
     * lip_conf.h определено LIP_DHCPC_FAILED_CB */
    void lip_dhcpc_failed_cb(void) {

    }
#endif

/* Обработка принятого UDP-пакета */
static t_lip_errs f_proc_recvd_udp(uint8_t *pkt, size_t size, const t_lip_udp_info *info) {

    if (!strncmp((char*)pkt, "start", size)) {
        /* копируем адрес удаленного хоста, т.к. info->src_addr действителен
         * только внутри данной функции */
        memcpy(f_host_addr, info->src_addr, LIP_IPV4_ADDR_SIZE);
        /* сохраняем параметры подключения удаленного хоста */
        f_snd_udp_info.ip_type  = info->ip_type;
        f_snd_udp_info.src_port = info->dst_port;
        f_snd_udp_info.dst_port = info->src_port;
        f_snd_udp_info.dst_addr = f_host_addr;

        /* разрешаем передачу */
        f_snd_cntr = 0;
        f_snd_en = 1;
    } else if (!strncmp((char*)pkt, "stop", size)) {
        f_snd_en = 0;
    }
    return LIP_ERR_SUCCESS;
}

void lip_sample_udp_cntr_init(const uint8_t* mac, const uint8_t* ip,
                       const uint8_t *mask, const uint8_t* gate,
                       uint16_t port) {
    /* инициализация стека */
    lip_init();

    /* MAC-адрес всегда устанавливается сразу после lip_init().
       Для изменения нужно вызвать lip_close(), lip_init() и снова
        lip_eth_set_mac_addr()*/
    lip_eth_set_mac_addr(mac);

    if (ip!=NULL) {
        /* Установка статических параметров IPv4. Можно изменять и во время
         * работы стека */
        lip_ipv4_set_addr(ip);
        lip_ipv4_set_mask(mask);
        lip_ipv4_set_gate(gate);
    } else {
        /* Разрешение динамического получения адреса по DHCP.
           Узнать установленный адрес можно с помощью lip_ipv4_cur_addr(),
           когда lip_state() станет e_LIP_STATE_CONFIGURED,
           либо определить callback-функцию на получение адреса */
        lip_dhcpc_enable(1);
    }

    /* Обнуляем информацию о удаленном хосте для передачи. Она будет
        проинициализирована при приходе пакета со строкой "start" от удаленного
        хоста */
    memset(&f_snd_udp_info, 0, sizeof(f_snd_udp_info));

    /* устанавливаем функцию, которая будет вызываться при приходе UDP пакета
       на заданный порт */
    lip_udp_port_listen(port, f_proc_recvd_udp);
}

void lip_sample_udp_cntr_pull(void) {
    /* продвижение стека */
    lip_pull();

    /* Если разрешена передача, то при наличии линка и свободного буфера на
       передачу, формируем пакет с счетчиком и отправляем */
    if (f_snd_en && (lip_state()==LIP_STATE_CONFIGURED) && lip_tx_buf_rdy()) {
        int max_size = 0;
        /* подготовка UDP пакета для передачи, получаем указатель на буфер для
           записи данных и макс. размер данных в max_size */
        uint32_t *put_buf = (uint32_t*)lip_udp_prepare(&f_snd_udp_info, &max_size);
        if (put_buf!=NULL) {
            int snd_size = 0;
            for (int i=0; i < max_size/4; i++) {
                put_buf[i] = f_snd_cntr++;
                snd_size+=4;
            }
            /* передача сформированного пакета */
            lip_udp_flush(snd_size);
        }
    }
}
