⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 aps.c

📁 本程序是基于Zigbee协议的无线温度传感器网络系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
*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 + -