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

📄 rf_remote_unit.c

📁 reference about wireless design which is helpful to everyone
💻 C
📖 第 1 页 / 共 2 页
字号:
/// \addtogroup module_rfru
/// @{
#include "cc2511_app_ex_lib_headers.h"

BOOL __xdata rfTimeout; //used both by rf isr and timer 2 isr
static BYTE __xdata rfrdAckPkt[10];//must be 10 to hold CRC
static RFRU_DATA __xdata rfruData;/// internal data

//Some functions only used locally in this file, do not call from anywhere else.
static void rfruHandleUnwantedPacket(void);
static void rfruHandleTimeout(void);
static void rfruSBReq(void);

/**
 * \brief Must be called once before any other functions in the rf_usb_dongle module.
 *
 * Initiates radio and everything associated with it. Does not start RX or TX.
 *
 * \note This function calculates the timeout settings for the mac timer based on the
 * CLOCKON.TICKSPD setting. Do not change CLOCKON.TICKSPD after this function has been called
 *
 * \param[in]  bufferSize \n
 * Set the size of the buffers that will later be given to the radio with the \ref rfudStartReceive() function.
 * The radio will use this number to make sure that it does not write outside the buffers.
 */
BOOL rfruInit(BYTE bufferSize)
{
   BYTE i, temp;
   //setup radio, and calibrate
   halRfConfig(2433000);
   //calibrate when going to RX/TX
   MCSM0 = 0x10;
   //setup radio
   rfruData.maxPacketLength = bufferSize - 3;
   PKTLEN = rfruData.maxPacketLength;
   MCSM1 = 0x00;

    //set rx ack packet Ptr
   rfruData.pRxAckPkt = (RF_PACKET __xdata *) rfrdAckPkt;
   rfruData.rfTimeout = FALSE;
   rfruData.pTxAckPkt.length = 6;//length of tx ack packet
   rfruData.pTxDataRequestPkt.length = 6;//length of data request packet
   rfruData.pTxDataRequestPkt.flag = RF_DATA_REQUEST;

   for(i = 0; i < RF_SEQUENCE_BYTES; i++)
   {
      rfruData.pTxSequenceBits[i] = 0;
      rfruData.pRxSequenceBits[i] = 0;
   }

   //setup all fields in DMA descriptor for RX that newer change
   SET_WORD(rfruData.dmaFromRadioDesc.SRCADDRH, rfruData.dmaFromRadioDesc.SRCADDRL, &X_RFD);
   rfruData.dmaFromRadioDesc.VLEN       = VLEN_1_P_VALOFFIRST_P_2;
   SET_WORD(rfruData.dmaFromRadioDesc.LENH, rfruData.dmaFromRadioDesc.LENL, bufferSize);
   rfruData.dmaFromRadioDesc.WORDSIZE   = WORDSIZE_BYTE;
   rfruData.dmaFromRadioDesc.TMODE      = TMODE_SINGLE;
   rfruData.dmaFromRadioDesc.TRIG       = DMATRIG_RADIO;
   rfruData.dmaFromRadioDesc.DESTINC    = DESTINC_1;
   rfruData.dmaFromRadioDesc.SRCINC     = SRCINC_0;
   rfruData.dmaFromRadioDesc.IRQMASK    = IRQMASK_DISABLE;
   rfruData.dmaFromRadioDesc.M8         = M8_USE_8_BITS;
   rfruData.dmaFromRadioDesc.PRIORITY   = PRI_GUARANTEED;

   //setup all fields in DMA descriptor for TX that newer change
   SET_WORD(rfruData.dmaToRadioDesc.DESTADDRH, rfruData.dmaToRadioDesc.DESTADDRL, &X_RFD);
   rfruData.dmaToRadioDesc.VLEN       = VLEN_1_P_VALOFFIRST;
   SET_WORD(rfruData.dmaToRadioDesc.LENH, rfruData.dmaToRadioDesc.LENL, 256);
   rfruData.dmaToRadioDesc.WORDSIZE   = WORDSIZE_BYTE;
   rfruData.dmaToRadioDesc.TMODE      = TMODE_SINGLE;
   rfruData.dmaToRadioDesc.TRIG       = DMATRIG_RADIO;
   rfruData.dmaToRadioDesc.DESTINC    = DESTINC_0;
   rfruData.dmaToRadioDesc.SRCINC     = SRCINC_1;
   rfruData.dmaToRadioDesc.IRQMASK    = IRQMASK_DISABLE;
   rfruData.dmaToRadioDesc.M8         = M8_USE_8_BITS;
   rfruData.dmaToRadioDesc.PRIORITY   = PRI_GUARANTEED;

   rfruData.radio_state = RFRU_STATE_IDLE;
   RFIF &= ~(IRQ_DONE | IRQ_TXUNF | IRQ_RXOVF);
   RFIM |= (IRQ_DONE | IRQ_TXUNF | IRQ_RXOVF);
   INT_ENABLE(INUM_RF, INT_ON);

   // setup timer 2
   halSetTimer2Period(5000, &temp, &i);
   rfruData.timer2Cnt = temp;
   T2CT = 0;
   T2CTL = 0x10;
   INT_ENABLE(INUM_T2, INT_ON);
   INT_GLOBAL_ENABLE(INT_ON);
   return TRUE;
}

/**
 * \brief Used to check if radio is busy sending or receiving a packet.
 *
 * \return  BOOL \n
 * If TRUE is returned, the radio is in IDLE and the application can start a new packet transmission.
 */
BOOL rfruIsRadioReady(void)
{
   return (rfruData.radio_state == RFRU_STATE_IDLE);
}



/**
 * \brief Used to send a \ref RF_DATA_PACKET to the dongle.
 *
 * After successfully calling this function with the \ref RF_ACK_REQUEST flag set
 * one of the three following \ref RF_EVENT will occur.
 * \li \ref RFRU_EVENT_ACK_RECEIVED - An ACK packet is received, indicating that the dongle has successfully received the packet.
 * \li \ref RFRU_EVENT_NACK_RECEIVED - An NACK packet is received, indicating that the packet did reach the dongle,
 * but the dongle was unable or unwilling to accept it. The application must decide what to do,
 * but in most cases it should wait a short time and then attempt to retransmit the packet.
 * \li \ref RFUD_EVENT_ACK_TIMEOUT - No ACK/NACK packet is received within the ack timeout period.
 * Indicating that either the \ref RF_DATA_PACKET did not reach the dongle,
 * or the \ref RF_ACK / \ref RF_NACK packet was lost on the way back.
 *
 * If the \ref RF_ACK_REQUEST flag is not set, the packet will be sent, but no \ref RF_EVENT will occur.
 * \ref rfruIsRadioReady() can be used to check if radio is ready before calling this function.
 *
 * \param[in]  pTxPacket \n
 * A pointer to the \ref RF_DATA_PACKET.
 * In the packet the following fields/flags must be set by the application before calling this function:
 * \li \ref RF_PACKET.length
 * \li \ref RF_PACKET.destAddress
 * \li \ref RF_PACKET.flag only the \ref RF_ACK_REQUEST and \ref RF_DATA_PENDING flags.
 * \li \ref The packets data payload.
 * All other fields will be set automatically by the rfru module before sending the packet.
 *
 * \return BOOL \n
 * If radio is ready, it will return TRUE and start the transmission.
 * Will return FALSE and refuse to handle this call if radio is busy sending or receiving another packet.
 */
BOOL rfruSendDataPacket(RF_PACKET __xdata * pTxPacket)
{
   if(rfruData.radio_state != RFRU_STATE_IDLE) return FALSE;

   //copy source and network address to the packet
   pTxPacket->sourceAddress = rfruData.pTxAckPkt.sourceAddress;
   pTxPacket->networkAddress[0] = rfruData.pTxAckPkt.networkAddress[0];
   pTxPacket->networkAddress[1] = rfruData.pTxAckPkt.networkAddress[1];
   pTxPacket->networkAddress[2] = rfruData.pTxAckPkt.networkAddress[2];

   //set sequence bit
   if(RF_GET_SEQ_BIT(rfruData.pTxSequenceBits, pTxPacket->destAddress)) { pTxPacket->flag &= ~RF_SEQUENCE_BIT; }
   else { pTxPacket->flag |= RF_SEQUENCE_BIT; }
   //set packet type bit
   pTxPacket->flag &= ~RF_PACKET_TYPE;
   pTxPacket->flag |= RF_DATA_PACKET;
   //set if rf state (ack or no ack expected)
   if(pTxPacket->flag & RF_ACK_REQUEST) {
      rfruData.radio_state = RFRU_STATE_TX_PKT_EXPECT_ACK;
      //Setup DMA descriptor for reception of the ack packet
      rfruData.pRxAckPkt->length = 0;
      SET_WORD(rfruData.dmaFromRadioDesc.DESTADDRH, rfruData.dmaFromRadioDesc.DESTADDRL, (BYTE __xdata *) rfruData.pRxAckPkt);
   }
   else { rfruData.radio_state = RFRU_STATE_TX_PKT_NO_ACK; }
   rfruData.lastPktSentTo = pTxPacket->destAddress;
   SET_WORD(rfruData.dmaToRadioDesc.SRCADDRH, rfruData.dmaToRadioDesc.SRCADDRL, (BYTE __xdata *) pTxPacket);
   RF_START_DMA_TX(&rfruData.dmaToRadioDesc);
   STX();
   return TRUE;
}


/**
 * \brief Used to send a \ref RF_DATA_REQUEST to the CC2511 USB Dongle,
 * if the dongle has a \ref RF_DATA_PACKET ready it will send it when receiving this request.
 *
 * After successfully calling this function one of the three following \ref RF EVENT will occur.
 *
 * \li RFRU_EVENT_DATA_PACKET_RECEIVED - A new data packet is received and ready to be read from the rx buffer.
 * If the RF_ACK_REQUEST flag is set, it will automatically be acked.
 *
 * \li rfEvent \ref RFRU_EVENT_DATA_REQUEST_NACKED - An NACK packet is received, indicating that the dongle does not
 * have any data packets to this unit. The \ref RF_NACK packet can be found in the rx buffer.
 *
 * \li \ref RFRU_EVENT_DATA_PACKET_REQUEST_TIMEOUT - No reply is received within timeout period.
 * Indicating that either the \ref RF_DATA_REQUEST did not reach the dongle
 * or the reply packet was lost on the way back. The rx buffer is empty.
 *
 * \ref rfruIsRadioReady() can be used to check if radio is ready before calling this function.
 *
 * \param[in] destAdr \n
 * Device address of the dongle the request should be sent to. (Network address is appended automatically)
 *
 * \param[in]  pRxPacketBuffer \n
 * A pointer to the rx buffer where the received packet should be placed.
 *
 * \return BOOL \n
 * Will return FALSE and refuse to handle this call if radio is busy sending or receiving another packet.
 * If radio is ready, it will return TRUE and start the transmission.
 */
BOOL rfruSendDataRequest(BYTE destAdr, RF_PACKET __xdata * pRxPacketBuffer)
{
   if(rfruData.radio_state != RFRU_STATE_IDLE) return FALSE;
   rfruData.pTxDataRequestPkt.destAddress = destAdr;
   rfruData.lastPktSentTo = destAdr;
   rfruData.radio_state = RFRU_STATE_TX_DATA_REQ;
   //Setup DMA descriptor for reception of the reply packet
   pRxPacketBuffer->length = 0;
   SET_WORD(rfruData.dmaFromRadioDesc.DESTADDRH, rfruData.dmaFromRadioDesc.DESTADDRL, (BYTE __xdata *) pRxPacketBuffer);
   rfruData.pRxPacket = pRxPacketBuffer;
   //setup DMA for TX
   SET_WORD(rfruData.dmaToRadioDesc.SRCADDRH, rfruData.dmaToRadioDesc.SRCADDRL, (BYTE __xdata *) &rfruData.pTxDataRequestPkt);
   RF_START_DMA_TX(&rfruData.dmaToRadioDesc);
   STX(); //start TX
   return TRUE;
}


/**
 * \brief Used to send a \ref RF_BIND_REQUEST to the dongle, attempting to bind to it.
 *
 * The remote unit will attempt to bind to the dongle the number of times defined in \ref RF_BIND_REQUEST_RETRIES.
 * After successfully calling this function one of the two following \ref RF EVENT will occur.
 *
 * \li RFRU_EVENT_BIND_SUCCESSFULL - The unit has completed a successful bind to the dongle.
 * The device address of the dongle is found in the eventData parameter in \ref rfruHookRfEvent().
 * The address assigned to this unit can be found by calling \ref rfruGetMyDeviceAddress() and \ref rfruGetNetworkAddress().
 *
 * \li \ref RFRU_EVENT_BIND_REQUEST_TIMEOUT - No reply from the dongle received within timeout period after attempting to bind.
 *
 * \param[in] preferredAddress \n
 * The device address this unit would prefer to be assigned, if application has no preferred address set this parameter to 0x00.
 */
void rfruSendBindRequest(BYTE preferredAddress)
{
   rfruData.bindRequestRetries = 0;
   rfruStopRadio();
   if((preferredAddress != 0) && (preferredAddress != 0xFF)) {
      rfruSetMyAddress(0xFF, 0xFF, 0xFF, preferredAddress);
   } else {
      rfruSetMyAddress(0xFF, 0xFF, 0xFF, 0xFF);
   }
   PKTCTRL1 |= 0x03;//Address check, 0 (0x00) and 255 (0xFF) broadcast
   rfruSBReq();
}


/**
 * \brief Used to put the radio in IDLE.
 *
 * This function is used when the application want to stop the radio.
 * Any ongoing transmissions, both RX and TX will be aborted.
 */
void rfruStopRadio(void)
{
   SIDLE();//set radio to idle
   STOP_RADIO_TIMEOUT();
   rfruData.rfTimeout = FALSE;
   rfruData.radio_state = RFRU_STATE_IDLE;
   DMA_ABORT_CHANNEL(0);
}



/**
 * \brief Can be used to set the address of this device.
 *
 * Use only if application both knows the address it should use,
 * and knows that the dongle will accept packets from this address.
 * This function is called automatically from the rfrd module each time a successful bind has occurred.
 * E.g. if \ref rfruSendBindRequest() is used to bind to the dongle, the application should not call this function.
 *
 * \param[in]  networkAddress0 \n
 * Most significant byte in the network address
 *
 * \param[in]  networkAddress1 \n
 * Second most significant byte in the network address
 *
 * \param[in]  networkAddress2 \n
 * Least significant byte in the network address
 *
 * \param[in]  deviceAddress \n
 * Device address.
 */
void rfruSetMyAddress(BYTE networkAddress0, BYTE networkAddress1, BYTE networkAddress2, BYTE deviceAddress)
{
   rfruData.pNetworkAddress[0] = networkAddress0;
   rfruData.pNetworkAddress[1] = networkAddress1;
   rfruData.pNetworkAddress[2] = networkAddress2;

   //setup ack packet
   rfruData.pTxAckPkt.sourceAddress = deviceAddress; //source address
   rfruData.pTxAckPkt.networkAddress[0] = networkAddress0; //network(2) address
   rfruData.pTxAckPkt.networkAddress[1] = networkAddress1; //network(1) address
   rfruData.pTxAckPkt.networkAddress[2] = networkAddress2; //network(0) address

   //  rfruData.pTxDataRequestPkt
   rfruData.pTxDataRequestPkt.sourceAddress = deviceAddress; //source address
   rfruData.pTxDataRequestPkt.networkAddress[0] = networkAddress0; //network(2) address
   rfruData.pTxDataRequestPkt.networkAddress[1] = networkAddress1; //network(1) address
   rfruData.pTxDataRequestPkt.networkAddress[2] = networkAddress2; //network(0) address

   //setup radio hardware address filter
   ADDR = deviceAddress;
   PKTCTRL1 &= ~0x03;
   PKTCTRL1 |= 0x01;//Address check, no broadcast
}

/**
 * \brief Returns the device address of this device.
 *
 * \param[out]  BYTE \n
 * The device address of this device, returns 0 if no address is yet assigned.
 */
BYTE rfruGetMyDeviceAddress(void)
{
   return ADDR;

⌨️ 快捷键说明

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