📄 aps.c
字号:
/*
*2006/08/16 WXL 2.0
*/
/*
V0.2 added PC-based binding
V0.1 Initial Release 10/July/2006
*/
/*
APS 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 "zep.h"
#include "aps.h"
#include "evboard.h"
#define apsTXIdle() (!aps_pib.flags.bits.TxInProgress)
#define apsTXBusy() (aps_pib.flags.bits.TxInProgress)
#define apsSetTxBusy() aps_pib.flags.bits.TxInProgress = 1
#define apsSetTxIdle() aps_pib.flags.bits.TxInProgress = 0
typedef enum _APS_RXSTATE_ENUM {
APS_RXSTATE_IDLE,
APS_RXSTATE_START,
APS_RXSTATE_RESOLVE_INDIRECT,
APS_RXSTATE_ACK_SEND_WAIT
} APS_RXSTATE_ENUM;
APS_PIB aps_pib;
APS_SERVICE a_aps_service;
APS_STATE_ENUM apsState;
APS_EP_ELEM apsEndPoints[LRWPAN_MAX_ENDPOINTS];
//there can only be one TX in progress at a time, so
//a_aps_tx_data contains the arguments for that TX on the APS layer.
APS_TX_DATA a_aps_tx_data;
APS_RX_DATA a_aps_rx_data;
APS_RX_DATA indirect_data; //used for holding an indirect packet while being reflected.
void apsFSM(void);
void apsTxData(BOOL copy_payload);
//locals
static APS_RXSTATE_ENUM apsRxState;
static LRWPAN_STATUS_ENUM apsTxFSM_status;
static void apsParseHdr(BYTE *ptr);
static void apsRxFSM(void);
static BOOL apsCheckAck(void);
static void apsFormatAck(void);
static void apsTxFSM(void);
static void apsInjectPacket(BOOL indirect_flag);
static void apsInjectTxPacket(void);
#ifdef LRWPAN_COORDINATOR
void apsRxBuffInit(void);
BOOL apsRxBuffFull(void);
BOOL apsRxBuffEmpty(void);
APS_RX_DATA *apsGetRxPacket(void);
void apsFreeRxPacket(BOOL freemem);
void apsRxBuffAdd (APS_RX_DATA *ptr);
#endif
//converts MAC TICKs to Microseconds
UINT32 aplMacTicksToUs(UINT32 ticks){
return(halMacTicksToUs(ticks));
}
//this sleeps, then restarts the stack and the radio
void aplShutdown(void){
//wait until stack is idle
while(apsBusy()) apsFSM();
DISABLE_GLOBAL_INTERRUPT(); //disable interrupts, if halSleep wants to reenable them, let it.
halShutdown();
a_aps_service.status = LRWPAN_STATUS_SUCCESS;
}
void aplWarmstart(void){
a_aps_service.status = macWarmStartRadio();
}
//this is top level init, does inits for other layers
void apsInit(void){
debug_level = 0;
apsState = APS_STATE_IDLE;
apsRxState = APS_RXSTATE_IDLE;
#ifdef LRWPAN_COORDINATOR
aps_pib.rxCnt = 0;
aps_pib.rxTail = 0;
aps_pib.rxHead = 0;
#endif
aps_pib.apsTSN = 0;
aps_pib.flags.val = 0;
aps_pib.apscAckWaitDuration = MSECS_TO_MACTICKS(LRWPAN_APS_ACK_WAIT_DURATION) ; //convert to MAC Ticks
aps_pib.apsAckWaitMultiplier = 1; //default value
aps_pib.apscMaxFrameRetries = LRWPAN_APS_MAX_FRAME_RETRIES ;
//initialize the endpoints
aps_pib.activeEPs = 0; //only tracks user endpoints.
phyInit();
macInit();
nwkInit();
zepInit();
}
//simply remembers these so that we can report them to the coordinator.
LRWPAN_STATUS_ENUM aplRegisterEndPoint(BYTE epNum)
{
if (aps_pib.activeEPs == LRWPAN_MAX_ENDPOINTS) return(LRWPAN_STATUS_APS_MAX_ENDPOINTS_EXCEEDED);
if (epNum == 0) return(LRWPAN_STATUS_APS_ILLEGAL_ENDPOINT);
apsEndPoints[aps_pib.activeEPs++].epNum = epNum;
return(LRWPAN_STATUS_SUCCESS);
}
//Formats a Send Message service
void aplFmtSendMSG (BYTE dstMode,
LADDR_UNION *dstADDR,
BYTE dstEP,
BYTE cluster,
BYTE srcEP,
BYTE* pload,
BYTE plen,
BYTE tsn,
BYTE reqack)
{
BYTE buf[8];
BYTE i;
while(apsBusy()) apsFSM();
a_aps_service.cmd = LRWPAN_SVC_APS_GENERIC_TX;
a_aps_tx_data.flags.val = 0;
a_aps_tx_data.srcEP = srcEP;
a_aps_tx_data.usrPlen = plen;
a_aps_tx_data.usrPload = pload;
a_aps_tx_data.tsn = tsn;
a_aps_tx_data.cluster = cluster;
a_aps_tx_data.dstMode = dstMode;
a_aps_tx_data.dstEP = dstEP;
a_aps_tx_data.srcSADDR = macGetShortAddr();
a_aps_tx_data.af_fcf = (1 | AF_FRM_TYPE_MSG);
if (dstMode == APS_DSTMODE_NONE) {
a_aps_tx_data.aps_fcf = APS_FRM_TYPE_DATA | APS_FRM_DLVRMODE_INDIRECT;
}else {
a_aps_tx_data.aps_fcf = APS_FRM_TYPE_DATA | APS_FRM_DLVRMODE_NORMAL;
if (a_aps_tx_data.dstMode == APS_DSTMODE_SHORT ){
a_aps_tx_data.dstSADDR = dstADDR->saddr;
if (dstADDR->saddr == macGetShortAddr()) {
//sending to ourselves
a_aps_tx_data.flags.bits.loopback = 1;
}
}
else {
a_aps_tx_data.dstLADDR = &dstADDR->laddr.bytes[0];
a_aps_tx_data.dstSADDR = LRWPAN_SADDR_USE_LADDR;
/* APS acks to no make sense for LONG addressing, which is
being used to bypass routing. The MAC acks serve for APS acks
in this case. Also APS acks would be returned via routing,
negating the bypass of the routing in the first place.
*/
reqack = 0;
//see if we are sending to ourself
halGetProcessorIEEEAddress(buf);
for(i=0;i<8;i++) {
if (buf[i] != dstADDR->laddr.bytes[i]) break;
}
if (i==8) {
//this is a loopback, so use our short address in this field
a_aps_tx_data.dstSADDR = macGetShortAddr();
a_aps_tx_data.flags.bits.loopback = 1;
}
}
}
if (reqack) a_aps_tx_data.aps_fcf |= (APS_FRM_ACKREQ_MASK);
}
//TODO - add a pib flag that indicates when the User's TX
//buffer has been copied so that user can begin building a
//new TX packet while the old one is being TX'ed.
void apsFSM(void) {
#ifdef LRWPAN_COORDINATOR
APS_RX_DATA *rxPtr;
#endif
nwkFSM();
//if TxFSM is busy we need to call it
if (apsTXBusy()) apsTxFSM();
apsRxFSM(); //check RX
zepFSM(); //do ZEP
apsFSM_start:
switch (apsState) {
case APS_STATE_IDLE:
//ackSendPending check must come before the indirect Pending check!
if (aps_pib.flags.bits.ackSendPending) {
apsState = APS_STATE_ACK_SEND_START;
goto apsFSM_start;
}
#ifdef LRWPAN_COORDINATOR
if (aps_pib.flags.bits.indirectPending) {
//free up RX FSM so that we can receive possible APS acks for this packet.
aps_pib.flags.bits.indirectPending = 0; //free up RX FSM
// an indirect message needs resolving
//initialize the binding table iterator
//get pointer to current indirect packet
rxPtr = &aps_pib.rxBuff[aps_pib.rxTail];
if (!evbBindTableIterInit(rxPtr->srcEP, rxPtr->srcSADDR,rxPtr->cluster)){
//a failure to initialize the iterator, give up.
DEBUG_STRING(DBG_ERR,"APS: BindTable Iterator initialize failed. Discarding indirect msg.\n");
apsState = APS_STATE_IDLE;
}else {
apsState = APS_STATE_INDIRECT_GETDST;
goto apsFSM_start;
}
}
#endif
break;
case APS_STATE_COMMAND_START:
switch(a_aps_service.cmd) {
case LRWPAN_SVC_APS_GENERIC_TX:
aps_pib.flags.bits.IsUsrBufferFree = 0;
#ifdef LRWPAN_COORDINATOR
if (APS_GET_FRM_DLVRMODE(a_aps_tx_data.aps_fcf) == APS_FRM_DLVRMODE_INDIRECT){
//this is a special case. A Coordinator endpoint is sending indirect.
//we need to inject this into the stack as if it has been received
apsState = APS_STATE_INJECT_INDIRECT;
goto apsFSM_start;
}
#endif
if (a_aps_tx_data.flags.bits.loopback) {
apsState = APS_STATE_INJECT_LOOPBACK; //we are sending a direct packet to ourself!
goto apsFSM_start;
}
//Indirect vs Direct is handled within the apsTxData() function
//at this point ready to begin formating packet.
//do not exit this state until we can grab the TX buffer.
if (phyTxUnLocked()) {
phyGrabTxLock(); //prevents lower stack layers from grabbing TX buffer.
phy_pib.currentTxFlen = 0; //set frame length to zero, build from scratch
apsTxData(TRUE);
aps_pib.flags.bits.IsUsrBufferFree = 1;
apsState = APS_STATE_GENERIC_TX_WAIT;
}
break;
case LRWPAN_SVC_APS_DO_ZEP_TX:
if (phyTxUnLocked()) {
phyGrabTxLock(); //prevents lower stack layers from grabbing TX buffer.
switch(a_aps_service.args.zep_tx.clusterID)
{
case ZEP_END_DEVICE_ANNOUNCE:
zepFmtEndDeviceAnnounce(a_aps_service.args.zep_tx.dst);
break;
case ZEP_EXTENDED_CMD:
switch(a_aps_service.args.zep_tx.extID)
{
case ZEP_EXT_NODE_INFO_RSP:
zepFmtNodeInfoRsp(a_aps_service.args.zep_tx.dst);
break;
case ZEP_EXT_PING:
zepFmtPing(a_aps_service.args.zep_tx.dst);
break;
case ZEP_EXT_SEND_ALARM:
zepFmtAlarm(a_aps_service.args.zep_tx.dst,
a_aps_service.args.zep_tx.ext.alarm.mode
);
break;
}
break;
default: break;
}
phy_pib.currentTxFlen = 0; //set frame length to zero, build from scratch
apsTxData(FALSE); //payload already in TX buffer
apsState = APS_STATE_GENERIC_TX_WAIT;
}
break;
case LRWPAN_SVC_APS_NWK_PASSTHRU:
//for NWK calls that have to pass thru the APS layer
//this just serves to lock the APS layer while the
//the NWK layer is doing its thing
if (nwkBusy()) break; //wait until nwk is idle
nwkDoService();
apsState = APS_STATE_NWK_PASSTHRU_WAIT;
break;
default: break;
}//end switch(a_aps_service.cmd)
break;
case APS_STATE_ACK_SEND_START:
if (phyTxLocked()) break;
//send an ACK
//lock the TX buffer
phyGrabTxLock();
//we are now ready
apsFormatAck();
phy_pib.currentTxFlen = 0; //set frame length to zero, build from scratch
apsTxData(TRUE);
//data sent, release the RX buffer, will let RX FSM resume
aps_pib.flags.bits.ackSendPending = 0;
apsState = APS_STATE_GENERIC_TX_WAIT;
break;
case APS_STATE_GENERIC_TX_WAIT:
if (!apsTXIdle()) break;
//TX is finished, copy status
a_aps_service.status = apsTxFSM_status;
//release the TX buffer lock before exiting.
phyReleaseTxLock();
apsState = APS_STATE_IDLE;
if (aps_pib.flags.bits.indirectPending) {
//have used this state to wait for finishing sending an
//ACK back to the source of an indirect transmit. Now
//finish resolving the indirect
goto apsFSM_start;
}
break;
case APS_STATE_NWK_PASSTHRU_WAIT:
//for split-phase passthrus
if (nwkBusy()) break;
a_aps_service.status = a_nwk_service.status;
apsState = APS_STATE_IDLE;
break;
case APS_STATE_INJECT_LOOPBACK:
//wait for RX to become idle
if (apsRxState != APS_RXSTATE_IDLE) break;
//inject packet into RX FSM
apsInjectPacket(FALSE);
aps_pib.flags.bits.IsUsrBufferFree = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -