Wixel SDK
radio_queue.c
1 /* radio_queue.c:
2  * This layer builds on top of radio_mac.c to provide a mechanism for queueing
3  * RF packets to be sent and packets that are received by this device. It does
4  * not ensure reliability or specify the format of the packets, except that the
5  * first byte of the packet must contain its length.
6  *
7  * This layer does not transmit packets as quickly as possible; instead, it
8  * listens for incoming packets for a random interval of 1-4 ms between sending
9  * packets.
10  *
11  * This layer defines the RF packet memory buffers used, and controls access to
12  * those buffers.
13  *
14  * Radio_queue is essentially a stripped-down version of the radio_link
15  * library, so radio_link is a good alternative if you want a more specialized
16  * implementation with more features.
17  */
18 
19 #include <radio_queue.h>
20 #include <radio_registers.h>
21 #include <random.h>
22 
23 /* PARAMETERS *****************************************************************/
24 
26 
27 /* PACKET VARIABLES AND DEFINES ***********************************************/
28 
29 // Compute the max size of on-the-air packets. This value is stored in the PKTLEN register.
30 #define RADIO_MAX_PACKET_SIZE (RADIO_QUEUE_PAYLOAD_SIZE)
31 
32 #define RADIO_QUEUE_PACKET_LENGTH_OFFSET 0
33 
34 /* rxPackets:
35  * We need to be prepared at all times to receive a full packet from another
36  * party, even if we cannot give it to the main loop. Therefore, we need (at
37  * least) THREE buffers, so that two can be owned by the main loop while
38  * another is owned by the ISR and ready to receive the next packet.
39  *
40  * If a packet is received and the main loop still owns the other two buffers,
41  * we discard it.
42  *
43  * Ownership of the RX packet buffers is determined from radioQueueRxMainLoopIndex and radioQueueRxInterruptIndex.
44  * The main loop owns all the buffers from radioQueueRxMainLoopIndex to radioQueueRxInterruptIndex-1 inclusive.
45  * If the two indices are equal, then the main loop owns nothing. Here are three examples:
46  *
47  * radioQueueRxMainLoopIndex | radioQueueRxInterruptIndex | Buffers owned by main loop.
48  * 0 | 0 | None
49  * 0 | 1 | rxBuffer[0]
50  * 0 | 2 | rxBuffer[0 and 1]
51  */
52 #define RX_PACKET_COUNT 3
53 static volatile uint8 XDATA radioQueueRxPacket[RX_PACKET_COUNT][1 + RADIO_MAX_PACKET_SIZE + 2]; // The first byte is the length.
54 static volatile uint8 DATA radioQueueRxMainLoopIndex = 0; // The index of the next rxBuffer to read from the main loop.
55 static volatile uint8 DATA radioQueueRxInterruptIndex = 0; // The index of the next rxBuffer to write to when a packet comes from the radio.
56 
57 /* txPackets are handled similarly */
58 #define TX_PACKET_COUNT 16
59 static volatile uint8 XDATA radioQueueTxPacket[TX_PACKET_COUNT][1 + RADIO_MAX_PACKET_SIZE]; // The first byte is the length.
60 static volatile uint8 DATA radioQueueTxMainLoopIndex = 0; // The index of the next txPacket to write to in the main loop.
61 static volatile uint8 DATA radioQueueTxInterruptIndex = 0; // The index of the current txPacket we are trying to send on the radio.
62 
64 
65 /* GENERAL FUNCTIONS **********************************************************/
66 
68 {
70 
71  PKTLEN = RADIO_MAX_PACKET_SIZE;
72  CHANNR = param_radio_channel;
73 
74  radioMacInit();
76 }
77 
78 // Returns a random delay in units of 0.922 ms (the same units of radioMacRx).
79 // This is used to decide when to next transmit a queued data packet.
80 static uint8 randomTxDelay()
81 {
82  return 1 + (randomNumber() & 3);
83 }
84 
85 /* TX FUNCTIONS (called by higher-level code in main loop) ********************/
86 
88 {
89  // Assumption: TX_PACKET_COUNT is a power of 2
90  return (radioQueueTxInterruptIndex - radioQueueTxMainLoopIndex - 1) & (TX_PACKET_COUNT - 1);
91 }
92 
94 {
95  return (radioQueueTxMainLoopIndex - radioQueueTxInterruptIndex) & (TX_PACKET_COUNT - 1);
96 }
97 
99 {
100  if (!radioQueueTxAvailable())
101  {
102  return 0;
103  }
104 
105  return radioQueueTxPacket[radioQueueTxMainLoopIndex];
106 }
107 
109 {
110  // Update our index of which packet to populate in the main loop.
111  if (radioQueueTxMainLoopIndex == TX_PACKET_COUNT - 1)
112  {
113  radioQueueTxMainLoopIndex = 0;
114  }
115  else
116  {
117  radioQueueTxMainLoopIndex++;
118  }
119 
120  // Make sure that radioMacEventHandler runs soon so it can see this new data and send it.
121  // This must be done LAST.
122  radioMacStrobe();
123 }
124 
125 /* RX FUNCTIONS (called by higher-level code in main loop) ********************/
126 
128 {
129  if (radioQueueRxMainLoopIndex == radioQueueRxInterruptIndex)
130  {
131  return 0;
132  }
133  return radioQueueRxPacket[radioQueueRxMainLoopIndex];
134 }
135 
137 {
138  if (radioQueueRxMainLoopIndex == RX_PACKET_COUNT - 1)
139  {
140  radioQueueRxMainLoopIndex = 0;
141  }
142  else
143  {
144  radioQueueRxMainLoopIndex++;
145  }
146 }
147 
148 /* FUNCTIONS CALLED IN RF_ISR *************************************************/
149 
150 static void takeInitiative()
151 {
152  if (radioQueueTxInterruptIndex != radioQueueTxMainLoopIndex)
153  {
154  // Try to send the next data packet.
155  radioMacTx(radioQueueTxPacket[radioQueueTxInterruptIndex]);
156  }
157  else
158  {
159  radioMacRx(radioQueueRxPacket[radioQueueRxInterruptIndex], 0);
160  }
161 }
162 
163 void radioMacEventHandler(uint8 event) // called by the MAC in an ISR
164 {
165  if (event == RADIO_MAC_EVENT_STROBE)
166  {
167  takeInitiative();
168  return;
169  }
170  else if (event == RADIO_MAC_EVENT_TX)
171  {
172  // Give ownership of the current TX packet back to the main loop by updated radioQueueTxInterruptIndex.
173  if (radioQueueTxInterruptIndex == TX_PACKET_COUNT - 1)
174  {
175  radioQueueTxInterruptIndex = 0;
176  }
177  else
178  {
179  radioQueueTxInterruptIndex++;
180  }
181 
182  // We sent a packet, so now let's give another party a chance to talk.
183  radioMacRx(radioQueueRxPacket[radioQueueRxInterruptIndex], randomTxDelay());
184  return;
185  }
186  else if (event == RADIO_MAC_EVENT_RX)
187  {
188  uint8 XDATA * currentRxPacket = radioQueueRxPacket[radioQueueRxInterruptIndex];
189 
191  {
192  if (radioQueueTxInterruptIndex != radioQueueTxMainLoopIndex)
193  {
194  radioMacRx(currentRxPacket, randomTxDelay());
195  }
196  else
197  {
198  radioMacRx(currentRxPacket, 0);
199  }
200  return;
201  }
202 
203  if (currentRxPacket[RADIO_QUEUE_PACKET_LENGTH_OFFSET] > 0)
204  {
205  // We received a packet that contains actual data.
206 
207  uint8 nextradioQueueRxInterruptIndex;
208 
209  // See if we can give the data to the main loop.
210  if (radioQueueRxInterruptIndex == RX_PACKET_COUNT - 1)
211  {
212  nextradioQueueRxInterruptIndex = 0;
213  }
214  else
215  {
216  nextradioQueueRxInterruptIndex = radioQueueRxInterruptIndex + 1;
217  }
218 
219  if (nextradioQueueRxInterruptIndex != radioQueueRxMainLoopIndex)
220  {
221  // We can accept this packet!
222  radioQueueRxInterruptIndex = nextradioQueueRxInterruptIndex;
223  }
224  }
225 
226  takeInitiative();
227  return;
228  }
229  else if (event == RADIO_MAC_EVENT_RX_TIMEOUT)
230  {
231  takeInitiative();
232  return;
233  }
234 }
void radioMacInit(void)
Definition: radio_mac.c:209
#define DATA
Definition: cc2511_types.h:52
void radioMacStrobe(void)
Definition: radio_mac.c:201
BIT radioQueueAllowCrcErrors
Definition: radio_queue.c:63
#define XDATA
Definition: cc2511_types.h:65
void radioMacTx(uint8 XDATA *packet)
Definition: radio_mac.c:254
#define RADIO_MAC_EVENT_RX
Definition: radio_mac.h:34
uint8 XDATA * radioQueueRxCurrentPacket(void)
Definition: radio_queue.c:127
#define RADIO_MAC_EVENT_STROBE
Definition: radio_mac.h:38
uint8 randomNumber(void)
Definition: random.c:9
#define RADIO_MAC_EVENT_RX_TIMEOUT
Definition: radio_mac.h:36
void radioMacEventHandler(uint8 event)
Definition: radio_link.c:262
__bit BIT
Definition: cc2511_types.h:32
uint8 XDATA * radioQueueTxCurrentPacket(void)
Definition: radio_queue.c:98
void radioMacRx(uint8 XDATA *packet, uint8 timeout)
Definition: radio_mac.c:226
void randomSeedFromSerialNumber(void)
unsigned char uint8
Definition: cc2511_types.h:9
#define RADIO_MAC_EVENT_TX
Definition: radio_mac.h:32
signed long int32
Definition: cc2511_types.h:24
void radioQueueTxSendPacket(void)
Definition: radio_queue.c:108
BIT radioCrcPassed()
uint8 radioQueueTxQueued(void)
Definition: radio_queue.c:93
uint8 radioQueueTxAvailable(void)
Definition: radio_queue.c:87
void radioQueueInit(void)
Definition: radio_queue.c:67
#define CODE
Definition: cc2511_types.h:39
void radioQueueRxDoneWithPacket(void)
Definition: radio_queue.c:136