forked from gatsby/df_datalink
432 lines
12 KiB
C
432 lines
12 KiB
C
/*****************************************************************************/
|
|
/**
|
|
* @file scan.c
|
|
* @author FanHao ([email protected])
|
|
* @brief DF Linklayer scan implementation file.
|
|
* @version 0.1
|
|
* @date 2023-05-06
|
|
*
|
|
* @copyright Copyright(c) 2024 Beijing Institute of Technology.\n
|
|
* Lab of Communication and Network
|
|
*
|
|
******************************************************************************/
|
|
/**
|
|
* @addtogroup LinkLayer
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @addtogroup LinkLayer_Scan
|
|
* @{
|
|
*/
|
|
|
|
/***************************** Include Files *********************************/
|
|
#include <string.h>
|
|
#include "link_layer.h"
|
|
#include "link_layer_types.h"
|
|
#include "msg_def.h"
|
|
#include "node_list.h"
|
|
#include "error.h"
|
|
#include "common.h"
|
|
#include "../phy_layer/phy_layer.h"
|
|
|
|
/************************** Constant Definitions *****************************/
|
|
#define ACK_FRAME_SLOTS 4
|
|
/***************** Macros (In-line Functions) Definitions *********************/
|
|
|
|
/**************************** Type Definitions *******************************/
|
|
|
|
/************************** Variable Definitions *****************************/
|
|
|
|
/************************** Function Prototypes ******************************/
|
|
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId);
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Packing Scan message to a bit array.
|
|
*
|
|
* @param bitarr pointer to bit array buffer.
|
|
* @param msgType message type.
|
|
*
|
|
* @return EPARAM
|
|
* SUCCESS
|
|
*
|
|
******************************************************************************/
|
|
static int32_t ScanMsg_Packing(L2_INST *instPtr, L2_FRAME_TYPE type, uint8_t dstId)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
int32_t Status;
|
|
|
|
switch (type)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
{
|
|
L2_MSG_ADV *message = (L2_MSG_ADV *)(instPtr->sendPktData);
|
|
|
|
// Common section of link layer package
|
|
message->common.frameNum = L2_GetNextFrameNum(instPtr);
|
|
message->common.slotNum = L2_GetNextSlotNum(instPtr);
|
|
message->common.src = L2_GetNodeId(instPtr);
|
|
message->common.dst = dstId;
|
|
message->common.msgType = L2_FRAME_ADV;
|
|
|
|
// insert position and speed info
|
|
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
|
message->srcPosX = instPtr->sysInfo.posX;
|
|
message->srcPosY = instPtr->sysInfo.posY;
|
|
message->srcPosZ = instPtr->sysInfo.posZ;
|
|
|
|
// Insert net start time
|
|
message->srcNetStatTime = instPtr->netStartTime;
|
|
|
|
// Packing extra payload
|
|
SysMonitor_GetSendPayload(message->advData, &(message->advDataId), L2_PAYLOAD_LEN_ADV);
|
|
if (message->advDataId == DATA_ID_NONE)
|
|
{
|
|
memset(message->advData, 0xAA, L2_PAYLOAD_LEN_ADV);
|
|
}
|
|
|
|
// Append CRC
|
|
uint32_t crcVal;
|
|
Status = L2_CrcGen((uint8_t *)message, sizeof(L2_MSG_ADV) - L2_MSG_CRC_LEN, L2_CRC8_31, &crcVal);
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("Fail to generate CRC, error code: %" PRId32 ".\n", Status);
|
|
return Status;
|
|
}
|
|
message->crc = crcVal;
|
|
|
|
// Logging...
|
|
memcpy(instPtr->log.txLog.data, message, sizeof(L2_MSG_ADV));
|
|
instPtr->log.txLog.dataId = message->advDataId;
|
|
|
|
break;
|
|
}
|
|
case L2_FRAME_ACK:
|
|
{
|
|
L2_MSG_ACK *message = (L2_MSG_ACK *)(instPtr->sendPktData);
|
|
|
|
// Common section of link layer package
|
|
message->common.frameNum = L2_GetNextFrameNum(instPtr);
|
|
message->common.slotNum = L2_GetNextSlotNum(instPtr);
|
|
message->common.src = L2_GetNodeId(instPtr);
|
|
message->common.dst = dstId;
|
|
message->common.msgType = L2_FRAME_ADV;
|
|
|
|
// insert position and speed info
|
|
SysMonitor_GetSysinfo(&(instPtr->sysInfo));
|
|
message->srcPosX = instPtr->sysInfo.posX;
|
|
message->srcPosY = instPtr->sysInfo.posY;
|
|
message->srcPosZ = instPtr->sysInfo.posZ;
|
|
message->srcSpeedX = instPtr->sysInfo.vX;
|
|
message->srcSpeedY = instPtr->sysInfo.vY;
|
|
message->srcSpeedZ = instPtr->sysInfo.vZ;
|
|
|
|
// Packing extra payload
|
|
SysMonitor_GetSendPayload(message->ackData, &(message->ackDataId), L2_PAYLOAD_LEN_ACK);
|
|
if (message->ackDataId == DATA_ID_NONE)
|
|
{
|
|
memset(message->ackData, 0xAA, L2_PAYLOAD_LEN_ACK);
|
|
}
|
|
|
|
// Append CRC
|
|
uint32_t crcVal;
|
|
Status = L2_CrcGen((uint8_t *)message, sizeof(L2_MSG_ACK) - L2_MSG_CRC_LEN, L2_CRC8_31, &crcVal);
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("Fail to generate CRC, error code: %" PRId32 ".\n", Status);
|
|
return Status;
|
|
}
|
|
message->crc = crcVal;
|
|
|
|
// Logging...
|
|
memcpy(instPtr->log.txLog.data, message, sizeof(L2_MSG_ACK));
|
|
instPtr->log.txLog.dataId = message->ackDataId;
|
|
|
|
break;
|
|
}
|
|
default:
|
|
DBG_ERROR("Unexpected frame type: %" PRId8 ".\n", type);
|
|
return EPARAM;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/**
|
|
* @brief Scan net packet handler.
|
|
*
|
|
* @param instPtr a pointer to linklayer layer instance
|
|
* @param msg A pointer to frame data buffer.
|
|
*
|
|
* @return
|
|
*
|
|
******************************************************************************/
|
|
int32_t L2_Scan_PktHandler(L2_INST *instPtr, uint8_t *msg)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
ASSERT(msg != NULL);
|
|
int32_t Status;
|
|
L2_FRAME_TYPE frameType = L2_FRAME_NONE;
|
|
L2_FrameGetChunk(msg, L2_MSG_TYPE, L2_MSG_TYPE_LEN, &frameType);
|
|
|
|
switch (frameType)
|
|
{
|
|
case L2_FRAME_ADV:
|
|
{
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD)
|
|
{
|
|
DBG_ERROR("Unexpected call from head node, only member Node can handle L2_FRAME_ADV.\n");
|
|
Status = EUNEXP;
|
|
break;
|
|
}
|
|
|
|
L2_MSG_ADV *message = (L2_MSG_ADV *)msg;
|
|
|
|
// Update node status.
|
|
uint8_t nodeId = message->common.src;
|
|
NODE_ENTRY *node;
|
|
node = L2_GetNodeById(instPtr->nodeList, nodeId);
|
|
if (node == NULL)
|
|
{
|
|
node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_HEAD);
|
|
if (node == NULL)
|
|
{
|
|
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", nodeId);
|
|
Status = ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Update node info.
|
|
node->nodeInfo.pos.x = message->srcPosX;
|
|
node->nodeInfo.pos.y = message->srcPosY;
|
|
node->nodeInfo.pos.z = message->srcPosZ;
|
|
node->nodeInfo.antIndex = Phy_ReceiveAntIndex(instPtr->config.phyInstPtr);
|
|
|
|
// Reset node ttl
|
|
node->ttlCnt = 0;
|
|
|
|
// Update net start time.
|
|
uint32_t netstartTime = message->srcNetStatTime;
|
|
L2_EVENT netSetupDoneEvent =
|
|
{
|
|
.event = L2_EV_NET_ADV_UPDATE,
|
|
.msg = &netstartTime
|
|
};
|
|
AssertL2Event(instPtr, &netSetupDoneEvent);
|
|
|
|
// Calculate time deviation
|
|
uint32_t frameNum = message->common.frameNum;
|
|
uint32_t slotNum = (uint32_t)message->common.slotNum;
|
|
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("Failed to compute time deviation.\n")
|
|
break;
|
|
}
|
|
|
|
// check if net setup finished.
|
|
if (L2_isCxn2Net(instPtr) == false)
|
|
{
|
|
// Assert Net-Setup Done.
|
|
L2_EVENT l2Event = {
|
|
.event = L2_EV_NET_SETUP_DONE,
|
|
.msg = NULL
|
|
};
|
|
(void)AssertL2Event(instPtr, &l2Event);
|
|
}
|
|
// Time sync.
|
|
L2_TimeAdjust(instPtr, &(instPtr->log.timeDev));
|
|
|
|
// Get data payload
|
|
uint32_t dataId = message->advDataId;
|
|
SysMonitor_UpdateRecvPayload(message->advData, dataId, L2_PAYLOAD_LEN_ADV);
|
|
|
|
// Logging...
|
|
memcpy(instPtr->log.rxLog.data, msg, sizeof(L2_MSG_ADV));
|
|
instPtr->log.rxLog.dataId = dataId;
|
|
|
|
Status = SUCCESS;
|
|
break;
|
|
}
|
|
case L2_FRAME_ACK:
|
|
{
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_MEMBER)
|
|
{
|
|
DBG_ERROR("Unexpected call from member node, only head Node can handle L2_FRAME_ACK.\n");
|
|
Status = EUNEXP;
|
|
break;
|
|
}
|
|
|
|
L2_MSG_ACK *message = (L2_MSG_ACK *)msg;
|
|
|
|
// Update node status.
|
|
uint8_t nodeId = message->common.src;
|
|
NODE_ENTRY *node;
|
|
node = L2_GetNodeById(instPtr->nodeList, nodeId);
|
|
if (node == NULL)
|
|
{
|
|
node = L2_AppendNode(instPtr->nodeList, nodeId, L2_NODE_MEMBER);
|
|
if (node == NULL)
|
|
{
|
|
DBG_ERROR("Failed to append new node [id: %" PRId8 "]", nodeId);
|
|
Status = ENOMEM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Update node info.
|
|
node->nodeInfo.pos.x = message->srcPosX;
|
|
node->nodeInfo.pos.y = message->srcPosY;
|
|
node->nodeInfo.pos.z = message->srcPosZ;
|
|
node->nodeInfo.speed.x = message->srcSpeedX;
|
|
node->nodeInfo.speed.y = message->srcSpeedY;
|
|
node->nodeInfo.speed.z = message->srcSpeedZ;
|
|
node->nodeInfo.antIndex = Phy_ReceiveAntIndex(instPtr->config.phyInstPtr);
|
|
|
|
// Reset node ttl
|
|
node->ttlCnt = 0;
|
|
|
|
// Calculate time deviation
|
|
uint32_t frameNum = message->common.frameNum;
|
|
uint32_t slotNum = (uint32_t)message->common.slotNum;
|
|
Status = L2_GetTimeDeviation(instPtr, frameNum, slotNum, true, &(instPtr->log.timeDev));
|
|
if (Status != SUCCESS)
|
|
{
|
|
DBG_ERROR("Failed to compute time deviation.\n")
|
|
break;
|
|
}
|
|
|
|
if (L2_GetMainState(instPtr) == L2_INIT_STATE) // FIXME: state switch should follow routing table
|
|
{
|
|
// Assert Net-Setup Done.
|
|
L2_EVENT l2Event;
|
|
L2_NODE_STATE newState = L2_NORMAL_STATE;
|
|
l2Event.event = L2_EV_MAIN_STATE_UPDATE;
|
|
l2Event.msg = &newState;
|
|
(void)AssertL2Event(instPtr, &l2Event);
|
|
}
|
|
|
|
// Get data payload
|
|
uint32_t dataId = message->ackDataId;
|
|
SysMonitor_UpdateRecvPayload(message->ackData, dataId, L2_PAYLOAD_LEN_ACK);
|
|
|
|
// Logging...
|
|
memcpy(instPtr->log.rxLog.data, msg, sizeof(L2_MSG_ACK));
|
|
instPtr->log.rxLog.dataId = dataId;
|
|
|
|
Status = SUCCESS;
|
|
break;
|
|
}
|
|
default:
|
|
DBG_ERROR("Unsupported frame type: %" PRId8 ".\n", frameType);
|
|
Status = EUNEXP;
|
|
break;
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* @brief Execute a scan net Routine procedure.
|
|
*
|
|
* @param rtneEntry Routine configuration
|
|
*
|
|
* @return used slot (2 ms slot).
|
|
*
|
|
******************************************************************************/
|
|
int32_t L2_Scan_Routine(L2_INST *instPtr, const L2_RTNE_TABLE_ENTRY *rtneEntry)
|
|
{
|
|
ASSERT(instPtr != NULL);
|
|
DBG_INFO("-------- Scan Routine --------\n");
|
|
|
|
if (rtneEntry->slotSeq != 0)
|
|
{
|
|
return SUCCESS; // skip other slots, only process in the 1st slot
|
|
}
|
|
|
|
PHY_INST *phyRef = instPtr->config.phyInstPtr;
|
|
PHY_ANT_INDEX antIndex;
|
|
L2_TOR_TYPE torState;
|
|
const NODE_ENTRY *commNode;
|
|
|
|
switch (rtneEntry->slotType)
|
|
{
|
|
case L2_SLOT_ADVERTISE:
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD && rtneEntry->src == L2_GetNodeId(instPtr))
|
|
{
|
|
// antenna selection based on broadcast id in routing table
|
|
antIndex = L2_AntId2AntIndex(rtneEntry->dst);
|
|
// head node transmits messages in advertise slot
|
|
torState = L2_TOR_TX;
|
|
|
|
// reset memory
|
|
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
|
|
// pack message
|
|
if (ScanMsg_Packing(instPtr, L2_FRAME_ADV, rtneEntry->dst) != SUCCESS)
|
|
{
|
|
return FAILURE;
|
|
}
|
|
}
|
|
else if (L2_GetNodeType(instPtr) == L2_NODE_MEMBER)
|
|
{
|
|
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
|
|
// antenna selection based on node list
|
|
antIndex = commNode->nodeInfo.antIndex;
|
|
// member node receives message in advertise slot
|
|
torState = L2_TOR_RX;
|
|
}
|
|
else
|
|
{
|
|
// otherwise suspend
|
|
antIndex = PHY_ANT_INDEX_NONE;
|
|
torState = L2_TOR_SUSPEND;
|
|
}
|
|
(void)Phy_SetAntIndex(instPtr->config.phyInstPtr, antIndex);
|
|
(void)L2_SetupNextSlot(instPtr, torState, L2_FRAME_ADV);
|
|
break;
|
|
case L2_SLOT_ACKNOWLEDGE:
|
|
if (L2_GetNodeType(instPtr) == L2_NODE_HEAD && rtneEntry->dst == L2_GetNodeId(instPtr))
|
|
{
|
|
// FIXME: is antenna index necessary here?
|
|
antIndex = PHY_ANT_INDEX_NONE;
|
|
// head node receives messages in acknowledge slot
|
|
torState = L2_TOR_RX;
|
|
}
|
|
else if (L2_GetNodeType(instPtr) == L2_NODE_MEMBER && rtneEntry->src == L2_GetNodeId(instPtr))
|
|
{
|
|
commNode = L2_GetNodeById(instPtr->nodeList, rtneEntry->src);
|
|
// antenna selection based on node list
|
|
antIndex = commNode->nodeInfo.antIndex;
|
|
// member node transmits message in acknowledge slot
|
|
torState = L2_TOR_TX;
|
|
|
|
// reset memory
|
|
memset(instPtr->sendPktData, 0xAA, L2_PACK_LEN_MAX);
|
|
// pack message
|
|
if (ScanMsg_Packing(instPtr, L2_FRAME_ACK, rtneEntry->dst) != SUCCESS)
|
|
{
|
|
return FAILURE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// otherwise suspend
|
|
antIndex = PHY_ANT_INDEX_NONE;
|
|
torState = L2_TOR_SUSPEND;
|
|
}
|
|
(void)Phy_SetAntIndex(instPtr->config.phyInstPtr, antIndex);
|
|
(void)L2_SetupNextSlot(instPtr, torState, L2_FRAME_ACK);
|
|
break;
|
|
default:
|
|
DBG_ERROR("Cannot start a routine for slot type [%" PRId8 "] properly.\n", rtneEntry->slotType);
|
|
return FAILURE;
|
|
}
|
|
return SUCCESS;
|
|
}
|
|
|
|
/** @} LinkLayer_Scan*/
|
|
/** @} LinkLayer*/
|