📄 mac.c
字号:
mac_pib.flags.bits.WaitingForAssocResponse = 1;
//send to coordinator with Short address = 0;
a_mac_tx_data.SrcPANID = 0xFFFF;
//Transmit it
macTxData();
macState = MAC_STATE_ASSOC_REQ_WAIT1;
break;
default: break;
}//end switch cmd
break;
case MAC_STATE_ASSOC_REQ_WAIT1:
if (!macTXIdle()) break;
//TX is finished
phyReleaseTxLock();
if (macTxFSM_status != LRWPAN_STATUS_SUCCESS) {
//no sense waiting any longer, nobody responded to MAC-level ACK
a_mac_service.status = macTxFSM_status;
mac_pib.flags.bits.WaitingForAssocResponse = 0;
macState = MAC_STATE_IDLE;
break;
}
//now need to wait for association response
//start a timer
mac_utility_timer = halGetMACTimer();
macState = MAC_STATE_ASSOC_REQ_WAIT2;
break;
case MAC_STATE_ASSOC_REQ_WAIT2:
if (mac_pib.flags.bits.macIsAssociated) {
//association successful, hooray!
a_mac_service.status = LRWPAN_STATUS_SUCCESS;
mac_pib.flags.bits.WaitingForAssocResponse = 0;
macState = MAC_STATE_IDLE;
}else if ((halMACTimerNowDelta(mac_utility_timer))>MAC_ASSOC_WAIT_TIME ){
//timeout on association, give it up
a_mac_service.status = LRWPAN_STATUS_MAC_ASSOCIATION_TIMEOUT;
DEBUG_STRING(DBG_INFO,"MAC: Association timeout\n");
mac_pib.flags.bits.WaitingForAssocResponse = 0;
macState = MAC_STATE_IDLE;
}
break;
case MAC_STATE_ORPHAN_WAIT1:
if (!macTXIdle()) break;
//TX is finished
phyReleaseTxLock();
if (macTxFSM_status != LRWPAN_STATUS_SUCCESS){
//don't wait, TX failed
DEBUG_STRING(DBG_INFO,"Orphan Notify TX failed\n");
mac_pib.flags.bits.WaitingForOrphanResponse = 0;
a_mac_service.status = macTxFSM_status;
macState = MAC_STATE_IDLE;
break;
}
//now need to wait for association response
//start a timer
mac_utility_timer = halGetMACTimer();
macState = MAC_STATE_ORPHAN_WAIT2;
break;
case MAC_STATE_ORPHAN_WAIT2:
if (mac_pib.flags.bits.GotOrphanResponse) {
//rejoin successfull
a_mac_service.status = LRWPAN_STATUS_SUCCESS;
mac_pib.flags.bits.WaitingForOrphanResponse = 0;
mac_pib.flags.bits.GotOrphanResponse = 0;
macState = MAC_STATE_IDLE;
} else if ((halMACTimerNowDelta(mac_utility_timer))>MAC_ORPHAN_WAIT_TIME ){
//timeout on rejoin, give it up
a_mac_service.status = LRWPAN_STATUS_MAC_ORPHAN_TIMEOUT;
DEBUG_STRING(DBG_INFO,"MAC: Orphan timeout\n");
mac_pib.flags.bits.WaitingForOrphanResponse = 0;
macState = MAC_STATE_IDLE;
}
break;
case MAC_STATE_GENERIC_TX_WAIT:
if (!macTXIdle()) break;
//TX is finished, copy status
a_mac_service.status = macTxFSM_status;
macState = MAC_STATE_IDLE;
break;
//this is used by MAC CMDs in general which send a packet with no ACK.
case MAC_STATE_GENERIC_TX_WAIT_AND_UNLOCK:
if (!macTXIdle()) break;
//TX is finished, copy status
a_mac_service.status = macTxFSM_status;
macState = MAC_STATE_IDLE;
//also unlock TX buffer
phyReleaseTxLock();
break;
#ifdef LRWPAN_FFD
case MAC_STATE_HANDLE_ORPHAN_NOTIFY:
//first, check to see if this node is in my neighbor table
nt_ptr = ntFindByLADDR(&a_mac_rx_data.SrcAddr.laddr);
if (!nt_ptr) {
//not my orphan, ignoring
DEBUG_STRING(DBG_INFO,"MAC: Received orphan notify, but not my orphan, ignoring.\n");
macState = MAC_STATE_IDLE;
//also unlock TX buffer
phyReleaseTxLock();
break;
}
DEBUG_STRING(DBG_INFO,"Sending Coord Realign (Orphan response)\n");
//at this point, we have an orphan. Send a response.
macFormatCoordRealign(mac_addr_tbl[nt_ptr->map_index].saddr);
goto mac_state_send_assoc_response1; //shared code
case MAC_STATE_SEND_BEACON_RESPONSE:
//got a Beacon Request, send the response
DEBUG_STRING(DBG_INFO,"Sending BCN Response\n");
macFormatBeacon();
a_mac_tx_data.fcflsb = LRWPAN_FRAME_TYPE_BEACON;
a_mac_tx_data.fcfmsb = LRWPAN_FCF_DSTMODE_NOADDR|LRWPAN_FCF_SRCMODE_SADDR;
a_mac_tx_data.SrcAddr = macGetShortAddr();
a_mac_tx_data.SrcPANID = mac_pib.macPANID;
macTxData();
macState = MAC_STATE_GENERIC_TX_WAIT_AND_UNLOCK;
break;
case MAC_STATE_SEND_ASSOC_RESPONSE:
DEBUG_STRING(DBG_INFO,"Sending Association Response\n");
macFormatAssociationResponse();
mac_state_send_assoc_response1:
a_mac_tx_data.fcflsb = LRWPAN_FRAME_TYPE_MAC|LRWPAN_FCF_ACKREQ_MASK;
a_mac_tx_data.fcfmsb = LRWPAN_FCF_DSTMODE_LADDR|LRWPAN_FCF_SRCMODE_LADDR;
a_mac_tx_data.DestAddr.laddr.bytes[0] = a_mac_rx_data.SrcAddr.laddr.bytes[0];
a_mac_tx_data.DestAddr.laddr.bytes[1] = a_mac_rx_data.SrcAddr.laddr.bytes[1];
a_mac_tx_data.DestAddr.laddr.bytes[2] = a_mac_rx_data.SrcAddr.laddr.bytes[2];
a_mac_tx_data.DestAddr.laddr.bytes[3] = a_mac_rx_data.SrcAddr.laddr.bytes[3];
a_mac_tx_data.DestAddr.laddr.bytes[4] = a_mac_rx_data.SrcAddr.laddr.bytes[4];
a_mac_tx_data.DestAddr.laddr.bytes[5] = a_mac_rx_data.SrcAddr.laddr.bytes[5];
a_mac_tx_data.DestAddr.laddr.bytes[6] = a_mac_rx_data.SrcAddr.laddr.bytes[6];
a_mac_tx_data.DestAddr.laddr.bytes[7] = a_mac_rx_data.SrcAddr.laddr.bytes[7];
a_mac_tx_data.DestPANID = mac_pib.macPANID;
macTxData();
macState = MAC_STATE_GENERIC_TX_WAIT_AND_UNLOCK;
break;
#endif
default: break;
}
}
//called by HAL when TX for current packet is finished
void macTxCallback(void) {
if (LRWPAN_GET_ACK_REQUEST(*(phy_pib.currentTxFrm))) {
mac_pib.flags.bits.ackPending = 1; //we are requesting an ack for this packet
//record the time of this packet
mac_pib.tx_start_time = halISRGetMACTimer();
}
}
//we pass in the pointer to the packet
//first byte is packet length
void macRxCallback(BYTE *ptr, BYTE rssi) {
//if this is an ACK, update the current timeout, else indicate
// that an ACK is pending
// check length check frame control field
if ((*ptr == LRWPAN_ACKFRAME_LENGTH ) && LRWPAN_IS_ACK(*(ptr+1))) {
//do not save ACK frames
//this is an ACK, see if it is our ACK, check DSN
if (*(ptr+3) == mac_pib.macDSN) {
//DSN matches, assume this is our ack, clear the ackPending flag
mac_pib.flags.bits.ackPending = 0;
DEBUG_CHAR( DBG_ITRACE,DBG_CHAR_OURACK );
}
} else {
//save the packet, we assume the Physical/Hal layer has already checked
//if the MAC buffer has room
mac_pib.rxHead++;
if (mac_pib.rxHead == MAC_RXBUFF_SIZE) mac_pib.rxHead = 0;
//save it.
mac_pib.rxBuff[mac_pib.rxHead].data = ptr; //save pointer
mac_pib.rxBuff[mac_pib.rxHead].rssi = rssi; //save RSSI value
}
}
BOOL macRxBuffFull(void){
BYTE tmp;
//if next write would go to where Tail is, then buffer is full
tmp = mac_pib.rxHead+1;
if (tmp == MAC_RXBUFF_SIZE) tmp = 0;
return(tmp == mac_pib.rxTail);
}
BOOL macRxBuffEmpty(void){
return(mac_pib.rxTail == mac_pib.rxHead);
}
//this does NOT remove the packet from the buffer
MACPKT *macGetRxPacket(void) {
BYTE tmp;
if (mac_pib.rxTail == mac_pib.rxHead) return(NULL);
tmp = mac_pib.rxTail+1;
if (tmp == MAC_RXBUFF_SIZE) tmp = 0;
return(&mac_pib.rxBuff[tmp]);
}
//frees the first packet in the buffer.
void macFreeRxPacket(BOOL freemem) {
mac_pib.rxTail++;
if (mac_pib.rxTail == MAC_RXBUFF_SIZE) mac_pib.rxTail = 0;
if (freemem) MemFree(mac_pib.rxBuff[mac_pib.rxTail].data);
}
/************
The TxInProgress bit is set when the macTxData function
is called the first time to actually format the header and
send the packet. After that, each loop through the macTxFSM
checks to see if the TX started and finished correctly, and
if an ACK was received if one was requested. The FSM becomes
idle if:
a. the PHY TX returns an error
b. the PHY TX returned success and either no ACK was
requested or we received the correct ACK
c. the PHY TX returned success and we exhausted retries.
**************/
static void macTxFSM(void) {
if(!macTXIdle()) {
//we are not idle
if (phyIdle()) {
//cannot check anything until PHY is idle
if (a_phy_service.status != LRWPAN_STATUS_SUCCESS) {
//don't bother waiting for ACK, TX did not start correctly
mac_pib.flags.bits.ackPending = 0;
macSetTxIdle(); //mark TX as idle
macTxFSM_status = a_phy_service.status; //return status
} else if (!mac_pib.flags.bits.ackPending) {
//either no ACK requested or ACK has been received
macSetTxIdle(); //finished successfully, mark as idle
macTxFSM_status = LRWPAN_STATUS_SUCCESS;
}
//check timeout
else if (halMACTimerNowDelta(mac_pib.tx_start_time)> mac_pib.macAckWaitDuration)
{
// ACK timeout
if (mac_pib.currentAckRetries) mac_pib.currentAckRetries--;
if (!mac_pib.currentAckRetries) {
//retries are zero. We have failed.
macTxFSM_status = LRWPAN_STATUS_MAC_MAX_RETRIES_EXCEEDED;
macSetTxIdle();
DEBUG_STRING(1,"MAC TX Retry exceeded\n");
} else {
//retry...
macTxData(); //reuse the last packet.
}
}
}
}
}
//format the packet and send it
//this is NOT used for either beacon or ack frames, only for data and MAC frames
//a side effect of this function is that if the source address mode is SHORT
//and our MAC short address is 0xFFFE, then the source address mode is forced to
//long as per the IEEE SPEC.
//this builds the header in reverse order since we adding header bytes to
//headers already added by APS, NWK layers.
//Add the MAC header, then send it to PHY
static void macTxData(void) {
BYTE c;
BYTE dstmode, srcmode;
if (macTXIdle()) {
//first time we are sending this packet, format the header
//used static space for header. If need to store, will copy it later
//format the header
dstmode = LRWPAN_GET_DST_ADDR(a_mac_tx_data.fcfmsb);
srcmode = LRWPAN_GET_SRC_ADDR(a_mac_tx_data.fcfmsb);
if (mac_pib.macPANID == 0xFFFE && srcmode == LRWPAN_ADDRMODE_SADDR) {
//our short address is 0xFFFE, force srcmode to long address
srcmode = LRWPAN_ADDRMODE_LADDR;
//clear src mode
a_mac_tx_data.fcfmsb = a_mac_tx_data.fcfmsb & ~LRWPAN_FCF_SRCMODE_MASK;
//set to long address
LRWPAN_SET_SRC_ADDR(a_mac_tx_data.fcfmsb,LRWPAN_ADDRMODE_LADDR);
}
//format src Address
switch(srcmode){
case LRWPAN_ADDRMODE_NOADDR:
break;
case LRWPAN_ADDRMODE_SADDR:
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE)(a_mac_tx_data.SrcAddr >> 8);
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE)a_mac_tx_data.SrcAddr;
phy_pib.currentTxFlen=phy_pib.currentTxFlen+2;
break;
case LRWPAN_ADDRMODE_LADDR:
//this has to be our own long address, get it
halGetProcessorIEEEAddress(phy_pib.currentTxFrm-8);
phy_pib.currentTxFlen=phy_pib.currentTxFlen+8;
phy_pib.currentTxFrm = phy_pib.currentTxFrm-8;
break;
default:
break;
}
//format src PANID
if ( !LRWPAN_GET_INTRAPAN(a_mac_tx_data.fcflsb) &&
srcmode != LRWPAN_ADDRMODE_NOADDR
) {
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE) (a_mac_tx_data.SrcPANID >> 8);
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE)a_mac_tx_data.SrcPANID;
phy_pib.currentTxFlen=phy_pib.currentTxFlen+2;
}
//format dst Address
switch(dstmode){
case LRWPAN_ADDRMODE_NOADDR:
break;
case LRWPAN_ADDRMODE_SADDR:
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE)(a_mac_tx_data.DestAddr.saddr >> 8);
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE)a_mac_tx_data.DestAddr.saddr;
phy_pib.currentTxFlen=phy_pib.currentTxFlen+2;
break;
case LRWPAN_ADDRMODE_LADDR:
for(c=0;c<8;c++) {
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = a_mac_tx_data.DestAddr.laddr.bytes[7-c];
}
phy_pib.currentTxFlen=phy_pib.currentTxFlen+8;
break;
default:
break;
}
//format dst PANID, will be present if both dst is nonzero
if (dstmode != LRWPAN_ADDRMODE_NOADDR){
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE) (a_mac_tx_data.DestPANID >> 8);
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = (BYTE)a_mac_tx_data.DestPANID;
phy_pib.currentTxFlen=phy_pib.currentTxFlen+2;
}
//format dsn
mac_pib.macDSN = halGetRandomByte();
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = mac_pib.macDSN; //set DSN
//format MSB Fcontrol
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = a_mac_tx_data.fcfmsb;
//format LSB Fcontrol
phy_pib.currentTxFrm--;
*phy_pib.currentTxFrm = a_mac_tx_data.fcflsb;
phy_pib.currentTxFlen = phy_pib.currentTxFlen + 3; //DSN, FCFLSB, FCFMSB
// at this point, we will attempt a TX
mac_pib.flags.bits.ackPending = 0;
//now send the data, ignore the GTS and INDIRECT bits for now
DEBUG_STRING(DBG_TX,"TX DSN: ");
DEBUG_UINT8(DBG_TX,mac_pib.macDSN);
DEBUG_STRING(DBG_TX,"\n");
macSetTxBusy();
mac_pib.currentAckRetries = mac_pib.macMaxAckRetries;
macTxFSM_status = LRWPAN_STATUS_MAC_INPROGRESS;
}
a_phy_service.cmd = LRWPAN_SVC_PHY_TX_DATA;
phyDoService();
}
//might be able to simplify this later.
static void macRxFSM(void){
MACPKT *pkt;
BYTE cmd;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -