#include "lip_mac_rx.h"
#include "lip_mac_rx_cfg_defs.h"
#include "lip/ll/lip_ll.h"
#include "lip/ll/lip_ll_cfg_defs.h"
#include "lip/lip_private.h"
#include "lip/app/ptp/lip_ptp_cfg_defs.h"
#if LIP_SW_SUPPORT_KSZ8567
#include "lip/phy/ksz8567/lip_sw_ksz8567.h"
#endif
#if LIP_MAC_RX_QUEUE_ENABLE
#include "lip_mac_rx_queue.h"
#endif
#if LIP_VLAN_ENABLE
#include "lip/link/lip_vlan.h"
#include "lip/link/lip_vlan_cfg_defs.h"
#endif

#include <string.h>


static t_mac_rx_proc_frame_cb f_custom_rx_proc_cb;

void lip_max_rx_init(void) {
#if LIP_MAC_RX_QUEUE_ENABLE
    lip_max_rx_queue_reset();
#endif
}
void lip_max_rx_close(void) {
#if LIP_MAC_RX_QUEUE_ENABLE
    lip_max_rx_queue_reset();
#endif
}

void lip_mac_rx_set_custom_proc_frame_cb(t_mac_rx_proc_frame_cb cb) {
    f_custom_rx_proc_cb = cb;
}


/***************************************************************************//**
 *  Функция вызывается портом каждый раз, когда им был принят новый действительный
 *  кадр данных.
 *  Функция может вызываться из контекста прерывания.
 *  Функция помещает переданный пакет и информацию о нем в одну из очередей для
 *  приема, копируя в нее все данные кадра, т.е. по завершению выволнения буфер
 *  порта может использоваться для приема новых кадров.
 *
 *  Перед вызовом порт заполняет всю информацию о кадре, полученную от аппаратуры,
 *  в поля информации о принятом кадре типа #t_lip_rx_frame_info, а также
 *  передает данные кадра.
 *  Данные могут быть разбиты на две части, для обработки случая, когда на уровне
 *  порта используется кольцевой буфер и данные кадра разбиты концом буфера на две
 *  части (в конце буфере и в начале).
 *
 *  В случае отсутствия места в требуемой очереди, кадр будет отброшен
 *
 *  @param[in] ll_frame - указатель на структуру с информацией о принятом кадре и
 *                        его данных.
 ******************************************************************************/

#if !LIP_MAC_RX_QUEUE_ENABLE && LIP_LL_PORT_FEATURE_RX_SPLIT
LIP_MAC_RX_MERGED_PACKET_MEM(static uint8_t f_eth_rx_merged_packet[LIP_ETH_MAX_PACKET_SIZE]);
#endif

void lip_mac_rx_proc_frame(t_lip_rx_ll_frame *ll_frame) {
    t_lip_errs err = LIP_ERR_SUCCESS;
    if (f_custom_rx_proc_cb) {
        f_custom_rx_proc_cb(ll_frame);
    } else {
#if LIP_SW_SUPPORT_KSZ8567
        err = lip_sw_ksz8567_preproc_frame(ll_frame);
#endif
#if LIP_MAC_RX_FRAME_PREPROC_CB
        if (err == LIP_ERR_SUCCESS) {
            err = lip_mac_rx_frame_user_preproc(ll_frame);
        }
#endif
        if (err == LIP_ERR_SUCCESS) {
#if LIP_MAC_RX_QUEUE_ENABLE
            lip_mac_rx_queue_proc_frame(ll_frame);
#else
            t_lip_rx_frame rx_frame;
            rx_frame.info = ll_frame->info;
#if LIP_LL_PORT_FEATURE_RX_SPLIT
            if (ll_frame->pl_tail.size == 0) {
                rx_frame.pl = ll_frame->pl_main;
            } else {
                /* Если порт может передавать пакет как два буфера, то для простоты дальнейшей обработки,
                 * если пакет из двух частей, то копируем их в непрерывный буфер */
                memcpy(&f_eth_rx_merged_packet[0], ll_frame->pl_main.data, ll_frame->pl_main.size);
                memcpy(&f_eth_rx_merged_packet[ll_frame->pl_main.size], ll_frame->pl_tail.data, ll_frame->pl_tail.size);
                rx_frame.pl.data = f_eth_rx_merged_packet;
                rx_frame.pl.size = ll_frame->pl_main.size + ll_frame->pl_tail.size;
            }
#else
            rx_frame.pl = ll_frame->pl_main;
#endif
            lip_process_rx_frame(&rx_frame);
#endif
        }
    }
}

void lip_mac_rx_pull(void) {
#if LIP_MAC_RX_QUEUE_ENABLE
    t_lip_rx_frame *rx_frame = lip_mac_rx_queue_get_frame();
    if (rx_frame != NULL) {
        lip_process_rx_frame(rx_frame);
        /* освобождаем принятый буфер */
        lip_mac_rx_queue_get_frame_finish(rx_frame);
    }
#endif
}

