#include "lip_ptp_cfg_defs.h"
#if LIP_PTP_ENABLE
#include "lip_ptp.h"
#include "lip_ptp_internal.h"
#include "lip/link/lip_port_link_private.h"
#include "lip/app/ptp/nbrate/lip_ptp_nb_rate_ratio.h"
#include "lip/app/ptp/bmca/lip_ptp_port_announce.h"
#include "lip/app/ptp/bmca/lip_ptp_bmca_state_sel.h"
#include "lip/app/ptp/gptpcap/lip_ptp_port_gptp_cap.h"
#include "lip/app/ptp/sync/lip_ptp_port_sync.h"
#include "lip/app/ptp/sync/lip_ptp_site_sync.h"
#include "lip/app/ptp/sync/lip_ptp_local_clk_sync.h"
#include "lip/app/ptp/master/lip_ptp_master_sync.h"
#include "lip/app/ptp/md/eth/pdelay/lip_ptp_pdelay_req.h"
#include "lip/app/ptp/md/eth/pdelay/lip_ptp_pdelay_resp.h"
#include "lip/app/ptp/md/eth/sync/lip_ptp_md_eth_sync_recv.h"
#include "lip/app/ptp/md/eth/sync/lip_ptp_md_eth_sync_send.h"
#include "lip/app/ptp/misc/lip_ptp_tstmp_ops.h"
#include "lip_ptp_proto_defs.h"
#include "lip/link/lip_eth_private.h"
#include "lip/link/lip_eth.h"
#include "lip/link/lip_port_link.h"
#include "ltimer.h"
#include <string.h>
#if LIP_SW_SUPPORT_KSZ8567
#include "lip/phy/ksz8567/lip_sw_ksz8567.h"
#endif




#if (LIP_PTP_RX_QUEUE_NUM < 0) || (LIP_PTP_RX_QUEUE_NUM >= LIP_CFG_MAC_RX_QUEUE_CNT)
    #error invalid rx PTP queue number
#endif






const t_lip_mac_addr lip_ptp_eth_glob_mcast_addr = {0x01, 0x1B, 0x19, 0x00, 0x00, 0x00};
const t_lip_mac_addr lip_ptp_eth_link_mcast_addr = {0x01, 0x80, 0xC2, 0x00, 0x00, 0x0E};



t_lip_ptp_inst_ctx g_lip_ptp_inst_ctx;


/* Заполнение дополнительных двух байт ClockId в соответствии с заданным пользователем параметром */
static void f_fill_clock_id_suffix(t_lip_ptp_inst_ctx *inst) {
    uint8_t *clk_id_raw = &inst->sys_id.clockIdentity[0];
    clk_id_raw[6] = (inst->cfg.clkid_suffix >> 8) & 0xFF;
    clk_id_raw[7] = inst->cfg.clkid_suffix & 0xFF;
}

/* заполнение clockIdentity по MAC-адресу (IEE 1588-2019 7.5.2.2.2.2 Construction based on an NUI-48) */
static void f_fill_clock_id_by_mac(t_lip_ptp_inst_ctx *inst, const t_lip_mac_addr mac_addr) {
    /* первые 6 байт = mac, 2 байта - произвольные */
    uint8_t *clk_id_raw = &inst->sys_id.clockIdentity[0];
    clk_id_raw[0] = mac_addr[0];
    clk_id_raw[1] = mac_addr[1];
    clk_id_raw[2] = mac_addr[2];
    clk_id_raw[3] = mac_addr[3];
    clk_id_raw[4] = mac_addr[4];
    clk_id_raw[5] = mac_addr[5];
    f_fill_clock_id_suffix(inst);
}

static LINLINE uint8_t lip_ptp_msgfld_type(t_lip_ptp_msg_type type, uint8_t sdo_id_mj) {
    return LBITFIELD_SET(LIP_PTP_MSGFLD_TYPESDOID_MSGTYPE, type)
           | LBITFIELD_SET(LIP_PTP_MSGFLD_TYPESDOID_SDOID_MJ, sdo_id_mj);
}

static LINLINE uint8_t lip_ptp_msgfld_ver(void) {
    return LBITFIELD_SET(LIP_PTP_MSGFLD_VER_PTPVER_MJ, LIP_PTP_PROTO_VER_MJ)
           | LBITFIELD_SET(LIP_PTP_MSGFLD_VER_PTPVER_MN, LIP_PTP_PROTO_VER_MN);
}

void lip_ptp_set_log_interval_tmr(t_ltimer *tmr, int8_t logInterval, int cnt) {
    unsigned ms;
    if (logInterval >= 0) {
        ms = 1000 * (1 << logInterval);
    } else {
        ms = 1000 / (1 << -logInterval);
    }
    ltimer_set_ms(tmr, ms * cnt);
}

static t_lip_ptp_port_ctx *f_get_port_idx_ctx(uint8_t port_idx) {
    t_lip_ptp_port_ctx *p = &g_lip_ptp_inst_ctx.ports[port_idx];
    return  lip_ptp_port_is_en(p) ? p : NULL;
}

static void f_ptp_proc_egress_tstmp(t_lip_ptp_port_ctx *p, uint8_t msgtype, t_lip_ptp_tstmp *tstmp) {
    if (p && lip_ptp_port_is_en(p)) {
        lip_ptp_tstmp_add_ns(tstmp, p->egress_latency);

        if (msgtype == LIP_PTP_MSGTYPE_PDELAY_REQ) {
            lip_ptp_pdelay_req_etstmp(p, tstmp);
        } else if (msgtype == LIP_PTP_MSGTYPE_PDELAY_RESP) {
            lip_ptp_pdelay_resp_etstmp(p, tstmp);
        } else if (msgtype == LIP_PTP_MSGTYPE_SYNC) {
            lip_ptp_md_eth_send_sync_etstmp(p, tstmp);
        }
    }
}




void lip_ptp_proc_egress_tstmp(uint8_t port_idx, uint8_t msgtype, t_lip_ptp_tstmp *tstmp) {
    t_lip_ptp_port_ctx *p = f_get_port_idx_ctx(port_idx);
    f_ptp_proc_egress_tstmp(p, msgtype, tstmp);
}

t_lip_tx_frame *lip_ptp_prepare_frame(t_lip_ptp_port_ctx *p, t_lip_ptp_msg_type msgtype, uint16_t msglen, uint16_t flags) {
    t_lip_tx_frame_info finfo;
    finfo.flags = LIP_FRAME_TXINFO_FLAG_PORTS_FWD |
                  LIP_FRAME_TXINFO_FLAG_PORTS_BLK_OVD |
                  (LIP_PTP_MSGTYPE_IS_EVENT(msgtype) ? LIP_FRAME_TXINFO_FLAG_TSTAMP_REQ : 0);
#if LIP_MULTIPORT_ENABLE
    finfo.port_mask = p->port_mask;
#endif
    finfo.ptp_msg_type = msgtype;
    finfo.priority = LIP_PTP_MSGTYPE_IS_EVENT(msgtype) ? LIP_PTP_EVENT_PKT_PRIO : LIP_PTP_GENERAL_PKT_PRIO;
    t_lip_tx_frame *frame = lip_eth_frame_prepare(&finfo, LIP_ETHTYPE_PTP, lip_ptp_eth_link_mcast_addr);
    if (frame) {
        t_lip_ptp_msg_hdr *ptp_hdr = (t_lip_ptp_msg_hdr *)frame->buf.cur_ptr;
        memset(ptp_hdr, 0, msglen);

        ptp_hdr->msgType_mjSdoId = lip_ptp_msgfld_type(msgtype, flags & LIP_PTP_MSG_PREP_FLAG_CMLDS ? LIP_PTP_SDOID_MJ_CMLDS :  LIP_PTP_SDOID_MJ_GPTP);
        ptp_hdr->ptpVer = lip_ptp_msgfld_ver();
        ptp_hdr->domainNum = LIP_PTP_DOMAIN_NUM;
        memcpy(ptp_hdr->srcPortIdentity.clockIdentity, g_lip_ptp_inst_ctx.sys_id.clockIdentity, LIP_PTP_CLOCK_IDENTITY_SIZE);
        ptp_hdr->srcPortIdentity.portNum = p->pkt_port_num_be;
    }
    return frame;
}

void lip_ptp_frame_flush(t_lip_tx_frame *frame, uint16_t msglen) {
    t_lip_ptp_msg_hdr *ptp_hdr = (t_lip_ptp_msg_hdr *)frame->buf.cur_ptr;
    ptp_hdr->msgLen = HTON16(msglen);
    frame->buf.cur_ptr += msglen;
    lip_eth_frame_flush(frame);
}

void lip_ptp_mac_addr_update(const uint8_t *mac) {
    f_fill_clock_id_by_mac(&g_lip_ptp_inst_ctx, mac);
    lip_ptp_bmca_state_sel_system_clkid_update(&g_lip_ptp_inst_ctx);
}


bool lip_ptp_check_clock_identity(const t_lip_ptp_clock_identity *ci) {
    return memcmp(ci, g_lip_ptp_inst_ctx.sys_id.clockIdentity, LIP_PTP_CLOCK_IDENTITY_SIZE) == 0;
}

bool lip_ptp_check_port_identity(const t_lip_ptp_port_ctx *p, const void *msg_pi) {
    const t_lip_ptp_port_identity *pi = (const t_lip_ptp_port_identity *)msg_pi;
    return lip_ptp_check_clock_identity(&pi->clockIdentity) && (p->pkt_port_num_be == pi->portNum);
}




void lip_ptp_init(void) {
    g_lip_ptp_inst_ctx.sys_id.priority1 = LIP_PTP_SYSTEM_PRIO1_DEFAULT;
    g_lip_ptp_inst_ctx.sys_id.clockClass = LIP_PTP_SYSTEM_CLOCK_CLASS_DEFAULT;
    g_lip_ptp_inst_ctx.sys_id.clockAccuracy = LIP_PTP_SYSTEM_CLOCK_ACCUR_UNKNOWN;
    g_lip_ptp_inst_ctx.sys_id.offsetScaledLogVariance = HTON16(LIP_PTP_SYSTEM_OFFS_LOGVAR_UNKNOWN);
    g_lip_ptp_inst_ctx.sys_id.priority2 = LIP_PTP_SYSTEM_PRIO2_END_INST_DEFAULT;
    g_lip_ptp_inst_ctx.sys_time_info.timeSource = LIP_PTP_TIME_SRC_INTERNAL_OSC;
    g_lip_ptp_inst_ctx.sys_time_info.currentUtcOffset = 0; /** @todo - проверить, если время не PTP, то должен быть 0 и флаг valid = 0? */
    g_lip_ptp_inst_ctx.sys_time_info.flags1 = 0;
    g_lip_ptp_inst_ctx.cfg.clkid_suffix = LIP_PTP_CLOCKID_DEFAULT_SUFFIX;

    for (int port_idx = 0; port_idx < LIP_PORT_MAX_CNT; ++port_idx) {
        t_lip_ptp_port_ctx *p = &g_lip_ptp_inst_ctx.ports[port_idx];
        memset(p, 0, sizeof(t_lip_ptp_port_ctx));
        p->port_mask = 1 << port_idx;
        p->port_idx = port_idx;
    }

    lip_ptp_bmca_state_sel_init(&g_lip_ptp_inst_ctx);
    lip_ptp_site_sync_init(&g_lip_ptp_inst_ctx);
    lip_ptp_local_clk_sync_init(&g_lip_ptp_inst_ctx);
    lip_ptp_master_sync_init(&g_lip_ptp_inst_ctx);

    /** @todo перенести в разрешение порта для случая, когда порты по разным mac */
    lip_ll_join(lip_ptp_eth_link_mcast_addr);
}

void lip_ptp_close(void) {
    /** @todo перенести в запрет порта для случая, когда порты по разным mac */
    lip_ll_leave(lip_ptp_eth_link_mcast_addr);
    for (int port_idx = 0; port_idx < LIP_PORT_MAX_CNT; ++port_idx) {
        lip_ptp_port_disable(port_idx);
    }

}

static void f_ptp_port_init(t_lip_ptp_port_ctx *p) {
    lip_ptp_port_announce_init(p);
    lip_ptp_port_gptp_cap_init(p);
    lip_ptp_nb_rate_ratio_init(p);
    lip_ptp_pdelay_req_init(p);
    lip_ptp_pdelay_resp_init(p);
    lip_ptp_md_eth_sync_recv_init(p);
    lip_ptp_md_eth_sync_send_init(p);

}

void lip_ptp_port_link_changed(uint8_t port_idx, bool on) {
    t_lip_ptp_port_ctx *p = f_get_port_idx_ctx(port_idx);
    if (p) {
        if (on) {
            lip_printf(LIP_LOG_MODULE_PTP, LIP_LOG_LVL_PROGRESS, 0, "lip ptp: reconnect port %d\n", LIP_PTP_PRINT_PORT_NUM(p));
            f_ptp_port_init(p);
        } else {
            lip_printf(LIP_LOG_MODULE_PTP, LIP_LOG_LVL_PROGRESS, 0, "lip ptp: disconnect port %d\n", LIP_PTP_PRINT_PORT_NUM(p));
            p->stats.state = LIP_PTP_PORT_STATE_INIT;
            lip_ptp_port_announce_down(p);
            lip_ptp_port_gptp_cap_down(p);
            lip_ptp_pdelay_req_down(p);
            lip_ptp_bmca_state_sel_update_req(&g_lip_ptp_inst_ctx);
        }
    }
}

void lip_ptp_pull(void) {    
    for (int port_idx = 0; port_idx < LIP_PORT_MAX_CNT; ++port_idx) {
        t_lip_ptp_port_ctx *p = &g_lip_ptp_inst_ctx.ports[port_idx];
        if (lip_port_link_is_up(port_idx) && lip_ptp_port_is_en(p)) {
            lip_ptp_port_gptp_cap_pull(p);
            lip_ptp_port_announce_pull(p);
            lip_ptp_pdelay_req_pull(p);
            lip_ptp_md_eth_sync_recv_pull(p);
        }
    }
    lip_ptp_bmca_state_sel_pull(&g_lip_ptp_inst_ctx);
    lip_ptp_site_sync_pull(&g_lip_ptp_inst_ctx);
    lip_ptp_master_sync_pull(&g_lip_ptp_inst_ctx);
}

/** @todo - перенести на упровень link определение port_idx по rx_port от свича */
static int f_get_port_idx(const t_lip_rx_frame_info *frame_info) {
#if LIP_MULTIPORT_ENABLE
    return frame_info->rx_port;
#else
    return 0;
#endif
}

t_lip_errs lip_ptp_process_packet(t_lip_payload *pl, const t_lip_eth_rx_packet *eth_packet) {    
    t_lip_errs err = LIP_ERR_SUCCESS;

    t_lip_ptp_port_ctx *p = f_get_port_idx_ctx(f_get_port_idx(&eth_packet->ll_frame->info));
    if (!p) {
        err = LIP_ERR_PTP_INVALID_PORT;
    } else if (pl->size < sizeof(t_lip_ptp_msg_hdr)) {
        err = LIP_ERR_PTP_INVALID_RX_SIZE;
    } else {
        t_lip_ptp_msg_hdr *hdr = (t_lip_ptp_msg_hdr *)pl->data;
        const uint8_t ptp_ver_mj = LBITFIELD_GET(hdr->ptpVer, LIP_PTP_MSGFLD_VER_PTPVER_MJ);
        if (ptp_ver_mj != LIP_PTP_PROTO_VER_MJ) {
            err = LIP_ERR_PTP_UNSUP_PTP_VER;
        } else if (hdr->domainNum != LIP_PTP_DOMAIN_NUM) {
            err = LIP_ERR_PTP_UNSUP_DOMAIN_NUM;
        } else {
            uint16_t ptp_size = NTOH16(hdr->msgLen);
            if (pl->size < ptp_size) {
                err = LIP_ERR_PTP_INVALID_RX_SIZE;
            } else {
                /* проверка, не приняли ли мы пакет сами от себя */
                if (lip_ptp_check_clock_identity(&hdr->srcPortIdentity.clockIdentity)) {
                    /* если включено определение петли, то делаем соответствующую индикацию */
#if LIP_PORT_SELFLOOP_DETECTION
                    lip_port_set_selfloop_detected(p->port_idx);
#endif
                } else {
                    t_lip_ptp_rx_frame ptp_frame;
                    ptp_frame.msg_type  = LBITFIELD_GET(hdr->msgType_mjSdoId, LIP_PTP_MSGFLD_TYPESDOID_MSGTYPE);
                    ptp_frame.sdo_id_mj = LBITFIELD_GET(hdr->msgType_mjSdoId, LIP_PTP_MSGFLD_TYPESDOID_SDOID_MJ);
                    ptp_frame.ll_frame = eth_packet->ll_frame;
                    if (ptp_frame.ll_frame->info.flags & LIP_FRAME_RXINFO_FLAG_TSTAMP_VALID) {
                        ptp_frame.tstmp_valid = true;
                        ptp_frame.tstmp = ptp_frame.ll_frame->info.tstmp;
                        lip_ptp_tstmp_add_ns(&ptp_frame.tstmp, p->ingress_latency);
                    } else {
                        ptp_frame.tstmp_valid = false;
                    }


                    pl->size = ptp_size;
                    if (ptp_frame.msg_type ==  LIP_PTP_MSGTYPE_PDELAY_RESP) {
                        lip_ptp_pdelay_req_proc_resp(p, pl, &ptp_frame);
                    } else if (ptp_frame.msg_type == LIP_PTP_MSGTYPE_PDELAY_RESP_FOLLOW_UP) {
                        lip_ptp_pdelay_req_proc_follow_up(p, pl, &ptp_frame);
                    } else if (ptp_frame.msg_type == LIP_PTP_MSGTYPE_PDELAY_REQ) {
                        lip_ptp_pdelay_resp_proc_req(p, pl, &ptp_frame);
                    } else if (ptp_frame.msg_type == LIP_PTP_MSGTYPE_SYNC) {
                        lip_ptp_md_eth_sync_recv_proc_sync(p, pl, &ptp_frame);
                    } else if (ptp_frame.msg_type == LIP_PTP_MSGTYPE_FOLLOW_UP) {
                        lip_ptp_md_eth_sync_recv_proc_fup(p, pl, &ptp_frame);
                    } else if (ptp_frame.msg_type == LIP_PTP_MSGTYPE_ANNOUNCE) {
                        lip_ptp_port_proc_announce(p, pl, &ptp_frame);
                    } else if (ptp_frame.msg_type == LIP_PTP_MSGTYPE_SIGNALING) {
                        lip_ptp_port_proc_signaling(p, pl, &ptp_frame);
                    }
                }
            }
        }
    }

    return err;
}

void lip_ptp_port_enable(int port_idx, uint16_t port_num) {
    t_lip_ptp_port_ctx *p = &g_lip_ptp_inst_ctx.ports[port_idx];
    if (!lip_ptp_port_is_en(p)) {
        p->stats.state = LIP_PTP_PORT_STATE_INIT;
        p->port_num = port_num;
        p->pkt_port_num_be = HTON16(port_num + 1);
        f_ptp_port_init(p);
    }
}

void lip_ptp_port_disable(int port_idx) {
    t_lip_ptp_port_ctx *p = &g_lip_ptp_inst_ctx.ports[port_idx];
    p->stats.state = LIP_PTP_PORT_STATE_DISABLED;

    /** @todo возможное обновление bmca */
    lip_ptp_port_announce_down(p);
    lip_ptp_port_gptp_cap_down(p);
    lip_ptp_pdelay_req_down(p);
}





void lip_ptp_port_set_latency(int port_idx, int32_t egress, int32_t ingress) {
    t_lip_ptp_port_ctx *p = &g_lip_ptp_inst_ctx.ports[port_idx];
    p->ingress_latency = -ingress; /* должна вычитаться из метки времени (8.4.3 из IEEE 802.1AS-2020) */
    p->egress_latency = egress;
}

void lip_ptp_set_system_priority2(uint8_t prio) {
    t_lip_ptp_inst_ctx *inst = &g_lip_ptp_inst_ctx;
    if (inst->sys_id.priority2 != prio) {
        inst->sys_id.priority2 = prio;
        lip_printf(LIP_LOG_MODULE_PTP, LIP_LOG_LVL_PROGRESS, 0,
                   "lip ptp: change system prio2 to %d\n", prio);
        lip_ptp_bmca_state_sel_update_req(inst);
    }
}

void lip_ptp_set_clkid_suffix(uint16_t clkid_suffix) {
    t_lip_ptp_inst_ctx *inst = &g_lip_ptp_inst_ctx;
    inst->cfg.clkid_suffix = clkid_suffix;
    f_fill_clock_id_suffix(inst);
    lip_ptp_bmca_state_sel_system_clkid_update(inst);
}

static const uint8_t *f_get_tlv_org_id(const uint8_t *buf, uint32_t *orgId, uint32_t *subType) {
    *orgId = ((uint32_t)buf[0] << 16) | ((uint32_t)buf[1] << 8) | buf[2];
    *subType = ((uint32_t)buf[3] << 16) | ((uint32_t)buf[4] << 8) | buf[5];
    return buf + LIP_PTP_TLV_ORG_HDR_SIZE;
}

static LINLINE const uint8_t *f_get_tlv_hdr(const uint8_t *buf, t_lip_ptp_tlv_hdr *hdr) {
    hdr->tlvType = *buf++ << 8;
    hdr->tlvType |= *buf++;
    hdr->lengthField = *buf++ << 8;
    hdr->lengthField |= *buf++;
    return buf;
}

void lip_ptp_parse_tlv(const uint8_t *opt_ptr, const uint8_t *opt_end, void *ctx, t_lip_ptp_tlv_parce_cb tlv_cb, t_lip_ptp_orgtlv_parce_cb org_cb) {
    while (((opt_ptr + sizeof(t_lip_ptp_tlv_hdr)) <= opt_end)) {
        t_lip_ptp_tlv_hdr hdr;
        const uint8_t *opt_data = f_get_tlv_hdr(opt_ptr, &hdr);
        opt_ptr = opt_data + hdr.lengthField;
        if (opt_ptr <= opt_end) {
            if (org_cb && ((hdr.tlvType == LIP_PTP_TLV_CODE_ORG_EXT)
                || (hdr.tlvType == LIP_PTP_TLV_CODE_ORG_EXT_PROP)
                || (hdr.tlvType == LIP_PTP_TLV_CODE_ORG_EXT_NOT_PROP))) {
                if (hdr.lengthField >= LIP_PTP_TLV_ORG_HDR_SIZE)  {
                    uint32_t orgId, subType;
                    opt_data = f_get_tlv_org_id(opt_data, &orgId, &subType);
                    org_cb(ctx, orgId, subType, opt_data, opt_ptr - opt_data);
                }
            } else if (tlv_cb) {
                tlv_cb(ctx, hdr.tlvType, opt_data, hdr.lengthField);
            }
        }
    }
}

bool lip_ptp_gm_time_valid(void) {
    t_lip_ptp_inst_ctx *inst = &g_lip_ptp_inst_ctx;
    return (inst->gm_stats.flags & LIP_PTP_GM_STATS_FLAG_SELF_GM)  || g_lip_ptp_inst_ctx.local_clk.clk_offs_valid;
}

void lip_ptp_tstmp_local_to_gm(const t_lip_ptp_tstmp *loc, t_lip_ptp_tstmp *gm) {
    t_lip_ptp_inst_ctx *inst = &g_lip_ptp_inst_ctx;
    if (inst->gm_stats.flags & LIP_PTP_GM_STATS_FLAG_SELF_GM) {
        *gm = *loc;
    } else {
        lip_ptp_local_clk_sync_to_gm(inst, loc, gm);
    }
}

void lip_ptp_tstmp_gm_to_local(const t_lip_ptp_tstmp *gm, t_lip_ptp_tstmp *loc) {
    t_lip_ptp_inst_ctx *inst = &g_lip_ptp_inst_ctx;
    if (inst->gm_stats.flags & LIP_PTP_GM_STATS_FLAG_SELF_GM) {
        *loc = *gm;
    } else {
        lip_ptp_local_clk_sync_from_gm(&g_lip_ptp_inst_ctx, gm, loc);
    }
}

const t_lip_ptp_port_stats *lip_ptp_port_stats(uint8_t port_idx) {
    return &g_lip_ptp_inst_ctx.ports[port_idx].stats;
}

const t_lip_ptp_gm_stats *lip_ptp_gm_stats(void) {
    return &g_lip_ptp_inst_ctx.gm_stats;
}

const t_lip_ptp_system_identity *lip_ptp_sys_id() {
    return &g_lip_ptp_inst_ctx.sys_id;
}


bool lip_ptp_get_local_time(t_lip_ptp_tstmp *tstmp) {
    bool done = false;
#if LIP_SW_SUPPORT_KSZ8567
    if (lip_sw_ksz8567_ptp_is_en()) {
        done = lip_sw_ksz8567_tstmp_read(tstmp) == LIP_ERR_SUCCESS;
    }
#endif
#if LIP_LL_PORT_FEATURE_HW_PTP_TSTMP
    if (!done && lip_ll_tstmp_is_enabled()) {
        done = lip_ll_tstmp_read(tstmp) == LIP_ERR_SUCCESS;
    }
#endif
    return done;
}


#endif








