diff --git a/datalink814_ge/src/linklayer/schdevent.c b/datalink814_ge/src/linklayer/schdevent.c new file mode 100644 index 0000000..eeb36a7 --- /dev/null +++ b/datalink814_ge/src/linklayer/schdevent.c @@ -0,0 +1,385 @@ +/*****************************************************************************/ +/** + * Description: Event scheduling implementation + * + * Date: 2023-12-21 13:32 + * LastEditors: Fan Hao + * LastEditTime: 2023-12-21 13:32 + * Revisions: Rev 0.0 + * History: + * [2023-12-21]: Initial version. + * + * Copyright(c) 2021 Beijing Institute of Technology. + * Lab of Communication and Networking + * + ******************************************************************************/ + +/***************************** Include Files *********************************/ +#include +#include "schdevent.h" +#include "linklayer814.h" +#include "linklayer814_types.h" +#include "../error.h" +#include "../util/list.h" +/***************** Macros (Inline Functions) Definitions *********************/ +/**************************** Type Definitions *******************************/ +/************************** Variable Definitions *****************************/ +static L2_SCHD_EVENT util_schdevent; +/************************** Function Prototypes ******************************/ +/** + * @brief helper function to free schedule events. + */ +static void schdevent_free(void* val){ + if(val == NULL) { + return; + } + free(((L2_SCHD_EVENT*)val)->l2Event.msg); + free(val); +} + +/** + * @brief helper function to match events by ids. + */ +static bool schdevent_match(void* a, void* b){ + ASSERT(a == NULL); + ASSERT(b != NULL); + return (((L2_SCHD_EVENT*)a)->eventId + == ((L2_SCHD_EVENT*)b)->eventId); +} + +/*****************************************************************************/ +/** + * @brief Creat a schedule event pool. + * + * @param schdPool a pointer to schedule pool instance. + * + * @return SUCCESS + * + ******************************************************************************/ +int32_t L2_CreateSchedEventPool(L2_SCHD_POOL** schdPool) { + (*schdPool) = malloc(sizeof(L2_SCHD_POOL)); + if(*schdPool == NULL) { + DBG_ERROR("Failed to allocated memory for schdPool.\n"); + return EALLOC; + } + (*schdPool)->schdList = list_new(); + if((*schdPool)->schdList == NULL) { + DBG_ERROR("Failed to allocated memory for schdPool->schdList.\n"); + free(*schdPool); + return EALLOC; + } + (*schdPool)->schdList->free = schdevent_free; + (*schdPool)->schdList->match = schdevent_match; + (*schdPool)->envCnt = 0; + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Clear schedule event pool, delete all events in pool and + * free allocated memory. + * + * @param schdPool a pointer to schedule pool instance. + * + * @return SUCCESS + * + ******************************************************************************/ +void L2_ClearSchedEventPool(L2_SCHD_POOL* schdPool) { + ASSERT(schdPool != NULL); + list_clear(schdPool->schdList); + schdPool->envCnt = 0; +} + +/*****************************************************************************/ +/** + * @brief Completely destroy schedule event pool. + * + * @param schdPool a pointer to schedule pool instance. + * + * @return SUCCESS + * + ******************************************************************************/ +void L2_DestroySchedEventPool(L2_SCHD_POOL* schdPool) { + if(schdPool == NULL) { + return; + } + list_destroy(schdPool->schdList); + free(schdPool); +} + +/*****************************************************************************/ +/** + * @brief Creat a new schedule event, register event in schedule event pool. + * + * @param schdPool a pointer to schedule pool instance. + * @param event event type of the new schedule event. + * @param isVolatile event type of the new schedule event. + * + * @return NULL error occurred + * Pointer to schedule event. + * + ******************************************************************************/ +L2_SCHD_EVENT* L2_CreatNewSchdEvent(L2_SCHD_POOL* schdPool, L2_EVENT_TYPE event, bool isVolatile){ + ASSERT(schdPool != NULL); + if(event < L2_EV_SCAN_PROC_DONE || event > L2_ROUTINE_UPDATE){ + DBG_ERROR("Unknown event type: %d.\n", event); + return NULL; + } + L2_SCHD_EVENT* schdEvent = (L2_SCHD_EVENT*)malloc(sizeof(L2_SCHD_EVENT)); + if(schdEvent == NULL){ + DBG_ERROR("Failed to allocate schedule event.\n"); + return NULL; + } + list_node_t *node = list_node_new(schdEvent); + if(node == NULL) { + DBG_ERROR("Failed to allocate schedule event list node.\n"); + free(schdEvent); + return NULL; + } + schdEvent->eventId = schdPool->envCnt++; + schdEvent->ocurrCnt = 0; + schdEvent->l2Event.event = event; + schdEvent->l2Event.msg = NULL; + schdEvent->isSchd = false; + schdEvent->isVolatile = isVolatile; + schdEvent->schdSlot = L2_SLOTNO_NONE; + schdEvent->schdFrame = L2_FRAMENO_NONE; + list_rpush(schdPool->schdList, node); + return schdEvent; +} + +/*****************************************************************************/ +/** + * @brief Get a schedule event by its id. + * + * @param schdPool a pointer to schedule pool instance. + * @param id ID of the event + * + * @return NULL + * Pointer to the schedule event. + * + ******************************************************************************/ +L2_SCHD_EVENT* L2_GetEventById(L2_SCHD_POOL* schdPool, uint32_t id) { + ASSERT(schdPool != NULL); + util_schdevent.eventId = id; + list_node_t* node = list_find(schdPool->schdList, &util_schdevent); + if(node != NULL) { + DBG_WARNING("Event with id=%d, dose not exist.\n", id); + return NULL; + } + return ((L2_SCHD_EVENT*) node->val); +} + +/*****************************************************************************/ +/** + * @brief Delete a schedule event, remove the event from event pool, + * release memory. + * + * @param schdPool a pointer to schedule pool instance. + * @param id ID of the event + * + * @return SUCCESS + * error code + * + ******************************************************************************/ +int32_t L2_DeleteSchdEventById(L2_SCHD_POOL* schdPool, uint32_t id) { + ASSERT(schdPool != NULL); + util_schdevent.eventId = id; + list_node_t* node = list_find(schdPool->schdList, &util_schdevent); + if(node != NULL) { + DBG_ERROR("Event with id=%d, dose not exist.\n", id); + return EIGNORE; + } + list_remove(schdPool->schdList, node); + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Schedule a event at a specific time(indexed by frame and slot number) + * + * @param instPtr a pointer to linklayer instance + * @param schdEvent pointer to the schedule event. + * @param frameNum schedule frame number + * @param slotNum schedule slot number + * + * @return FAILURE, event has already been scheduled/schedule time not allowed. + * SUCCESS + * + ******************************************************************************/ +int32_t L2_ScheduleEventAt(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t frameNum, uint32_t slotNum){ + ASSERT(schdEvent != NULL); + if(L2_isEventScheduled(schdEvent) == true){ + DBG_ERROR("Event %d has already been scheduled.\n", schdEvent->eventId); + return FAILURE; + } + if(frameNum <= L2_GetCurrentFrameNum(instPtr) && slotNum < L2_GetCurrentSlotNum(instPtr)){ + DBG_ERROR("Cannot schedule event %d to the past(current: [%u-%u], schedule: [%u-%u]).\n", + schdEvent->eventId, L2_GetCurrentFrameNum(instPtr), L2_GetCurrentSlotNum(instPtr), frameNum, slotNum); + return FAILURE; + } + DBG_INFO("Schedule event (type:%d) [%u] at %u-%u.\n", + schdEvent->l2Event.event, schdEvent->eventId, + frameNum, slotNum); + schdEvent->isSchd = true; + schdEvent->schdFrame = frameNum; + schdEvent->schdSlot = slotNum; + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Schedule a event after a specific time period. + * + * @param instPtr a pointer to linklayer instance + * @param schdEvent pointer to the schedule event. + * @param numSlots how many slot later the event should be scheduled + * + * @return FAILURE, event has already been scheduled/schedule time not allowed. + * SUCCESS + * + ******************************************************************************/ +int32_t L2_ScheduleEventAfter(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t numSlots){ + ASSERT(schdEvent != NULL); + if(L2_isEventScheduled(schdEvent) == true){ + DBG_ERROR("Event %d has already been scheduled.\n", schdEvent->eventId); + return FAILURE; + } + uint32_t frameNum = L2_GetCurrentFrameNum(instPtr) + (numSlots/L2_SLOTS_PER_FRAME); + uint32_t slotNum = L2_GetCurrentSlotNum(instPtr) + (numSlots%L2_SLOTS_PER_FRAME); + return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum); +} + +/*****************************************************************************/ +/** + * @brief Reschedule a event at a specific time(indexed by frame and slot number) + * + * @param instPtr a pointer to linklayer instance + * @param schdEvent pointer to the schedule event. + * @param frameNum schedule frame number + * @param slotNum schedule slot number + * + * @return FAILURE, event has already been scheduled/schedule time not allowed. + * SUCCESS + * + ******************************************************************************/ +int32_t L2_RescheduleEventAt(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t frameNum, uint32_t slotNum){ + ASSERT(schdEvent != NULL); + if(schdEvent->isSchd == false){ + DBG_WARNING("Event %d has not been scheduled yet.\n", schdEvent->eventId); + } + schdEvent->isSchd = false; + return L2_ScheduleEventAt(instPtr, schdEvent, frameNum, slotNum); +} + +/*****************************************************************************/ +/** + * @brief Reschedule a event after a specific time period. + * + * @param instPtr a pointer to linklayer instance + * @param schdEvent pointer to the schedule event. + * @param numSlots how many slot later the event should be scheduled + * + * @return FAILURE, event has already been scheduled/schedule time not allowed. + * SUCCESS + * + ******************************************************************************/ +int32_t L2_RescheduleEventAfter(L2_INST* instPtr, L2_SCHD_EVENT* schdEvent, uint32_t numSlots){ + ASSERT(schdEvent != NULL); + if(schdEvent->isSchd == false){ + DBG_WARNING("Event %d has not been scheduled yet.\n", schdEvent->eventId); + } + return L2_ScheduleEventAfter(instPtr, schdEvent, numSlots); +} + + +/*****************************************************************************/ +/** + * @brief Check and excute schedule event in event pool illiterate. + * + * @param instPtr a pointer to linklayer instance + * + * @return NONE. + * + ******************************************************************************/ +void L2_EventPoolHandler(L2_INST* instPtr){ + ASSERT(instPtr != NULL); + list_node_t* node; + L2_SCHD_EVENT* event; + L2_SCHD_POOL *pool = instPtr->schdEventPool; + list_iterator_t* iter = list_iterator_new(pool->schdList, LIST_HEAD); + if (iter == NULL) + { + DBG_ERROR("Failed to initialize schedule event pool iteration.\n"); + return; + } + while (iter->next != NULL) + { + node = list_iterator_next(iter); + event = (L2_SCHD_EVENT*)node->val; + if(L2_isEventScheduled(event)){ + if(event->schdFrame == L2_GetCurrentFrameNum(instPtr) + && event->schdSlot == L2_GetCurrentSlotNum(instPtr)){ + DBG_INFO("Asserting scheduled event [%d].\n", event->eventId); + AssertL2Event(instPtr, &(event->l2Event)); + if(event->isVolatile == true) { + DBG_INFO("Deleting scheduled event [%d], since it is volatile.\n", event->eventId); + list_remove(pool->schdList, node); + } + else { + event->ocurrCnt++; + } + } + } + } + list_iterator_destroy(iter); +} + +/*****************************************************************************/ +/** + * @brief Append extra message content to specific schedule event. + * + * @param schdEvent pointer to the schedule event. + * msg pointer to the append content. + * + * @return SUCCESS. + * error code. + * + ******************************************************************************/ +inline void L2_SchdEventAppendMsg(L2_SCHD_EVENT* schdEvent, void* msg){ + ASSERT(schdEvent != NULL); + schdEvent->l2Event.msg = msg; +} + +/*****************************************************************************/ +/** + * @brief Cancel a scheduled event. + * + * @param schdEvent pointer to the schedule event. + * + * @return SUCCESS. + * + ******************************************************************************/ +inline int32_t L2_CancelEvent(L2_SCHD_EVENT* schdEvent){ + ASSERT(schdEvent != NULL); + if(schdEvent->isSchd == false){ + DBG_WARNING("Event %d has not been scheduled yet.\n", schdEvent->eventId); + } + schdEvent->isSchd = false; + return SUCCESS; +} + +/*****************************************************************************/ +/** + * @brief Check if the event was scheduled. + * + * @param schdEvent pointer to the schedule event. + * + * @return true. + * false. + * + ******************************************************************************/ +inline bool L2_isEventScheduled(const L2_SCHD_EVENT* schdEvent){ + ASSERT(schdEvent != NULL); + return schdEvent->isSchd; +}