📄 nwk.c
字号:
/*
V0.1 Initial Release 10/July/2006
*
*/
/*
V0.21 Fixed problem in nwkCopyFwdPkt relating to copying of the radius byte
27/July/2006
V0.2 added PC-based binding 21/July/2006
V0.1 Initial Release 10/July/2006
*/
/*
Network Layer
*/
#include "compiler.h"
#include "lrwpan_config.h" //user configurations
#include "lrwpan_common_types.h" //types common acrosss most files
#include "ieee_lrwpan_defs.h"
#include "console.h"
#include "debug.h"
#include "memalloc.h"
#include "neighbor.h"
#include "hal.h"
#include "halStack.h"
#include "phy.h"
#include "mac.h"
#include "nwk.h"
#include "aps.h"
#include "neighbor.h"
typedef enum _NWK_RXSTATE_ENUM {
NWK_RXSTATE_IDLE,
NWK_RXSTATE_START,
NWK_RXSTATE_APS_HANDOFF,
NWK_RXSTATE_DOROUTE
} NWK_RXSTATE_ENUM;
static NWK_RXSTATE_ENUM nwkRxState;
static void nwkParseHdr(BYTE *ptr);
NWK_SERVICE a_nwk_service;
NWK_STATE_ENUM nwkState;
NWK_RX_DATA a_nwk_rx_data;
BYTE nwkDSN;
NWK_PIB nwk_pib;
static void nwkRxFSM(void);
//locals
#ifndef LRWPAN_COORDINATOR
static UINT32 nwk_utility_timer; //utility timer
static UINT8 nwk_retries; //utility retry counter
#endif
#ifdef LRWPAN_FFD
void nwkCopyFwdPkt(void);
static BOOL nwkRxBuffFull(void);
static BOOL nwkRxBuffEmpty(void);
static NWK_FWD_PKT *nwkGetRxPacket(void);
static void nwkFreeRxPacket(BOOL freemem);
#endif
//there can only be one TX in progress at a time, so
//a_aps_tx_data contains the arguments for that TX on the NWK layer.
NWK_TX_DATA a_nwk_tx_data;
void nwkTxData(BOOL fwdFlag);
void nwkInit(void){
nwkDSN = 0;
nwk_pib.flags.val = 0;
nwkState = NWK_STATE_IDLE;
nwkRxState= NWK_RXSTATE_IDLE;
#ifdef LRWPAN_FFD
nwk_pib.rxTail = 0;
nwk_pib.rxHead = 0;
#endif
}
void nwkFSM(void){
macFSM();
nwkRxFSM();
nwkFSM_start:
switch (nwkState) {
case NWK_STATE_IDLE:
#ifdef LRWPAN_FFD
//see if we have packets to forward and can grab the TX buffer
if (!nwkRxBuffEmpty() && phyTxUnLocked()) {
//grab the lock and forward the packet
phyGrabTxLock();
nwkCopyFwdPkt();
//transmit it
nwkTxData(TRUE); //use TRUE as this is a forwarded packet
nwkState = NWK_STATE_FWD_WAIT;
}
#endif
break;
case NWK_STATE_COMMAND_START:
switch(a_nwk_service.cmd) {
case LRWPAN_SVC_NWK_GENERIC_TX:
//at this point, need to check if INDIRECT or DIRECT, take action
//send a generic packet with arguments specified by upper level
//this assumes the upper level has grabbed the TX buffer lock
nwkTxData(FALSE);
nwkState = NWK_STATE_GENERIC_TX_WAIT;
break;
#ifdef LRWPAN_COORDINATOR
case LRWPAN_SVC_NWK_FORM_NETWORK:
//if forming network, restart everything
//if we are forming a network, then we need to restart
//the PHY, MAC layers from scratch
phyInit();
macInit();
ntInitTable(); //init neighbor table
a_nwk_service.status = macInitRadio(); //turns on the radio
if (a_nwk_service.status != LRWPAN_STATUS_SUCCESS) {
DEBUG_STRING(DBG_ERR, "NWK Formation failed!\n");
nwkState = NWK_STATE_IDLE;
break;
}
//this is where we form a network.
nwkState = NWK_STATE_FORM_NETWORK_START;
goto nwkFSM_start;
#else
case LRWPAN_SVC_NWK_JOIN_NETWORK:
// see if this is a rejoin or join
if (a_nwk_service.args.join_network.RejoinNetwork) {
mac_pib.flags.bits.macIsAssociated = 0; //if doing rejoin, unsure of association, clear it.
nwkState = NWK_STATE_REJOIN_NETWORK_START;
goto nwkFSM_start; //do not do any other initialization
}
else nwkState = NWK_STATE_JOIN_NETWORK_START;
//if joining/rejoining network, restart everything
//if we are forming a network, then we need to restart
//the PHY, MAC layers from scratch
phyInit();
macInit();
#ifdef LRWPAN_FFD
ntInitTable(); //init neighbor table
#endif
a_nwk_service.status = macInitRadio(); //turns on the radio
if (a_nwk_service.status != LRWPAN_STATUS_SUCCESS) {
DEBUG_STRING(DBG_ERR, "NWK JOIN/REJOIN failed!\n");
nwkState = NWK_STATE_IDLE;
break;
}
goto nwkFSM_start;
#endif
default: break;
}//end switch(a_nwk_service.cmd)
case NWK_STATE_GENERIC_TX_WAIT:
if (macBusy()) break;
//mac finished, copy status.
a_nwk_service.status = a_mac_service.status;
nwkState = NWK_STATE_IDLE;
break;
#ifdef LRWPAN_FFD
case NWK_STATE_FWD_WAIT:
if (macBusy()) break;
//mac finished, this is only used for fwding packets
//will ignore status for now since there is not much
//can do about it. Eventally, with more advanced routing,
// will record the status of this link and try an alternate
//route on failure.
phyReleaseTxLock(); //release the lock
nwkState = NWK_STATE_IDLE;
break;
#endif
case NWK_STATE_REJOIN_NETWORK_START:
if (macBusy()) break;
//send an orphan notification
a_mac_service.cmd = LRWPAN_SVC_MAC_ORPHAN_NOTIFY;
nwkState = NWK_STATE_REJOIN_WAIT;
macDoService();
break;
case NWK_STATE_REJOIN_WAIT:
if (macBusy()) break;
//at this point, rejoin is finished, get status
a_nwk_service.status = a_mac_service.status;
nwkState = NWK_STATE_IDLE;
break;
#ifdef LRWPAN_COORDINATOR
case NWK_STATE_FORM_NETWORK_START:
//here is where we would scan the channels, etc.
//instead, we will just set the channel, and indicate
//that the network is formed, and init the neighbor table.
macSetPANID(a_nwk_service.args.form_network.PANid);
macSetChannel(LRWPAN_DEFAULT_START_CHANNEL);
macSetShortAddr(0);
//initialize address assignment, must be done after the
//short address is set
ntInitAddressAssignment();
//add ourselves to the
nwk_pib.flags.bits.nwkFormed = 1;
mac_pib.flags.bits.macIsAssociated = 1; //I am associated with myself!
//tell MAC to allow association
mac_pib.flags.bits.macAssociationPermit = 1;
a_nwk_service.status = LRWPAN_STATUS_SUCCESS;
nwkState = NWK_STATE_IDLE;
break;
#endif
#ifndef LRWPAN_COORDINATOR
case NWK_STATE_JOIN_NETWORK_START:
//if trying to join, do not allow association
mac_pib.flags.bits.macAssociationPermit = 0;
#ifdef LRWPAN_FORCE_ASSOCIATION_TARGET
//if forcing association to particular target, skip beacon request
//go to state that will start forced association, selecting channels
nwkState = NWK_STATE_JOIN_MAC_ASSOC_CHANSELECT;
#else
//select a channel
a_mac_service.args.beacon_req.LogicalChannel = LRWPAN_DEFAULT_START_CHANNEL;
//set retries
//we always send out at least three BEACON req to make
//sure that we adequately poll everybody in the region
nwk_retries = NWK_GENERIC_RETRIES;
mac_pib.bcnDepth = 0xFF; //initialze the beacon depth response
//start the request
nwkState = NWK_STATE_JOIN_SEND_BEACON_REQ;
#endif
goto nwkFSM_start;
case NWK_STATE_JOIN_SEND_BEACON_REQ:
//at this point, we would start scanning channels
//sending out beacon requests on each channel
// we will only send out a beacon on the default channel, instead of scanning
if (macBusy()) break;
a_mac_service.cmd = LRWPAN_SVC_MAC_BEACON_REQ;
nwkState = NWK_STATE_JOIN_NWK_WAIT1_BREQ;
macDoService();
break;
//waits for BCN request TX to finish
case NWK_STATE_JOIN_NWK_WAIT1_BREQ:
if (macBusy()) break;
//at this point, the packet has been sent. Now have
//to wait for a response. Record
nwk_utility_timer = halGetMACTimer();
nwkState =NWK_STATE_JOIN_NWK_WAIT2_BREQ;
break;
case NWK_STATE_JOIN_NWK_WAIT2_BREQ:
//wait for either a BCN response or timeout.
if (mac_pib.flags.bits.GotBeaconResponse) {
//we have received a BCN response. Try joining this node
//for right now just print out debug message
DEBUG_STRING(DBG_INFO,"Got BCN Response\n");
//keep trying, want to poll everybody in range
//and pick the closest one
mac_pib.flags.bits.GotBeaconResponse = 0;
}else if (halMACTimerNowDelta(nwk_utility_timer)> MSECS_TO_MACTICKS(LRWPAN_NWK_JOIN_WAIT_DURATION) ) {
if (nwk_retries) nwk_retries--;
if (nwk_retries) {
//retry Beacon Request
nwkState = NWK_STATE_JOIN_SEND_BEACON_REQ;
goto nwkFSM_start;
}else
{
//out of retries, check bcnDepth
if ( mac_pib.bcnDepth != 0xFF) {
//we got a response, so lets try to join
nwkState = NWK_STATE_JOIN_MAC_ASSOC;
//use the same channel
a_mac_service.args.assoc_req.LogicalChannel = a_mac_service.args.beacon_req.LogicalChannel;
DEBUG_STRING(DBG_INFO,"NWK trying association\n");
}else {
//indicate failure
DEBUG_STRING(DBG_INFO,"NWK Join Timeout\n");
a_nwk_service.status = LRWPAN_STATUS_NWK_JOIN_TIMEOUT;
nwkState = NWK_STATE_IDLE;
}
//clear flags
mac_pib.flags.bits.GotBeaconResponse = 0;
mac_pib.flags.bits.WaitingForBeaconResponse = 0;
}
}
break;
case NWK_STATE_JOIN_MAC_ASSOC_CHANSELECT:
//this will eventually scan channels, for now, just select default
a_mac_service.args.assoc_req.LogicalChannel = LRWPAN_DEFAULT_START_CHANNEL;
nwkState = NWK_STATE_JOIN_MAC_ASSOC;
goto nwkFSM_start;
case NWK_STATE_JOIN_MAC_ASSOC:
//do association to PANID discovered by beacon request
if (macBusy()) break;
a_mac_service.cmd = LRWPAN_SVC_MAC_ASSOC_REQ;
nwkState = NWK_STATE_JOIN_MAC_ASSOC_WAIT;
macDoService();
break;
case NWK_STATE_JOIN_MAC_ASSOC_WAIT:
if (macBusy()) break;
//at this point, association is finished, get status
a_nwk_service.status = a_mac_service.status;
#ifdef LRWPAN_FFD
if (a_nwk_service.status == LRWPAN_STATUS_SUCCESS) {
//as a router, initialize address assignment and
//begin allowing association
ntInitAddressAssignment();
mac_pib.flags.bits.macAssociationPermit = 1;
}
#endif
nwkState = NWK_STATE_IDLE;
break;
#endif
//these states for FORM NETWORK
default: break;
}//end switch(nwkState)
}
//Add the NWK header, then send it to MAC
//if fwdFlag is true, then packet is being forwarded, so nwk header
//is already in place, and assume that currentTxFrm and currentTxPLen
//are correct as well, and that the radius byte has been decremented.
void nwkTxData(BOOL fwdFlag) {
//if we are not associated, don't bother sending NWK packet
if (!mac_pib.flags.bits.macIsAssociated) {
//call a dummy service that just returns an error code
//have to do it this way since the caller is expecting a
//mac service call
a_mac_service.args.error.status = LRWPAN_STATUS_MAC_NOT_ASSOCIATED;
a_mac_service.cmd = LRWPAN_SVC_MAC_ERROR;
goto nwkTxData_sendit;
}
if (a_nwk_tx_data.radius == 0) {
DEBUG_STRING(DBG_ERR,"Nwk Radius is zero, discarding packet.\n");
//can no longer forward this packet.
a_mac_service.args.error.status = LRWPAN_STATUS_NWK_RADIUS_EXCEEDED;
a_mac_service.cmd = LRWPAN_SVC_MAC_ERROR;
goto nwkTxData_sendit;
}
if (fwdFlag) goto nwkTxData_addmac;
//sequence number
--phy_pib.currentTxFrm;
*phy_pib.currentTxFrm = nwkDSN;
nwkDSN++;
//radius, decrement before sending, receiver will
//get a value that is one less than this node.
--phy_pib.currentTxFrm;
*phy_pib.currentTxFrm = (--a_nwk_tx_data.radius);
//src address
--phy_pib.currentTxFrm;
*phy_pib.currentTxFrm = (BYTE) (a_nwk_tx_data.srcSADDR >> 8);
--phy_pib.currentTxFrm;
*phy_pib.currentTxFrm = (BYTE) (a_nwk_tx_data.srcSADDR);
//dst address
--phy_pib.currentTxFrm;
*phy_pib.currentTxFrm = (BYTE) (a_nwk_tx_data.dstSADDR >> 8);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -