📄 rf_remote_unit.c
字号:
/// \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 + -