/*****************************************************************************/ /** * Description: Implementations of 814 linklayer local record. * * Date: 2022-07-14 00:08 * LastEditors: Fan Hao * LastEditTime: 2022-07-14 22:52 * Revisions: Rev 0.0 * History: * [2022-07-14]: Initial version. * * Copyright(c) 2021 Beijing Institute of Technology. * Lab of Communication and Networking * ******************************************************************************/ /***************************** Include Files *********************************/ #include #include #include #include #include "linklayer814_types.h" #include "node_list.h" #include "../util/clist.h" #include "../common.h" #include "../error.h" /***************** Macros (Inline Functions) Definitions *********************/ inline uint32_t L2_GetNodeListLen(NODE_LIST *list) { ASSERT(list != NULL); return list->len; } /**************************** Type Definitions *******************************/ /************************** Variable Definitions *****************************/ static NODE_ENTRY util_entry; /************************** Function Prototypes ******************************/ /** * @brief helper function to free node entry. */ static void entry_free(void *val) { free(val); } /** * @brief helper function to match node entries by nodeIds */ static int8_t entry_compare(void *a, void *b) { ASSERT(a != NULL); ASSERT(b != NULL); register uint8_t idA, idB; idA = ((NODE_ENTRY *)a)->nodeInfo.nodeId; idB = ((NODE_ENTRY *)b)->nodeInfo.nodeId; if (idA == idB) { return 0; } else if (idA < idB) { return -1; } else { return 1; } } /*****************************************************************************/ /** * @brief Initialize node list * * @param list * * @return SUCCESS * ENOMEM - not enough memory. * ******************************************************************************/ int32_t L2_NodeList_Init(NODE_LIST **list) { (*list) = clist_new(); if (*list == NULL) { return ENOMEM; } (*list)->free = entry_free; (*list)->compare = entry_compare; return SUCCESS; } /*****************************************************************************/ /** * @brief Clear all nodes in the node list, free allocated memory. * * @param list *NONE * ******************************************************************************/ void L2_NodeList_Clear(NODE_LIST *list) { ASSERT(list != NULL); clist_clear(list); } /*****************************************************************************/ /** * @brief Completely destroy node list. * * @param list * * @return NONE * ******************************************************************************/ void L2_NodeList_Destroy(NODE_LIST *list) { clist_destroy(list); } /*****************************************************************************/ /** * @brief Get node entry from node list base on node id. * * @param list * @param nodeId * * @return Node entry * NULL if node dose not exist. * ******************************************************************************/ NODE_ENTRY *L2_GetNodeById(NODE_LIST *list, uint8_t nodeId) { ASSERT(list != NULL); util_entry.nodeInfo.nodeId = nodeId; clist_node_t *node = clist_find(list, &util_entry); if (node == NULL) { return NULL; } else { return ((NODE_ENTRY *)node->val); } } /*****************************************************************************/ /** * @brief Append a new node entry to the node list * * @param list * @param nodeId * @param nodeType * * @return SUCCESS Node was added successfully. * Other Error occurred.(Node already exist, memory alloc error ect.) * ******************************************************************************/ NODE_ENTRY *L2_AppendNode(NODE_LIST *list, uint8_t nodeId, L2_NODE_TYPE nodeType) { ASSERT(list != NULL); if (L2_isNodeInList(list, nodeId)) { DBG_WARNING("Node [%d] already exist.\n", nodeId); return NULL; } DBG_INFO("Link layer appending node [%d] to node list.\n", nodeId); NODE_ENTRY *nodeEntry = (NODE_ENTRY *)malloc(sizeof(NODE_ENTRY)); if (nodeEntry == NULL) { DBG_ERROR("Failed to allocated memory for nodeEntry.\n"); return NULL; } clist_node_t *node = clist_node_new(nodeEntry); if (node == NULL) { DBG_ERROR("Failed to allocated memory for list node.\n"); free(nodeEntry); return NULL; } nodeEntry->nodeInfo.nodeId = nodeId; nodeEntry->nodeInfo.nodeType = (uint8_t)nodeType; nodeEntry->nodeInfo.pos.x = 0; nodeEntry->nodeInfo.pos.y = 0; nodeEntry->nodeInfo.pos.z = 0; nodeEntry->nodeInfo.speed.x = 0; nodeEntry->nodeInfo.speed.y = 0; nodeEntry->nodeInfo.speed.z = 0; nodeEntry->nodeInfo.beamNo = 0; nodeEntry->ttlCnt = 0; clist_rpush(list, node); return nodeEntry; } /*****************************************************************************/ /** * @brief Delete a node in list based on node id. * * @param list * @param nodeId * * @return SUCCESS Node has been successfully deleted. * Other Node not exist. * ******************************************************************************/ int32_t L2_DeleteNodeById(NODE_LIST *list, uint8_t nodeId) { ASSERT(list != NULL); util_entry.nodeInfo.nodeId = nodeId; clist_node_t *node = clist_find(list, &util_entry); if (node == NULL) { DBG_WARNING("Node [%d] in not in node list, skip deleting process.\n", nodeId); return SUCCESS; } DBG_INFO("Deleting node [%d].\n", nodeId); clist_remove(list, node); return SUCCESS; } /*****************************************************************************/ /** * @brief Check whether the node is already in the node list. * * @param list * @param nodeId * * @return true node in the list * false node not in the list * ******************************************************************************/ bool L2_isNodeInList(NODE_LIST *list, uint8_t nodeId) { ASSERT(list != NULL); return (L2_GetNodeById(list, nodeId) != NULL); } /*****************************************************************************/ /** * @brief Get the distance between me and the node. * * @param list * @param nodeId * @param dst A pointer to store distance. * * @return SUCCESS distance has been successfully store in dst * FAILURE Node dose not exit. * ******************************************************************************/ int32_t L2_GetDistance(NODE_LIST *list, COORD myCoord, uint8_t nodeId, double *dst) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { *dst = Coord_Distance(myCoord, nodeEntry->nodeInfo.pos); return SUCCESS; } } /*****************************************************************************/ /** * @brief Update node positions information. * * @param list * @param nodeId * @param newPos A structure stores the corresponding node position info. * * @return SUCCESS update successfully. * FAILURE node not exist. * ******************************************************************************/ int32_t L2_UpdateNodePos(NODE_LIST *list, uint8_t nodeId, const COORD *newPos) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { memcpy(&(nodeEntry->nodeInfo.pos), newPos, sizeof(COORD)); } return SUCCESS; } /*****************************************************************************/ /** * @brief Get node positions information. * * @param list * @param nodeId * @param newPos A structure stores the corresponding node position info. * * @return SUCCESS update successfully. * FAILURE node not exist. * ******************************************************************************/ int32_t L2_GetNodePos(NODE_LIST *list, uint8_t nodeId, COORD *pos) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { memcpy(pos, &(nodeEntry->nodeInfo.pos), sizeof(COORD)); } return SUCCESS; } /*****************************************************************************/ /** * @brief Update node speed information. * * @param list * @param nodeId * @param newSpeed A structure stores the corresponding node speed info. * * @return SUCCESS update successfully. * FAILURE node not exist. * ******************************************************************************/ int32_t L2_UpdateNodeSpeed(NODE_LIST *list, uint8_t nodeId, const COORD *newSpeed) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { memcpy(&(nodeEntry->nodeInfo.speed), newSpeed, sizeof(COORD)); } return SUCCESS; } /*****************************************************************************/ /** * @brief Get node speed information. * * @param list * @param nodeId * @param newSpeed A structure stores the corresponding node speed info. * * @return SUCCESS update successfully. * FAILURE node not exist. * ******************************************************************************/ int32_t L2_GetNodeSpeed(NODE_LIST *list, uint8_t nodeId, COORD *speed) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { memcpy(speed, &(nodeEntry->nodeInfo.speed), sizeof(COORD)); } return SUCCESS; } /*****************************************************************************/ /** * @brief Update node ACK status. * * @param list * @param nodeId * @param devi * * @return SUCCESS update successfully. * FAILURE Node not exist. * ******************************************************************************/ int32_t L2_UpdateNodeTimeDeviation(NODE_LIST *list, uint8_t nodeId, int32_t devi) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { nodeEntry->timeDevi = devi; } return SUCCESS; } /*****************************************************************************/ /** * @brief Increase TTL of specified node in the list. * * @param list * @param inc cnt of slot to add * @param nodeId * * @return NONE * ******************************************************************************/ int32_t L2_IncNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t inc) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { nodeEntry->ttlCnt += inc; } return SUCCESS; } /*****************************************************************************/ /** * @brief Reset node TTL based on node id. * * @param list * @param nodeId * * @return SUCCESS TTL has been successfully cleared. * FAILURE Node not exist. * ******************************************************************************/ int32_t L2_RstNodeTTL(NODE_LIST *list, uint8_t nodeId) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { nodeEntry->ttlCnt = 0; } return SUCCESS; } /*****************************************************************************/ /** * @brief Get TTL of specified node in the list. * * @param list * @param nodeId * @param ttl * * @return NONE * ******************************************************************************/ int32_t L2_GetNodeTTL(NODE_LIST *list, uint8_t nodeId, uint32_t *ttl) { ASSERT(list != NULL); NODE_ENTRY *nodeEntry = L2_GetNodeById(list, nodeId); if (nodeEntry == NULL) { return FAILURE; } else { *ttl = nodeEntry->ttlCnt; } return SUCCESS; } /*****************************************************************************/ /** * @brief Implements a edit operations to each node. * * @param list * @param param * @param operation A pointer to a function handled "NODE_ENTRY*" as input * which defines the operations need to be apply. * * @return SUCCESS Operations has been applied successfully to all nodes. * Other Error occurred. * ******************************************************************************/ int32_t L2_IterEditNode(NODE_LIST *list, const void *param, int32_t (*operation)(NODE_ENTRY *, const void *)) { ASSERT(list != NULL); int32_t Status; clist_node_t *node; clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD); if (iter == NULL) { DBG_ERROR("Failed to initialize list iteration process.\n"); return EALLOC; } while ((node = clist_iterator_next(iter))) { Status = operation((NODE_ENTRY *)node->val, param); if (Status != SUCCESS) { DBG_ERROR("Error occurred when iteratively edit node entry.\n"); break; } } clist_iterator_destroy(iter); return Status; } /*****************************************************************************/ /** * @brief Filter all node, delete all the node not satisfied the condition. * * @param list * @param condition A pointer to a function handled "NODE_ENTRY*" as input * which defines the condition need to be verify. * * @return SUCCESS * ******************************************************************************/ int32_t L2_IterDeleteNode(NODE_LIST *list, bool (*condition)(NODE_ENTRY *)) { ASSERT(list != NULL); clist_node_t *node; clist_iterator_t *iter = clist_iterator_new(list, LIST_HEAD); if (iter == NULL) { DBG_ERROR("Failed to initialize list iteration process.\n"); return EALLOC; } while ((node = clist_iterator_next(iter))) { if (condition((NODE_ENTRY *)node->val) == false) { clist_remove(list, node); } } clist_iterator_destroy(iter); return SUCCESS; }