📄 zmac.c
字号:
#include "zMAC.h"
#if defined(I_AM_END_DEVICE)
static SM_ASSOCIATION smAssociation;
// Running count of transmit retries used to association/disassociation
BYTE macFrameRetryCount;
#endif
// MAC Module state info.
MAC_STATE macState;
// Potential coordinator description - used when Associate process is started.
PAN_DESC PANDesc;
// Number of coordinators found operating in radius.
BYTE PANDescCount;
// Current channel of operation.
BYTE macCurrentChannel;
// Running counter of MAC frame DSN.
BYTE macDSN;
BYTE lastMACDSN;
// Length of transmit packet that is being current loaded.
BYTE macPacketLen;
// MAC address info.
NODE_INFO macInfo;
// Coordinator address info.
NODE_INFO macCoordInfo;
// A temp NODE_INFO to store out going commands from the MAC layer
NODE_INFO macDestInfo;
// RF channel energy as of last energy scan.
BYTE macCurrentEnergy;
// Current MAC frame header.
MAC_HEADER macCurrentFrame;
// Array of recently transmitted frames that are yet to be acknowledged
// by remote nodes.
MAC_FRAME_STATUS macFrameStatusQ[MAX_MAC_FRAME_STATUS];
BYTE macFrameStatusQLen;
// Tick value used to calculate timeout conditions.
TICK macStartTick;
// Handle to a frame - used by many command state machines
HFRAME hFrame;
#define PHYBeginTxFIFOAccess() { PHYBegin(); PHYSelectTxFIFO(); }
#define PHYEndTxFIFOAccess() PHYEnd()
#define PHYPutTxData(v) PHYPut(v)
static HFRAME AddDSNInQueue(BYTE dsn);
static void UpdateQueue(BYTE dsn);
static void TransmitIt(void);
static BOOL MACGetHeader(void);
static void MACSendBeaconReq(void);
static void MACSendBeacon(void);
static BOOL MACProcessBeacon(void);
static void MACSendAck(ACK_TYPE ack);
// Only coordinator will process orphan notice.
// A orphan notice is said to be valid if there is no data bytes in addition to
// the command identifier itself.
#define MACProcessOrphanNotice() (macCurrentFrame.frameLength == 0)
/*********************************************************************
* Function: void MACInit(void)
*
* PreCondition: macInfo.longAddr must be initialized with
* desired MAC address.
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Initializes data variables used by MAC module.
*
* Note: None
********************************************************************/
void MACInit(void)
{
memset((void*)macFrameStatusQ, 0x00, sizeof(macFrameStatusQ));
macFrameStatusQLen = 0;
macCurrentFrame.Flags.Val = 0x00;
macState.Val = 0x00;
//du 读取地址
GetMACShortAddress(&macInfo.shortAddr);
GetMACAddress(&macInfo.longAddr);
//du 初始PAN ID = 0xffff
MACSetPANIdLSB(0xff);
MACSetPANIdMSB(0xff);
}
BOOL MACIsIdle()
{
return (MACIsPutReady() && (macFrameStatusQLen == 0));
}
/*********************************************************************
* Function: void MACEnable(void)
*
* PreCondition: macInfo.longAddr must be initialized with
* desired MAC address.
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Enables PHY regulator and registers.
*
* Note: None
********************************************************************/
void MACEnable(void)
{
// Power up the PHY's internal regulator
PHYEnable();
// Initialize the PHY's registers/wait for it's oscillator to
// become stable. In the event the PHY malfunctions for too long
// the watchdog timer will cause a reset to occur here.
while( !PHYInit() );
MACUpdateAddressInfo();
PHYSetChannel(PHYGetChannel());
macState.bits.bIsEnabled = TRUE;
}
/*********************************************************************
* Function: void MACISR(void)
*
* PreCondition: MACInit() is previously called.
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Determines if a frame has completed transmission
* or not.
*
* Note: None
********************************************************************/
void MACISR(void)
{
if ( macState.bits.bIsTxBusy )
macState.bits.bIsTxBusy = FALSE;
}
/*********************************************************************
* Function: BYTE MACGet(void)
*
* PreCondition: MACIsGetReady() == TRUE
*
* Input: None
*
* Output: Byte that was read
*
* Side Effects: None
*
* Overview: Retrives one bytes from RF RX buffer.
*
* Note: Caller must make sure that RX buffer contains
* at least one byte calling MACIsGetReady()
********************************************************************/
BYTE MACGet(void)
{
BYTE v;
// Start PHY RX buffer access.
PHYBegin();
PHYSelectRxFIFO();
v = PHYGet();
PHYEnd();
// Update current frame length.
macCurrentFrame.frameLength--;
// Now return it.
return v;
}
/*********************************************************************
* Function: void MACPutArray(BYTE *v, BYTE len)
*
* PreCondition: MACIsPutReady() == TRUE
*
* Input: b - Buffer that is to be loaded.
* len - Number of bytes to get
*
* Output: None
*
* Side Effects: None
*
* Overview: Loads given bytes into RF TX buffer.
*
* Note: None
********************************************************************/
void MACPutArray(BYTE *v, BYTE len)
{
// Start RX TX buffer access.
PHYBeginTxFIFOAccess();
// Copy all given bytes into TX buffer.
while( len-- )
{
PHYPutTxData(*v);
v++;
// Keep count of current TX frame length.
macPacketLen++;
}
// Conclude RX TX buffer access.
PHYEndTxFIFOAccess();
}
/*********************************************************************
* Function: BOOL MACIsPutReady(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Determines if it is okay to load new tx frame
* into RF TX buffer.
*
* Note: None
********************************************************************/
BOOL MACIsPutReady(void)
{
// The transmitter is said to be ready when
// 1. It has finished previous transmission,
// 2. We are part of a network
// 3. Enabled.
// 4. Ack queue is not full.
return (macState.bits.bIsTxBusy == FALSE &&
macState.bits.bIsAssociated == TRUE &&
macState.bits.bIsEnabled == TRUE &&
macFrameStatusQLen < MAX_MAC_FRAME_STATUS);
}
/*********************************************************************
* Function: void MACPut(BYTE v)
*
* PreCondition: MACIsPutReady() == TRUE
*
* Input: v - A byte to put
*
* Output: None
*
* Side Effects: None
*
* Overview: Copies given byte into RF TX buffer and increments
* write pointer.
*
* Note: None
********************************************************************/
void MACPut(BYTE v)
{
// Put given byte into TXFIFO
PHYBeginTxFIFOAccess();
PHYPutTxData(v);
PHYEndTxFIFOAccess();
// Maintain length so that we update header.
macPacketLen++;
}
/*********************************************************************
* Function: HFRAME MACFlush(void)
*
* PreCondition: MACIsPutReady() == TRUE and
* a valid TX frame is constructured using
* MACPutHeader() and MACPut()
*
* Input: None
*
* Output: HFRAME_INVALID if an Ack wasn't requested or the
* DSN queue was full. Otherwise, the handle to the
* DSN queue entry is returned which can later be
* used when the Ack frame arrives.
*
* Side Effects: None
*
* Overview: Sets the tx frame length, marks the tx frame
* as ready to be transmitted.
* If this frame requires ack from remote node,
* an entry is made into DSN queue so that
* we can match future ACK with this frame.
*
* Note: None
********************************************************************/
HFRAME MACFlush(void)
{
hFrame = HFRAME_INVALID;
// Remember that current message is in transmit buffer.
macState.bits.bIsTxBusy = TRUE;
if ( macCurrentFrame.Flags.bits.bToBeQueued )
hFrame = AddDSNInQueue(macDSN);
macCurrentFrame.Flags.bits.bToBeQueued = FALSE;
// First, update the packet length.
PHYBegin();
PHYSelectTxRAM();
PHYPut(macPacketLen);
// Terminate RAM access
PHYEnd();
// Now transmit it.
TransmitIt();
// Forget packet length.
macPacketLen = 0;
return hFrame;
}
static void TransmitIt(void)
{
BYTE v;
BYTE backOffCycles;
// Wait until transceiver is idle
//while( !PHYIsIdle() );
// To creat randomness in initial backoff, we will use
// LSB of current tick counter.
backOffCycles = (BYTE)TickGet();
// Remember that a message is being transmitted.
macState.bits.bIsTxBusy = TRUE;
// Turn on RX
PHYSetTRXState(PHY_TRX_RX_ON);
// Wait for RSSI to become valid
PHYBegin();
do
{
PHYPut(STROBE_SNOP);
v = PHYGet();
if ( v & 0x02 )
break;
} while(1);
PHYEnd();
PHYBegin();
do
{
PHYTx();
v = PHYGet();
PHYPut(STROBE_SNOP);
v = PHYGet();
// If transmission was started, break out of this loop.
if ( v & 0x08 )
break;
//TODO(DF9): CSMA-CA back-off needed
// Else, need to back-off - not quite IEEE compliant.
backOffCycles <<= 1;
// Reinitialize backoff time if we reach 0 or 0xff value.
if ( backOffCycles == 0x00 || backOffCycles == 0xff )
backOffCycles = (BYTE)TickGet();
// Now wait until backoff cycles expire.
v = backOffCycles;
while( v-- );
} while( 1 );
PHYEnd();
// Tell application that we have just transmitted a frame.
AppMACFrameTransmitted();
}
/*********************************************************************
* Function: void MACUpdateTimeoutFlags( void )
*
* PreCondition: MACInit() is called
*
* Input: None
*
* Output: None
*
* Side Effects: Frame timeout flags are updated
*
* Overview: This function goes through the frame queue and
* checks each frame that is currently waiting for
* an acknowledge to see if it has timed out. It
* then calls the application call-back.
*
* Note: None
********************************************************************/
void MACUpdateTimeoutFlags( void )
{
BYTE i;
MAC_FRAME_STATUS *pMACFrameStatus;
pMACFrameStatus = macFrameStatusQ;
for ( i = 0; i < sizeof(macFrameStatusQ)/sizeof(macFrameStatusQ[0]); i++, pMACFrameStatus++ )
{
if ( pMACFrameStatus->Flags.bits.bIsInUse )
{
if ( !pMACFrameStatus->Flags.bits.bIsConfirmed )
{
if ( TickGetDiff(TickGet(), pMACFrameStatus->lastTick) >= MAC_ACK_WAIT_DURATION )
{
pMACFrameStatus->Flags.bits.bIsTimedOut = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -