/*****************************************************************************/ /** * 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 int8_t schdevent_compare(void *a, void *b) { ASSERT(a == NULL); ASSERT(b != NULL); register uint32_t idA, idB; idA = ((L2_SCHD_EVENT *)a)->eventId; idB = ((L2_SCHD_EVENT *)b)->eventId; if (idA == idB) { return 0; } else if (idA < idB) { return -1; } else { return 1; } } /*****************************************************************************/ /** * @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->compare = schdevent_compare; (*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->occurCnt = 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 ((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->occurCnt++; } } } } 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; }