📄 zmac_receive.c
字号:
BYTE MACGet(void)
{
BYTE v;
// Start PHY RX buffer access.
PHYBegin();
PHYSelectRxFIFO();
v = PHYGetMac();
PHYEnd();
// Update current frame length.
macCurrentFrame.frameLength--;
// Now return it.
return v;
}
/*********************************************************************
* Function: void MACCopyRxPacketToRx(void)
*
* PreCondition: MACIsGetReady() == TRUE &&
* MACIsPutReady() == TRUE
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Copies remaining RX data bytes into current
* TX buffer.
*
* Note: None
********************************************************************/
void MACCopyRxPacketToTx(void)
{
// Copy reminaing RX to TX buffer.
while( macCurrentFrame.frameLength )
MACPut(MACGet());
}
/*********************************************************************
* 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: void MACTxFrameEnqeue(void)
*
* PreCondition: None
*
* Input: None
*
* Output: None
*
* Side Effects: None
*
* Overview: Enqueues current tx frame to tx indirect buffer.
*
* Note: This function is available when MAC_USE_TX_INDIRECT_BUFFER
* is defined (i.e. Coordinator mode)
********************************************************************/
#if defined(MAC_USE_TX_INDIRECT_BUFFER)
void MACTxFrameEnqueue(void)
{
// Set frame length into current tx state buffer.
*(txIndirectBuffer[currentTxIndirectBuffer].pBuffer) = macPacketLen;
// Remember when we enqueue this frame so that we can discard it if it
// were to stay for long time.
txIndirectBuffer[currentTxIndirectBuffer].lastTick = TickGet();
// Remember current macDSN for this queued frame so that we can match its ACK
txIndirectBuffer[currentTxIndirectBuffer].frameDSN = macDSN;
// Once we finish loading tx indirect buffer,
// reset the setting so that next tx operation
// will be on RF chip buffer unless explictly changed by caller.
macState.bits.bUseTxRAM = FALSE;
}
#endif
/*********************************************************************
* 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();
#if defined(WIN32)
break;
#else
PHYPut(STROBE_SNOP);
v = PHYGet();
// If transmission was started, break out of this loop.
if ( v & 0x08 )
break;
#endif
// 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: static void _MACIndirectTransmit(
* TX_INDIRECT_BUFFER *pIndirectTxBuffer)
*
* PreCondition: None
*
* Input: pIndirectTxBuffer - pointer to the frame in
* txIndirectBuffer to transmit
*
* Output: None
*
* Side Effects: None
*
* Overview: Transmits current indirect tx buffer
*
* Note: None
********************************************************************/
#if defined(MAC_USE_TX_INDIRECT_BUFFER)
static void _MACIndirectTransmit(TX_INDIRECT_BUFFER *pIndirectTxBuffer)
{
// Get the frame length from the buffer.
pCurrentTxIndirectData = pIndirectTxBuffer->pBuffer;
macPacketLen = *pCurrentTxIndirectData++;
// Clear TXFIFO
PHYBegin();
PHYFlushTx();
PHYEnd();
// Load the entire frame starting from the frame length byte.
PHYBegin();
PHYSelectTxFIFO();
PHYPut(macPacketLen);
// macPacketLen includes the two checksum bytes. Since checksum bytes
// are automatically generated by the RF chip, we will reduce macPacketLen
// by two and let RF chip stuff checksum byte at the end.
macPacketLen -= 2;
// Load entire frame into RF chip buffer.
while( macPacketLen-- )
{
PHYPut(*pCurrentTxIndirectData++);
};
PHYEnd();
// A indirect frame may be transmitted multiple times.
// If this is the first time, add that in DSN queue and remember
// the queue handle so that we can check for ack status for this frame.
if ( !pIndirectTxBuffer->Flags.bIsSent )
{
pIndirectTxBuffer->Flags.hFrame =
AddDSNInQueue(pIndirectTxBuffer->frameDSN);
// Remember that this frame is transmitted at least once.
pIndirectTxBuffer->Flags.bIsSent = TRUE;
}
// Remember when we transmitted this so that we can determine when to
// discard it if we do not receive any ack.
//TODO: HS - I think this is redundant information. A tick count is stored in macFrameStatusQ[pIndirectTxBuffer->Flags.hFrame] as well.
pIndirectTxBuffer->lastTick = TickGet();
// Decrement the transmit attempt counter so that we can determine
// when to discard it if we never receive an ack.
macFrameStatusQ[pIndirectTxBuffer->Flags.hFrame].retryCount--;
// Now transmit it.
TransmitIt();
// Forget packet length.
macPacketLen = 0;
}
#endif
/*********************************************************************
* Function: BOOL MACTask(void)
*
* PreCondition: MACInit() is called
*
* Input: None
*
* Output: TRUE - If Processing is complete
* FALSE - If further processing is required
*
* Side Effects: None
*
* Overview: If previous frame is processed, it checks
* for new RX frame.
* Fetches the header and determiens if it is valid
* Automatically sends ACK if remote node has
* requested it.
* Also performs some other automatic processing
* based on the frame type.
* If there is no frame in buffer, it goes through
* DSN queue and calculates timeout for unack'ed
* TX frames.
*
* Note: This function must be called as many times as
* possible to keep handling MAC frames.
********************************************************************/
BOOL MACTask(void)
{
MAC_FRAME_STATUS *pCurrentFrame;
// If there was an overflow, handle it.
// Since this is a half-duplex and the way CC2420 indicates RX FIFO OVERFLOW,
// check for overflow condition only when RF is not actively transmitting a packet.
if ( macState.bits.bIsTxBusy == FALSE )
{
if ( PHYProcessRxOverflow() )
{
DEBUG_OUT("MAC: A receive overflow was detected and removed.\r\n");
}
}
// Do not process any new frame until current one is all processed.
if ( MACIsGetReady() )
return TRUE;
// Continue only if there is a new frame in buffer.
if ( !_MACIsGetReady() )
{
// Get pointer to current frame that we want to operate on.
pCurrentFrame = &macFrameStatusQ[currentQueueItem];
// Now prepare for next item.
currentQueueItem++;
// Wrap the number if we reached the end of queue.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -