Wixel SDK
radio_com.c
1 #include <radio_link.h>
2 #include <radio_com.h>
3 
4 #define PAYLOAD_TYPE_DATA 0
5 #define PAYLOAD_TYPE_CONTROL_SIGNALS 1
6 
8 
9 static uint8 DATA txBytesLoaded = 0;
10 static uint8 DATA rxBytesLeft = 0;
11 
12 static uint8 XDATA * DATA rxPointer = 0;
13 static uint8 XDATA * DATA txPointer = 0;
14 static uint8 XDATA * DATA packetPointer = 0;
15 
16 static uint8 radioComRxSignals = 0;
17 static uint8 radioComTxSignals = 0;
18 static uint8 lastRxSignals = 0; // The last RX signals sent to the higher-level code.
19 static BIT sendSignalsSoon = 0; // 1 iff we should transmit control signals soon
20 
21 // For highest throughput, we want to send as much data in each packet
22 // as possible. But for lower latency, we sometimes need to send packets
23 // that are NOT full.
24 // This library will only send non-full packets if the number of packets
25 // currently queued to be sent is small. Specifically, that number must
26 // not exceed TX_QUEUE_THRESHOLD.
27 // A higher threshold means that there will be more under-populated packets
28 // at the beginning of a data transfer (which is bad), but slightly reduces
29 // the importance of calling radioComTxService often (which can be good).
30 #define TX_QUEUE_THRESHOLD 1
31 
33 {
34  radioLinkInit();
35 }
36 
39 #define WAITING_TO_REPORT_RX_SIGNALS (radioComRxEnforceOrdering && radioComRxSignals != lastRxSignals)
40 
41 static void receiveMorePackets(void)
42 {
43  uint8 XDATA * packet;
44 
45  if (rxBytesLeft != 0)
46  {
47  // There are bytes available. The higher-level code should
48  // call radioComRxReceiveByte to get them.
49  return;
50  }
51 
52  if (WAITING_TO_REPORT_RX_SIGNALS)
53  {
54  // The higher-level code needs to call radioComRxSignals before
55  // we feed it any more data.
56  return;
57  }
58 
59  // Each iteration of this loop processes one packet received on the radio.
60  // This loop stops when we are out of packets or when we received a packet
61  // that contains some information that the higher-level code needs to process.
62  while(packet = radioLinkRxCurrentPacket())
63  {
65  {
66  case PAYLOAD_TYPE_DATA:
67  // We received some data. Populate rxPointer and rxBytesLeft.
68  // The data can be retreived with radioComRxAvailable and racioComRxReceiveByte().
69 
70  // Assumption: radioLink doesn't ever return zero-length packets,
71  // so rxBytesLeft is non-zero now and we don't have to worry about
72  // discard zero-length packets in radio_com.c.
73  rxBytesLeft = packet[0]; // Read the packet length.
74  rxPointer = packet+1; // Make rxPointer point to the data.
75  return;
76 
77  case PAYLOAD_TYPE_CONTROL_SIGNALS:
78  // We received a command to set the control signals.
79  radioComRxSignals = packet[1];
80 
82 
83  if (WAITING_TO_REPORT_RX_SIGNALS)
84  {
85  // The higher-level code has not seen these values for the control
86  // signals yet, so stop processing packets.
87  // The higher-level code can access these values by calling radioComRxControlSignals().
88  return;
89  }
90 
91  // It was a redundant command so don't do anything special.
92  // Keep processing packets.
93  break;
94  }
95  }
96 }
97 
98 // NOTE: This function only returns the number of bytes available in the CURRENT PACKET.
99 // It doesn't look at all the packets received, and it doesn't count the data that is
100 // queued on the other Wixel. Therefore, it is never recommended to write some kind of
101 // program that waits for radioComRxAvailable to reach some value greater than 1: it might
102 // never reach that value.
104 {
105  receiveMorePackets();
106  return rxBytesLeft;
107 }
108 
109 // Assumption: The user recently called radioComRxAvailable and it returned
110 // a non-zero value.
112 {
113  uint8 tmp = *rxPointer; // Read a byte from the current RX packet.
114  rxPointer++; // Update pointer and counter.
115  rxBytesLeft--;
116 
117  if (rxBytesLeft == 0) // If there are no bytes left in this packet...
118  {
119  radioLinkRxDoneWithPacket(); // Tell the radio link layer we are done with it so we can receive more.
120  }
121 
122  return tmp;
123 }
124 
126 {
127  receiveMorePackets();
128  lastRxSignals = radioComRxSignals;
129  return lastRxSignals;
130 }
131 
134 static void radioComSendDataNow()
135 {
136  *packetPointer = txBytesLoaded;
137  radioLinkTxSendPacket(PAYLOAD_TYPE_DATA);
138  txBytesLoaded = 0;
139 }
140 
141 static void radioComSendControlSignalsNow()
142 {
143  // Assumption: txBytesLoaded is 0 (we are not in the middle of populating a data packet)
144  // Assumption: radioLinkTxAvailable() >= 1
145 
146  uint8 XDATA * packet;
147 
148  packet = radioLinkTxCurrentPacket();
149  packet[0] = 1; // Payload length is one byte.
150  packet[1] = radioComTxSignals;
151  sendSignalsSoon = 0;
152  radioLinkTxSendPacket(PAYLOAD_TYPE_CONTROL_SIGNALS);
153 }
154 
156 {
158  {
159  // The other device has sent us a reset packet, which means it has been
160  // reset. We should send the state of the control signals to it.
162  sendSignalsSoon = 1;
163  }
164 
165  if (sendSignalsSoon)
166  {
167  // We want to send the control signals ASAP.
168 
169  // NOTE: The if statement below could probably be moved to radioComTxControlSignals()
170  // and then you could add the assumption here that txBytesLoaded is 0
171  // (we are not in the middle of populating a data packet).
172  if (txBytesLoaded != 0)
173  {
174  // There is normal data that needs to be sent before the control signals,
175  // so send it now.
176  radioComSendDataNow();
177  }
178 
179  if (radioLinkTxAvailable())
180  {
181  radioComSendControlSignalsNow();
182  }
183  }
184  else
185  {
186  // We don't need to send control signals ASAP, so we use the normal policy
187  // for sending data: only send a non-full packet if the number of packets
188  // queued in the lower level drops below the TX_QUEUE_THRESHOLD.
189 
190  if (txBytesLoaded != 0 && radioLinkTxQueued() <= TX_QUEUE_THRESHOLD)
191  {
192  radioComSendDataNow();
193  }
194  }
195 }
196 
198 {
199  if (sendSignalsSoon)
200  {
201  // We want to send the control signals ASAP, but have not yet been able to
202  // queue a packet for them. Return 0 because we don't want to accept any
203  // more data bytes until we queue up those control signals. This is part of
204  // the plan to ensure that everything is processed in the right order.
205  return 0;
206  }
207  else
208  {
209  // Assumption: If txBytesLoaded is non-zero, radioLinkTxAvailable will be non-zero,
210  // so the subtraction below does not overflow.
211  // Assumption: The multiplication below does not overflow ever.
212  return radioLinkTxAvailable()*RADIO_LINK_PAYLOAD_SIZE - txBytesLoaded;
213  }
214 }
215 
217 {
218  // Assumption: The user called radioComTxAvailable recently and it returned a non-zero value.
219  if (txBytesLoaded == 0)
220  {
221  txPointer = packetPointer = radioLinkTxCurrentPacket();
222  }
223 
224  txPointer++;
225  *txPointer = byte;
226  txBytesLoaded++;
227 
228  if (txBytesLoaded == RADIO_LINK_PAYLOAD_SIZE)
229  {
230  radioComSendDataNow();
231  }
232 }
233 
234 // If we are in the middle of building a packet, send it.
235 void radioComTxControlSignals(uint8 controlSignals)
236 {
237  if(controlSignals != radioComTxSignals)
238  {
239  radioComTxSignals = controlSignals;
240  sendSignalsSoon = 1;
242  }
243 }
void radioComTxSendByte(uint8 byte)
Definition: radio_com.c:216
uint8 radioComRxControlSignals(void)
Definition: radio_com.c:125
#define DATA
Definition: cc2511_types.h:52
uint8 radioComTxAvailable(void)
Definition: radio_com.c:197
void radioComTxControlSignals(uint8 controlSignals)
Definition: radio_com.c:235
#define XDATA
Definition: cc2511_types.h:65
void radioComTxService(void)
Definition: radio_com.c:155
uint8 radioComRxReceiveByte(void)
Definition: radio_com.c:111
BIT radioComRxEnforceOrdering
Definition: radio_com.c:7
uint8 radioComRxAvailable(void)
Definition: radio_com.c:103
__bit BIT
Definition: cc2511_types.h:32
void radioComInit(void)
Definition: radio_com.c:32
unsigned char uint8
Definition: cc2511_types.h:9