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

📄 spp.c

📁 1:打开IAR开发环境
💻 C
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************
Filename:     spp.c
Target:       cc2430
Revised:      16/12-2005
Revision:     1.0
******************************************************************************/
#include <string.h>
#include "cul.h"
#include <stdio.h>

// protos
void rxCallBack(void);
void ackTimeout(void);
BOOL ackReceived(BYTE sourceAddress);
void sendAck(SPP_RX_STRUCT* receivedPacket);
void waitForAck(void);


static DMA_DESC* dmaTx;          // pointer to the DMA descriptor for transmit.
static DMA_DESC* dmaRx;          // pointer to the DMA descriptor for receive.
static BYTE dmaNumberTx = 0;     // number indicating which DMA channel is used for transmit.
static BYTE dmaNumberRx = 0;     // number indicating which DMA channel is used for receive.
static BYTE myAddress;
volatile BYTE sppRxStatus = 0;
volatile BYTE  sppTxStatus = 0;
static BYTE pAckBuffer[7];
static SPP_TX_STRUCT* pAckData;
static volatile UINT8 retransmissionCounter;
static UINT8 ackTimerNumber;
static FUNCTION* rxCallBackFunction;


//-----------------------------------------------------------------------------
// See cul.h for a description of this function.
//-----------------------------------------------------------------------------
//设置用户指定的回调函数,在接收到一个正确的数据包死运行
//通过这个函数可以用程序来改变正确接收数据包后的动作。
//callBackFunction 用户指定的函数
//rxCallBackFunction 指向 FUNCTION 的全局变量指针变量
void sppSetRxCallBackFunction(FUNCTION* callBackFunction)
{
   rxCallBackFunction = callBackFunction;
} // Ends sppSetRxCallBackFunction()


//发送应答
//SPP_RX_STRUCT 定义在 cul.h
//SFR(  RFD       ,  0xD9  )   //  RF Data 定义在ioCC2430.h
// myAddress 全局变量
// ACK cul.h 中宏定义
// ISTXON hal.h 中宏定义
// srcAddress 源地址
void sendAck(SPP_RX_STRUCT* receivedPacket)
{
   RFD = SPP_HEADER_AND_FOOTER_LENGTH + SPP_ACK_LENGTH;
   RFD = receivedPacket->srcAddress;
   RFD = myAddress;
   RFD = ACK;
   RFD = 0;
   RFIF &= ~IRQ_TXDONE;
   ISTXON;
   while(!(RFIF & IRQ_TXDONE));

   return;
}

//------------------------------------------------------------------------------------------------------
// void rxCallBack(...)
//
//  Description:
//      This function is called by the interrupt routine when the Rx DMA channel
//      finishes the data transfer. The received packet's destination address
//      is checked. If not addressed to this node, or if the CRC value is not
//      correct, the packet is erased. An ACK is sent if the packet
//      tells to. A user defined callback function may is run if set (set
//      with setRxCallBackFunction())
//在Rx DAM  通道完成数据传输后由中断程序调用。检查接收包掉的目的地址,如果地址不是
//这个节点的,或CRC值是错误的,包装将被擦除。如果数据包被告知将发送一个应答。一个用户定义的回调函数可以运行如果定义了的话。
//  Arguments:
//      void
//
//  Return value:
//      void
//-----------------------------------------------------------------------------
//#define  RXFIFOCNT   XREG( 0xDF53 )  /*  Receive FIFO Count 定义在ioCC2430.h
// ISFLUSHRX 清 RX FIFO 命令滤波. hal.h 命令滤波中定义
// GET_DMA_DEST(dmaRx) hal.h 中的宏定义,取得一个 DMA 通道的目标地址
// static DMA_DESC* dmaRx 指向设备 DMA 描述符的指针,全局变量.DMA_DESC DMA 配置结构。
//
void rxCallBack(void)
{
   SPP_RX_STRUCT __xdata* receivedPacket;
   BYTE res = FALSE;

   if(RXFIFOCNT > 0)
   {
      ISFLUSHRX;
      ISFLUSHRX;
   }

   // Investigating the received packet.
   // Checking the destination address and that the CRC is OK.
   // The message is ACK'ed if it tells to.
   receivedPacket = (SPP_RX_STRUCT __xdata*) GET_DMA_DEST(dmaRx);
   receivedPacket->payloadLength = receivedPacket->payloadLength-SPP_HEADER_AND_FOOTER_LENGTH; //减去头和尾长度

   if((receivedPacket->destAddress == myAddress) || (receivedPacket->destAddress == BROADCAST_ADDRESS)) //包目的地是本节点地址或广播地址
   {
      if(receivedPacket->payload[receivedPacket->payloadLength+1] & 0x80)	//CRC正确
      {
         if(receivedPacket->flags == ACK)	//收到了应答包
         {
            res = ackReceived(receivedPacket->srcAddress);
         }
         else		//收到普通数据包
         {
            sppRxStatus = PACKET_RECEIVED;		//ssp接收状态-收到数据包
            res = TRUE;
            if(receivedPacket->flags & DO_ACK)	//要求收到后发应答
            {
               sendAck(receivedPacket); 		//发应答
            }
            sppRxStatus = RX_COMPLETE;			//ssp接收状态-接收完成
            if(rxCallBackFunction)
            {
               rxCallBackFunction();			//调用用户指定回调函数
            }
         }
      }
   }

   if(res == FALSE)
   {
      ISFLUSHRX;	//清RX FIFO
      ISFLUSHRX;

      // rearming DMA channel
      DMA_ARM_CHANNEL(dmaNumberRx);
      RFIM |= IRQ_SFD;
      sppRxStatus = RX_WAIT;
   }
   return;
}   // ends rxCallBack




//-----------------------------------------------------------------------------
// void ackTimeout(...)
//
//  Description:
//      This function resends a packet if it is not ACK'ed by the recipient
//      within _ACK_TIMEOUT_ m-seconds. The message is resent _ACK_RETRIES_ times.
//      If the message remains un-ACK'ed, transmission is aborted and spp TX
//      status is set to DEST_UNREACHABLE.
//如果没有收到接收器返回的应答,将重新发送数据包
//  Arguments:
//      void
//
//  Return value:
//      void
//-----------------------------------------------------------------------------
// TIMER4_RUN() 宏函数在 hal.h 中定义
// #define ACK_RETRIES  3 在 hal.h 中的宏定义常数
void ackTimeout(void){
   culTimer4AdmClear(ackTimerNumber);

   if(pAckData != NULL)
   {
      if(retransmissionCounter < ACK_RETRIES)	//重发次数小于尝试接收应答次数
      {
         // Resending the message.
         pAckData->flags |= RETRANSMISSION;		//数据包标志-重发

         TIMER4_RUN(FALSE);						//停止定时器4

         sppSend(pAckData);						//发送数据包

         T4CNT = 0;								//定时器4计数清零
         TIMER4_RUN(TRUE);						//定时器4开始运行

         retransmissionCounter++;
      }
      else
      {
         // The packet has been resent too many times. Assuming that the node is unreacheble.
         pAckData = 0;
         retransmissionCounter = 0;
         sppTxStatus = DEST_UNREACHABLE;		//ssp发送状态-不能完成
         RFIM &= ~IRQ_FIFOP;
      }
   }
   return;
} // ends ackTimeout




//-----------------------------------------------------------------------------
// See cul.h for a description of this function.
// 初始化简单的数据包装协议Simple Packet Protocol (SPP)
// 从 DMA 管理器申请两个 DMA 通道,用于分别从 Rx FIFO 和 Tx FIFO 传输数据。定时器4
// 管理器同样被设置,这个单元用于在数据包发送后接收器在一定时间内没有返回应答时
// 产生中断。无线部分配置为发送,工作在特定的频率,在发送时自动计算和插入和检查CRC值。
//-----------------------------------------------------------------------------
BOOL sppInit(UINT32 frequency, BYTE address){
   BYTE res = 0;
   BOOL status = TRUE;

   sppSetAddress(address);

   // Clearing the states of the spp.
   sppTxStatus = TX_IDLE;	//在 cul.h TX 和 RX 状态标志部分宏定义
   sppRxStatus = RX_IDLE;	//同上
   retransmissionCounter = 0;
   ackTimerNumber = 0;
   pAckData = 0;

   // Clearing the RF interrupt flags and enable mask and enabling RF interrupts
   RFIF = 0;
   RFIM = 0;
   INT_SETFLAG(INUM_RF,INT_CLR);
   INT_ENABLE(INUM_RF,INT_ON);

   // Setting the frequency and initialising the radio
   res = halRfConfig(frequency); //在rfconfig.c
   if(res == FALSE){
      status = FALSE;
   }

   // Setting the number of bytes to assert the FIFOP flag
   IOCFG0 = 7;

   INT_SETFLAG(INUM_RFERR, INT_CLR);
   INT_ENABLE(INUM_RFERR, INT_ON);

   // Flushing both Tx and Rx FiFo. The flush-Rx is issued twice to reset the SFD.
   // Calibrating the radio and turning on Rx to evaluate the CCA.
   // SFD 开始帧定界符
   SRXON;
   SFLUSHTX;
   SFLUSHRX;
   SFLUSHRX;
   STXCALN;
   ISSTART;


   // Using the timer 4 administrator to generate interrupt to check if a message is unacked...
   culTimer4AdmInit();

   // Initialising the DMA administrator
   culDmaInit();

   // Requesting a DMA channel for transmit data. No callback function is used. Instead the TX_DONE
   // interrupt is used to determine when a transfer is finished. Configuring the DMA channel for
   // transmit. The data address and length will be set prior to each specific transmission.
   dmaTx = culDmaAllocChannel(&dmaNumberTx, 0);
   if((dmaNumberTx == 0) || (dmaNumberTx > 4)){
      status = FALSE;
   }

   culDmaToRadio(dmaTx, 0, 0, FALSE);

   // Requesting a DMA channel for receiving data. Giving the address of the callback function.
   // Configuring the DMA channel for receive. The data address will be set prior to each specific
   // reception.
   dmaRx = culDmaAllocChannel(&dmaNumberRx, &rxCallBack);
   if((dmaNumberRx == 0) || (dmaNumberRx > 4)){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -