📄 ping_pong_rejoin.c
字号:
/*
V0.1 Initial Release 10/July/2006 RBR
*/
/*
This is a two node test, requires a Coordinator
and an RFD. The coordinator and node simply
ping-pong a packet back and forth, and print
out the RSSI byte. The RFD waits before
bouncing it back, while the coordinator responds
immediately.
Expects coordinator, and one RFD.
The topology to test should be:
Coordinator -> RFD1
Start the coordinator first, then
RFD1. If a RFD1 fails to join the network, try
again. The RFD1 will prompt the user to hit
a key to start the ping-pong.
You can connect multiple RFDs if desired.
You can also ping-pong through a router; see
the note in usrJoinVerifyCallback(). The topology
for a router would be:
coord -> router -> RFD1
-> RFD2
-> ..RFDn
This requires Virtual Boards to be running,
since a switch press is needed to start the pinging.
*/
#include "msstate_lrwpan.h"
#ifndef LRWPAN_COORDINATOR
#define PING_DELAY 2 //wait before bouncing back
#else
#define PING_DELAY 0 //coordinator does not wait
#endif
#define RX_PING_TIMEOUT 5 //seconds
//this is assumed to be the long address of our coordinator, in little endian order
//used to test LONG ADDRESSING back to coordinator
UINT16 ping_cnt;
UINT32 my_timer;
UINT32 last_tx_start;
LADDR_UNION dstADDR;
typedef enum _PP_STATE_ENUM {
PP_STATE_START_RX,
PP_STATE_WAIT_FOR_RX,
PP_STATE_SEND,
PP_STATE_WAIT_FOR_TX
}PP_STATE_ENUM;
PP_STATE_ENUM ppState;
BYTE rxFlag; //set from within usrRxPacketCallback
BYTE payload[2];
UINT16 numTimeouts;
BOOL first_packet;
void PingPong(void);
void printJoinInfo(void);
UINT8 pingRxTimeouts; //successive RX timeouts
UINT8 pingTxFailures; //successive TX failures
#define MAX_RX_TIMEOUTS 5
#define MAX_TX_FAILURES 5
void PingPong (void ) {
//exits on excessive RX or TX failures
while(1) {
apsFSM();
switch (ppState) {
case PP_STATE_START_RX:
if (!first_packet) {
my_timer= halGetMACTimer();
ppState = PP_STATE_WAIT_FOR_RX;
}else if (rxFlag) {
//on first packet, do not start timer, just wait for a packet.
ppState = PP_STATE_WAIT_FOR_RX;
first_packet = FALSE;
}
break;
case PP_STATE_WAIT_FOR_RX:
//rxFlag is set from within usrRxPacketCallback
if (rxFlag || halMACTimerNowDelta(my_timer) > MSECS_TO_MACTICKS( RX_PING_TIMEOUT *1000 )) {
if (!rxFlag) {
//increment total timeouts
numTimeouts++; //got tired of waiting for a response, send again
pingRxTimeouts++;
if (pingRxTimeouts > MAX_RX_TIMEOUTS) {
//too many successive timeouts, exit for rejoin
return;
}
} else {
pingRxTimeouts = 0; //reset successive timeouts
}
rxFlag = 0; //clear flag
if (EVB_LED1_STATE()) EVB_LED1_OFF(); else EVB_LED1_ON();
//start timer
my_timer= halGetMACTimer();
pingTxFailures = 0;
ppState = PP_STATE_SEND;
}
break;
case PP_STATE_SEND:
if ((halMACTimerNowDelta(my_timer))> MSECS_TO_MACTICKS(PING_DELAY*1000)){
MemDump();
//increment ping counter
ping_cnt++; //this was value received by this node
//received packet, ping it back
//format the packet
payload[0] = (BYTE) ping_cnt;
payload[1] = (BYTE) (ping_cnt>>8);
ppState = PP_STATE_WAIT_FOR_TX;
last_tx_start = halGetMACTimer();
aplSendMSG (APS_DSTMODE_SHORT,
&dstADDR,
2, //dst EP
0, //cluster is ignored for direct message
1, //src EP
&payload[0],
2, //msg length
apsGenTSN(),
FALSE); //No APS ack requested
ppState = PP_STATE_WAIT_FOR_TX;
}
break;
case PP_STATE_WAIT_FOR_TX:
if (apsBusy()) break; //status not ready yet if busy.
if (aplGetStatus() == LRWPAN_STATUS_SUCCESS) {
ppState = PP_STATE_START_RX;
//compute the latency of this TX send operation
//aplGetLastTxTime gets the time that the LAST tx operation finished.
//this will be the latency of the TX stack operation only if no mac retries were required
last_tx_start = aplMacTicksToUs(aplGetLastTxTime() - last_tx_start);
conPrintROMString("TX Stack latency(us): ");
conPrintUINT32(last_tx_start);
conPCRLF();
}else {
pingTxFailures++;
if (pingTxFailures > MAX_TX_FAILURES) {
//the only reason this should happen is because of our Radio failure
//or our parent is not returning MAC acks.
return;
}
conPrintROMString("Ping Send failed! Restarting timer to try again\n");
my_timer= halGetMACTimer();
ppState = PP_STATE_SEND;
}
break;
}
}
}
void printJoinInfo(void){
conPrintROMString("My ShortAddress is: ");
conPrintUINT16(aplGetMyShortAddress());
conPCRLF();
conPrintROMString("Parent LADDR: ");
conPrintLADDR(aplGetParentLongAddress());
conPrintROMString(", Parent SADDR: ");
conPrintUINT16(aplGetParentShortAddress());
conPCRLF();
}
typedef enum _JOIN_STATE_ENUM {
JOIN_STATE_START_JOIN,
JOIN_STATE_WAIT_FOR_JOIN,
JOIN_STATE_RUN_APP1,
JOIN_STATE_RUN_APP2,
JOIN_STATE_RUN_APP3,
JOIN_STATE_START_REJOIN,
JOIN_STATE_WAIT_FOR_REJOIN,
}JOIN_STATE_ENUM;
JOIN_STATE_ENUM joinState;
#define MAX_REJOIN_FAILURES 3
void main (void){
UINT8 failures;
//this initialization set our SADDR to 0xFFFF,
//PANID to the default PANID
//HalInit, evbInit will have to be called by the user
numTimeouts = 0;
my_timer = 0;
first_packet = TRUE;
halInit();
evbInit();
aplInit(); //init the stack
conPrintConfig();
ENABLE_GLOBAL_INTERRUPT(); //enable interrupts
EVB_LED1_OFF();
EVB_LED2_OFF();
joinState = JOIN_STATE_START_JOIN; //main while(1) initial state
ping_cnt = 0;
rxFlag = 0; //set to '1' when a packet is received.
//debug_level = 10;
//This version of PingPong has Network Rejoin logic in case of excessive failures
//by the PingPong() function during transmit.
while (1) {
apsFSM();
switch (joinState) {
case JOIN_STATE_START_JOIN:
EVB_LED1_OFF();
#ifdef LRWPAN_COORDINATOR
aplFormNetwork();
#else
aplJoinNetwork();
#endif
joinState = JOIN_STATE_WAIT_FOR_JOIN;
break;
case JOIN_STATE_WAIT_FOR_JOIN:
if (apsBusy()) break; //if stack is busy, continue
#ifdef LRWPAN_COORDINATOR
if (aplGetStatus() == LRWPAN_STATUS_SUCCESS) {
conPrintROMString("Network formed, waiting for RX\n");
EVB_LED1_ON(); //turn on LED1 indicating network is formed.
joinState = JOIN_STATE_RUN_APP1;
} else {
//only reason for this to fail is some sort of hardware failure
conPrintROMString("Network formation failed, waiting, trying again\n");
my_timer= halGetMACTimer();
//wait for 2 seconds
while ((halMACTimerNowDelta(my_timer))< MSECS_TO_MACTICKS(2*1000));
joinState = JOIN_STATE_START_JOIN;
}
#else
if (aplGetStatus() == LRWPAN_STATUS_SUCCESS) {
EVB_LED1_ON();
conPrintROMString("Network Join succeeded!\n");
printJoinInfo();
joinState = JOIN_STATE_RUN_APP1;
} else {
conPrintROMString("Network Join FAILED! Waiting, then trying again\n");
my_timer= halGetMACTimer();
//wait for 2 seconds
while ((halMACTimerNowDelta(my_timer))< MSECS_TO_MACTICKS(2*1000));
joinState = JOIN_STATE_START_JOIN;
}
#endif
break;
case JOIN_STATE_RUN_APP1:
#ifdef LRWPAN_COORDINATOR
//WARNING - this is only for latency testing, this variable is normally
//set to aMaxFrameRetries (value=3) as defined in mac.h. Setting this to 0 means
//that there will be no automatic retransmissions of frames if we do not get a MAC ACK back.
//only do this in your normal code if you want to disable automatic retries
aplSetMacMaxFrameRetries(0);
//coordinator waits for RX first
ppState = PP_STATE_START_RX;
pingRxTimeouts = 0; //used by PingPong to track RX successive failures
pingTxFailures = 0; //used by PingPont to track TX successive failures.
first_packet = TRUE;
PingPong(); //only exits on if excessive misses
//reset first_packet to flag to true, this causes Coord to just
//wait for a packet, and not try any retransmit on misses.
#else
conPrintROMString("Hit any switch to start!\n");
joinState = JOIN_STATE_RUN_APP2;
#endif
break;
case JOIN_STATE_RUN_APP2:
if (!(EVB_SW1_PRESSED() || EVB_SW2_PRESSED())) break; //fall through to next state
case JOIN_STATE_RUN_APP3:
//WARNING - this is only for latency testing, this variable is normally
//set to aMaxFrameRetries (value=3) as defined in mac.h. Setting this to 0 means
//that there will be no automatic retransmissions of frames if we do not get a MAC ACK back.
//only do this in your normal code if you want to disable automatic retries
aplSetMacMaxFrameRetries(0);
//switch is pressed, run app
dstADDR.saddr = 0; //RFD sends to the coordinator
ppState = PP_STATE_SEND;
pingRxTimeouts = 0; //used by PingPong to track RX successive failures
pingTxFailures = 0; //used by PingPont to track TX successive failures.
my_timer= halGetMACTimer(); //timer must be initialized before entering PP_SEND_STATE
PingPong();//only exits on if excessive misses
//try rejoining network
failures = 0;
joinState = JOIN_STATE_START_REJOIN;
break;
//rejoin states only executed by RFD
#ifndef LRWPAN_COORDINATOR
case JOIN_STATE_START_REJOIN:
EVB_LED1_OFF();
conPrintROMString("Trying to rejoin network!\n");
aplRejoinNetwork();
joinState = JOIN_STATE_WAIT_FOR_REJOIN;
break;
case JOIN_STATE_WAIT_FOR_REJOIN:
if (apsBusy()) break; //if stack is busy, continue
if (aplGetStatus() == LRWPAN_STATUS_SUCCESS) {
failures = 0;
EVB_LED1_ON();
conPrintROMString("Network Rejoin succeeded!\n");
printJoinInfo();
joinState = JOIN_STATE_RUN_APP3; //don't wait for button press
} else {
failures++;
if (failures == MAX_REJOIN_FAILURES) {
//this starts everything over
conPrintROMString("Max Rejoins failed, trying to join.\n");
joinState = JOIN_STATE_START_JOIN;
} else {
//else, wait to try again
conPrintROMString("Network Rejoin FAILED! Waiting, then trying again\n");
my_timer= halGetMACTimer();
//wait for 2 seconds
while ((halMACTimerNowDelta(my_timer))< MSECS_TO_MACTICKS(2*1000));
joinState = JOIN_STATE_START_REJOIN;
}
}
break;
#endif
default:
joinState = JOIN_STATE_START_JOIN;
}
}
}
//########## Callbacks ##########
//callback for anytime the Zero Endpoint RX handles a command
//user can use the APS functions to access the arguments
//and take additional action is desired.
//the callback occurs after the ZEP has already taken
//its action.
LRWPAN_STATUS_ENUM usrZepRxCallback(void){
#ifdef LRWPAN_COORDINATOR
if (aplGetRxCluster() == ZEP_END_DEVICE_ANNOUNCE) {
//a new end device has announced itself, print out the
//the neightbor table and address map
dbgPrintNeighborTable();
}
#endif
return LRWPAN_STATUS_SUCCESS;
}
//callback from APS when packet is received
//user must do something with data as it is freed
//within the stack upon return.
LRWPAN_STATUS_ENUM usrRxPacketCallback(void) {
BYTE len, *ptr;
//just print out this data
conPrintROMString("User Data Packet Received: \n");
conPrintROMString("SrcSADDR: ");
conPrintUINT16(aplGetRxSrcSADDR());
conPrintROMString(", DstEp: ");
conPrintUINT8(aplGetRxDstEp());
conPrintROMString(", Cluster: ");
conPrintUINT8(aplGetRxCluster());
conPrintROMString(", MsgLen: ");
len = aplGetRxMsgLen();
conPrintUINT8(len);
conPrintROMString(",RSSI: ");
conPrintUINT8(aplGetRxRSSI());
conPCRLF();
conPrintROMString("PingCnt: ");
ptr = aplGetRxMsgData();
ping_cnt = *ptr;
ptr++;
ping_cnt += ((UINT16)*ptr)<<8;
conPrintUINT16(ping_cnt);
conPrintROMString(", RxTimeouts: ");
conPrintUINT16(numTimeouts);
rxFlag = 1;//signal that we got a packet
//use this source address as the next destination address
dstADDR.saddr = aplGetRxSrcSADDR();
conPCRLF();
return LRWPAN_STATUS_SUCCESS;
}
#ifdef LRWPAN_FFD
//Callback to user level to see if OK for this node
//to join - implement Access Control Lists here based
//upon IEEE address if desired
BOOL usrJoinVerifyCallback(LADDR *ptr, BYTE capinfo){\
#if 0 //set this to '1' if you want to test through a router
//only accept routers.
//only let routers join us if we are coord
#ifdef LRWPAN_COORDINATOR
if (LRWPAN_GET_CAPINFO_DEVTYPE(capinfo)) {
//this is a router, let it join
conPrintROMString("Accepting router\n");
return TRUE;
}else {
conPrintROMString("Rejecting non-router\n");
return FALSE;
}
#else
return TRUE;
#endif
#else
return TRUE;
#endif
}
BOOL usrJoinNotifyCallback(LADDR *ptr){
//allow anybody to join
conPrintROMString("Node joined: ");
conPrintLADDR(ptr);
conPCRLF();
DEBUG_PRINTNEIGHBORS(DBG_INFO);
return TRUE;
}
#endif
//called when the slow timer interrupt occurs
#ifdef LRWPAN_ENABLE_SLOW_TIMER
void usrSlowTimerInt(void ) {}
#endif
//general interrupt callback , when this is called depends on the HAL layer.
void usrIntCallback(void){}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -