Wixel SDK
radio_link.c
1 /* radio_link.c:
2  * This layer uses radio_mac.c in order to provide reliable ordered delivery and reception of
3  * a series of data packets between this device and another. This is the layer that takes care
4  * of Ping/ACK/NAK packets, and handles the details of timing (however, the timing details
5  * are dependent on the performance/configuration of the MAC layer, so if the MAC layer
6  * changes then the timing details here may have to change.)
7  *
8  * There is a distinction here between RF packets and data packets: an RF packet is what gets
9  * transmitted by the radio. A data packet is a piece of data that needs to be sent to the
10  * other device, and it might correspond to several RF packets because there are retries and
11  * ACKs.
12  */
13 
14 #include <radio_link.h>
15 #include <radio_registers.h>
16 #include <random.h>
17 
18 /* PARAMETERS *****************************************************************/
19 
21 
22 /* PACKET VARIABLES AND DEFINES ***********************************************/
23 
24 // Compute the max size of on-the-air packets. This value is stored in the PKTLEN register.
25 #define RADIO_MAX_PACKET_SIZE (RADIO_LINK_PAYLOAD_SIZE + RADIO_LINK_PACKET_HEADER_LENGTH)
26 
27 // The link layer will add a one byte header to the beginning of each packet.
28 #define RADIO_LINK_PACKET_HEADER_LENGTH 1
29 
30 #define RADIO_LINK_PACKET_LENGTH_OFFSET 0
31 #define RADIO_LINK_PACKET_TYPE_OFFSET 1
32 
33 #define RADIO_LINK_PAYLOAD_TYPE_BIT_OFFSET 1
34 #define RADIO_LINK_PAYLOAD_TYPE_MASK 0b00011110
35 
36 #define PACKET_TYPE_MASK (3 << 6) // These are the bits that determine the packet type.
37 #define PACKET_TYPE_PING (0 << 6) // If both bits are zero, it is just a Ping packet (with optional data).
38 #define PACKET_TYPE_NAK (1 << 6) // A NAK packet (with optional data)
39 #define PACKET_TYPE_ACK (2 << 6) // An ACK packet (with optional data)
40 #define PACKET_TYPE_RESET (3 << 6) // A Reset packet (the next packet transmitted by the sender of this packet will have a sequence number of 0)
41 
42 /* rxPackets:
43  * We need to be prepared at all times to receive a full packet from the other party,
44  * even if all we can do is NAK it. Therefore, we need (at least) THREE buffers, so
45  * that two can be owned by the main loop while another is owned by the ISR and ready
46  * to receive the next packet.
47  *
48  * If a packet is received and the main loop still owns the other two buffers,
49  * we respond with a NAK to the other device.
50  *
51  * Ownership of the RX packet buffers is determined from radioLinkRxMainLoopIndex and radioLinkRxInterruptIndex.
52  * The main loop owns all the buffers from radioLinkRxMainLoopIndex to radioLinkRxInterruptIndex-1 inclusive.
53  * If the two indices are equal, then the main loop owns nothing. Here are three examples:
54  *
55  * radioLinkRxMainLoopIndex | radioLinkRxInterruptIndex | Buffers owned by main loop.
56  * 0 | 0 | None
57  * 0 | 1 | rxBuffer[0]
58  * 0 | 2 | rxBuffer[0 and 1]
59  */
60 #define RX_PACKET_COUNT 3
61 static volatile uint8 XDATA radioLinkRxPacket[RX_PACKET_COUNT][1 + RADIO_MAX_PACKET_SIZE + 2]; // The first byte is the length, 2nd byte is link header.
62 volatile uint8 DATA radioLinkRxMainLoopIndex = 0; // The index of the next rxBuffer to read from the main loop.
63 volatile uint8 DATA radioLinkRxInterruptIndex = 0; // The index of the next rxBuffer to write to when a packet comes from the radio.
64 
65 /* txPackets are handled similarly */
66 #define TX_PACKET_COUNT 16
67 static volatile uint8 XDATA radioLinkTxPacket[TX_PACKET_COUNT][1 + RADIO_MAX_PACKET_SIZE]; // The first byte is the length, 2nd byte is link header.
68 volatile uint8 DATA radioLinkTxMainLoopIndex = 0; // The index of the next txPacket to write to in the main loop.
69 volatile uint8 DATA radioLinkTxInterruptIndex = 0; // The index of the current txPacket we are trying to send on the radio.
70 
71 uint8 XDATA shortTxPacket[2];
72 
73 // The number of times the current TX packet has been transmitted.
74 // Does NOT overflow. If we have transmitting the current packet more than 255
75 // times, this variable will be 255.
76 uint8 DATA radioLinkTxCurrentPacketTries = 0;
77 
78 static volatile BIT sendingReset = 0;
79 static volatile BIT acceptAnySequenceBit = 0;
80 
82 
83 /* SEQUENCING VARIABLES *******************************************************/
84 /* Each data packet we transmit contains a bit that is either 0 or 1 called the
85  sequence bit. This bit changes every time we send a different data packet,
86  so it allows the receiver to tell if we transmitted the same packet twice
87  (which is what happens when the receiver's ACK packet was lost). */
88 
89 // rxSequenceBit is the value of the sequence bit for the LAST packet we received.
90 // If we receive a packet whose sequence bit has the same value, we will ACK it
91 // but not pass the data to the main loop. This variable is only used in the ISR.
92 static volatile BIT rxSequenceBit;
93 
94 // txSequenceBit is the value of the sequence bit for the NEXT packet we will
95 // send.
96 static volatile BIT txSequenceBit;
97 
98 
99 /* GENERAL VARIABLES **********************************************************/
100 
102 
103 /* GENERAL FUNCTIONS **********************************************************/
104 
106 {
108 
109  rxSequenceBit = 1;
110 
111  txSequenceBit = 0;
112 
113  PKTLEN = RADIO_MAX_PACKET_SIZE;
114  CHANNR = param_radio_channel;
115 
116  acceptAnySequenceBit = 1;
117  radioMacInit();
118 
119  // Start trying to send a reset packet.
120  sendingReset = 1;
121  radioMacStrobe();
122 }
123 
124 // Returns a random delay in units of 0.922 ms (the same units of radioMacRx).
125 // This is used to decide how long to wait before retransmitting.
126 // This is used to decide when to next transmit a queued data packet.
127 // If we have already tried sending this packet many times, then this function
128 // will return a much longer delay, in order to avoid overcrowding the airwaves for
129 // no reason. This is similar to the idea of exponential backoff used in other
130 // communications protocols such as Ethernet:
131 // http://en.wikipedia.org/wiki/Exponential_backoff
132 static uint8 randomTxDelay()
133 {
134  // 200 and 250 were chosen arbitrarily.
135  return (radioLinkTxCurrentPacketTries > 200 ? 250 : 1) + (randomNumber() & 3);
136 }
137 
139 {
140  return !sendingReset;
141 }
142 
143 /* TX FUNCTIONS (called by higher-level code in main loop) ********************/
144 
146 {
147  // Assumption: TX_PACKET_COUNT is a power of 2
148  return (radioLinkTxInterruptIndex - radioLinkTxMainLoopIndex - 1) & (TX_PACKET_COUNT - 1);
149 }
150 
152 {
153  return (radioLinkTxMainLoopIndex - radioLinkTxInterruptIndex) & (TX_PACKET_COUNT - 1);
154 }
155 
157 {
158  if (!radioLinkTxAvailable())
159  {
160  return 0;
161  }
162 
163  return radioLinkTxPacket[radioLinkTxMainLoopIndex] + RADIO_LINK_PACKET_HEADER_LENGTH;
164 }
165 
166 void radioLinkTxSendPacket(uint8 payloadType)
167 {
168  // Now we set the length byte.
169  radioLinkTxPacket[radioLinkTxMainLoopIndex][0] = radioLinkTxPacket[radioLinkTxMainLoopIndex][RADIO_LINK_PACKET_HEADER_LENGTH] + RADIO_LINK_PACKET_HEADER_LENGTH;
170 
171  // Put the payloadType into the packet header.
172  radioLinkTxPacket[radioLinkTxMainLoopIndex][RADIO_LINK_PACKET_TYPE_OFFSET] = payloadType << RADIO_LINK_PAYLOAD_TYPE_BIT_OFFSET;
173 
174  // Update our index of which packet to populate in the main loop.
175  if (radioLinkTxMainLoopIndex == TX_PACKET_COUNT - 1)
176  {
177  radioLinkTxMainLoopIndex = 0;
178  }
179  else
180  {
181  radioLinkTxMainLoopIndex++;
182  }
183 
184  // Make sure that radioMacEventHandler runs soon so it can see this new data and send it.
185  // This must be done LAST.
186  radioMacStrobe();
187 }
188 
189 /* RX FUNCTIONS (called by higher-level code in main loop) ********************/
190 
192 {
193  if (radioLinkRxMainLoopIndex == radioLinkRxInterruptIndex)
194  {
195  return 0;
196  }
197 
198  return radioLinkRxPacket[radioLinkRxMainLoopIndex] + RADIO_LINK_PACKET_HEADER_LENGTH;
199 }
200 
202 {
203  return radioLinkRxPacket[radioLinkRxMainLoopIndex][0];
204 }
205 
207 {
208  if (radioLinkRxMainLoopIndex == RX_PACKET_COUNT - 1)
209  {
210  radioLinkRxMainLoopIndex = 0;
211  }
212  else
213  {
214  radioLinkRxMainLoopIndex++;
215  }
216 }
217 
218 /* FUNCTIONS CALLED IN RF_ISR *************************************************/
219 
220 static void txResetPacket()
221 {
222  shortTxPacket[RADIO_LINK_PACKET_LENGTH_OFFSET] = 1;
223  shortTxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] = PACKET_TYPE_RESET;
224  radioMacTx(shortTxPacket);
225  if (radioLinkTxCurrentPacketTries < 255)
226  {
227  radioLinkTxCurrentPacketTries++;
228  }
229 }
230 
231 static void txDataPacket(uint8 packetType)
232 {
233  radioLinkTxPacket[radioLinkTxInterruptIndex][RADIO_LINK_PACKET_TYPE_OFFSET] =
234  (radioLinkTxPacket[radioLinkTxInterruptIndex][RADIO_LINK_PACKET_TYPE_OFFSET] & RADIO_LINK_PAYLOAD_TYPE_MASK) | packetType | txSequenceBit;
235  radioMacTx(radioLinkTxPacket[radioLinkTxInterruptIndex]);
236  if (radioLinkTxCurrentPacketTries < 255)
237  {
238  radioLinkTxCurrentPacketTries++;
239  }
240 }
241 
242 static void takeInitiative()
243 {
244  if (sendingReset)
245  {
246  // Try to send a reset packet.
247  txResetPacket();
249  }
250  else if (radioLinkTxInterruptIndex != radioLinkTxMainLoopIndex)
251  {
252  // Try to send the next data packet.
253  txDataPacket(PACKET_TYPE_PING);
255  }
256  else
257  {
258  radioMacRx(radioLinkRxPacket[radioLinkRxInterruptIndex], 0);
259  }
260 }
261 
262 void radioMacEventHandler(uint8 event) // called by the MAC in an ISR
263 {
264  if (event == RADIO_MAC_EVENT_STROBE)
265  {
266  takeInitiative();
267  return;
268  }
269  else if (event == RADIO_MAC_EVENT_TX)
270  {
271  // We sent a packet, so now lets give the other party a chance to talk.
272  radioMacRx(radioLinkRxPacket[radioLinkRxInterruptIndex], randomTxDelay());
273  return;
274  }
275  else if (event == RADIO_MAC_EVENT_RX)
276  {
277  uint8 XDATA * currentRxPacket = radioLinkRxPacket[radioLinkRxInterruptIndex];
278 
279  if (!radioCrcPassed())
280  {
281  if (radioLinkTxInterruptIndex != radioLinkTxMainLoopIndex)
282  {
283  radioMacRx(currentRxPacket, randomTxDelay());
284  }
285  else
286  {
287  radioMacRx(currentRxPacket, 0);
288  }
289  return;
290  }
291 
292  if ((currentRxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] & PACKET_TYPE_MASK) == PACKET_TYPE_RESET)
293  {
294  // The other Wixel sent a Reset packet, which means the next packet it sends will have a sequence bit of 0.
295  // So this Wixel should set its "previously received" sequence bit to 1 so it expects a 0 next.
296  rxSequenceBit = 1;
297 
298  // Notify the higher-level code.
300 
301  // Send an ACK
302  shortTxPacket[RADIO_LINK_PACKET_LENGTH_OFFSET] = 1;
303  shortTxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] = PACKET_TYPE_ACK;
304  radioMacTx(shortTxPacket);
305 
307 
308  return;
309  }
310 
311  if ((currentRxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] & PACKET_TYPE_MASK) == PACKET_TYPE_ACK)
312  {
313  // The packet we received contained an acknowledgment.
314 
315  if (sendingReset)
316  {
317  // If we were sending a Reset packet, stop trying to resend it.
318  sendingReset = 0;
319 
320  // Reset the transmission counter.
321  radioLinkTxCurrentPacketTries = 0;
322 
323  // Make sure the next packet we transmit has a sequence bit of 0.
324  txSequenceBit = 0;
325  }
326  else if (radioLinkTxInterruptIndex != radioLinkTxMainLoopIndex)
327  {
328  // Check to see if there is actually any TX packet that we were sending that
329  // can be acknowledged. This check should return true unless there is a bug
330  // on the other Wixel.
331 
332  // Give ownership of the current TX packet back to the main loop by updated radioLinkTxInterruptIndex.
333  if (radioLinkTxInterruptIndex == TX_PACKET_COUNT - 1)
334  {
335  radioLinkTxInterruptIndex = 0;
336  }
337  else
338  {
339  radioLinkTxInterruptIndex++;
340  }
341 
342  // Reset the transmission counter.
343  radioLinkTxCurrentPacketTries = 0;
344 
345  // The next packet we transmit will have a different sequence bit.
346  txSequenceBit ^= 1;
347  }
348  }
349 
350  if (currentRxPacket[RADIO_LINK_PACKET_LENGTH_OFFSET] > RADIO_LINK_PACKET_HEADER_LENGTH)
351  {
352  // We received a packet that contains actual data.
353 
354  uint8 responsePacketType = PACKET_TYPE_ACK;
355 
356  if (acceptAnySequenceBit || (rxSequenceBit != (currentRxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] & 1)))
357  {
358  // This packet is NOT a retransmission of the last packet we received.
359 
360  uint8 nextradioLinkRxInterruptIndex;
361 
362  // See if we can give the data to the main loop.
363  if (radioLinkRxInterruptIndex == RX_PACKET_COUNT - 1)
364  {
365  nextradioLinkRxInterruptIndex = 0;
366  }
367  else
368  {
369  nextradioLinkRxInterruptIndex = radioLinkRxInterruptIndex + 1;
370  }
371 
372  if (nextradioLinkRxInterruptIndex != radioLinkRxMainLoopIndex)
373  {
374  // We can accept this packet and send an ACK!
375 
376  uint8 payloadType;
377 
378  // Set rxSequenceBit to match the sequence bit in the received packet
379  rxSequenceBit = (currentRxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] & 1);
380  acceptAnySequenceBit = 0;
381 
382  // Extract the payload type.
383  payloadType = (currentRxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] & RADIO_LINK_PAYLOAD_TYPE_MASK) >> RADIO_LINK_PAYLOAD_TYPE_BIT_OFFSET;
384 
385  // Set length byte that will be read by the higher-level code.
386  // (This overrides the 1-byte header.)
387  currentRxPacket[RADIO_LINK_PACKET_HEADER_LENGTH] = currentRxPacket[RADIO_LINK_PACKET_LENGTH_OFFSET] - RADIO_LINK_PACKET_HEADER_LENGTH;
388 
389  // Set the payload type byte which will be read by radioLinkRxCurrentPayloadType().
390  // (This overrides the 1-byte RF packet length.)
391  currentRxPacket[0] = payloadType;
392 
393  radioLinkRxInterruptIndex = nextradioLinkRxInterruptIndex;
394  }
395  else
396  {
397  // The main loop is already using all of the other RX packet buffers,
398  // so we can't give this packet to the main loop and we will send a NAK.
399  responsePacketType = PACKET_TYPE_NAK;
400  }
401 
402  }
403 
404  // Send an ACK or NAK to the other party.
405 
406  if (radioLinkTxInterruptIndex != radioLinkTxMainLoopIndex)
407  {
408  // Send some data along with the ACK or NAK.
409  txDataPacket(responsePacketType);
410  }
411  else
412  {
413  // No data is available, so just send the ACK or NAK by itself.
414 
415  shortTxPacket[RADIO_LINK_PACKET_LENGTH_OFFSET] = 1;
416  shortTxPacket[RADIO_LINK_PACKET_TYPE_OFFSET] = responsePacketType;
417  radioMacTx(shortTxPacket);
418  }
419 
421  }
422  else
423  {
424  // TODO: if radioLinkTxCurrentPacketTries > 200 then we should probably just go
425  // into RX mode here so we can avoid having this conversation 4 times per second:
426  // DATA, NAK, DATA, NAK, DATA, NAK, DATA, NAK, DATA, NAK, ...
427  // (It starts when the sender takes initiative and sends his (failing) data every
428  // 250ms, and it ends as soon as one packet is lost.)
429  takeInitiative();
430  }
431  return;
432  }
433  else if (event == RADIO_MAC_EVENT_RX_TIMEOUT)
434  {
435  takeInitiative();
436  return;
437  }
438 }
void radioMacInit(void)
Definition: radio_mac.c:209
#define DATA
Definition: cc2511_types.h:52
void radioMacStrobe(void)
Definition: radio_mac.c:201
#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
#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
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
BIT radioCrcPassed()
#define CODE
Definition: cc2511_types.h:39