]> oss.titaniummirror.com Git - tinyos-2.x.git/blob - tos/chips/cc2420_tkn154/CC2420ReceiveP.nc
+ modified radio driver (PHY) interfaces: CSMA-CA algorithm is now pushed to radio...
[tinyos-2.x.git] / tos / chips / cc2420_tkn154 / CC2420ReceiveP.nc
1 /*
2 * Copyright (c) 2005-2006 Arch Rock Corporation
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * - Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * - Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the
13 * distribution.
14 * - Neither the name of the Arch Rock Corporation nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
29 * OF THE POSSIBILITY OF SUCH DAMAGE
30 */
31
32 /**
33 * @author Jonathan Hui <jhui@archrock.com>
34 * @author David Moss
35 * @author Jung Il Choi
36 * @author Jan Hauer <hauer@tkn.tu-berlin.de>
37 * @version $Revision$ $Date$
38 */
39 module CC2420ReceiveP {
40
41 provides interface Init;
42 provides interface CC2420AsyncSplitControl as AsyncSplitControl;
43 provides interface CC2420Receive;
44 provides interface CC2420Rx;
45
46 uses interface GeneralIO as CSN;
47 uses interface GeneralIO as FIFO;
48 uses interface GeneralIO as FIFOP;
49 uses interface GpioInterrupt as InterruptFIFOP;
50
51 uses interface Resource as SpiResource;
52 uses interface CC2420Fifo as RXFIFO;
53 uses interface CC2420Strobe as SACK;
54 uses interface CC2420Strobe as SFLUSHRX;
55 uses interface CC2420Strobe as SRXON;
56 uses interface CC2420Strobe as SACKPEND;
57 uses interface CC2420Register as MDMCTRL1;
58 uses interface ReferenceTime;
59 uses interface FrameUtility;
60 uses interface CC2420Config;
61 uses interface CC2420Ram as RXFIFO_RAM;
62
63 uses interface Leds;
64 }
65
66 implementation {
67
68 typedef enum {
69 S_STOPPED,
70 S_STARTING,
71 S_STARTED,
72 S_RX_LENGTH,
73 S_RX_FCF,
74 S_RX_HEADER,
75 S_RX_PAYLOAD,
76 } cc2420_receive_state_t;
77
78 enum {
79 RXFIFO_SIZE = 128,
80 TIMESTAMP_QUEUE_SIZE = 8,
81 //SACK_HEADER_LENGTH = 7,
82 SACK_HEADER_LENGTH = 3,
83 };
84
85 ieee154_reftime_t m_timestamp_queue[ TIMESTAMP_QUEUE_SIZE ];
86 ieee154_reftime_t m_timestamp;
87 norace bool m_timestampValid;
88
89 uint8_t m_timestamp_head;
90
91 uint8_t m_timestamp_size;
92
93 /** Number of packets we missed because we were doing something else */
94 uint8_t m_missed_packets;
95
96 /** TRUE if we are receiving a valid packet into the stack */
97 norace bool receivingPacket;
98
99 /** The length of the frame we're currently receiving */
100 norace uint8_t rxFrameLength;
101
102 norace uint8_t m_bytes_left;
103
104 // norace message_t* m_p_rx_buf;
105
106 // message_t m_rx_buf;
107
108 cc2420_receive_state_t m_state;
109
110 // new packet format:
111 message_t m_frame;
112 norace message_t *m_rxFramePtr;
113 norace uint8_t m_mhrLen;
114 uint8_t m_dummy;
115 norace bool m_stop;
116
117 /***************** Prototypes ****************/
118 void reset_state();
119 void beginReceive();
120 void receive();
121 void waitForNextPacket();
122 void flush();
123 void switchToUnbufferedMode();
124 void switchToBufferedMode();
125 void continueStart();
126 void continueStop();
127 task void stopContinueTask();
128
129 task void receiveDone_task();
130
131 /***************** Init Commands ****************/
132 command error_t Init.init() {
133 m_rxFramePtr = &m_frame;
134 atomic m_state = S_STOPPED;
135 return SUCCESS;
136 }
137
138 /***************** AsyncSplitControl ****************/
139 /* NOTE: AsyncSplitControl does not switch the state of the radio
140 * hardware (i.e. it does not put the radio in Rx mode, this has to
141 * be done by the caller through a separate interface/component).
142 */
143
144 /**
145 * AsyncSplitControl.start should be called before radio
146 * is switched to Rx mode (or at least early enough before
147 * a packet has been received, i.e. before FIFOP changes)
148 */
149 async command error_t AsyncSplitControl.start()
150 {
151 atomic {
152 if ( !call FIFO.get() && !call FIFOP.get() ){
153 // RXFIFO has some data (remember: FIFOP is inverted)
154 // the problem is that this messses up the timestamping
155 // so why don't we flush here ourselves?
156 // because we don't own the SPI...
157 return FAIL;
158 }
159 if (m_state != S_STOPPED){
160 call Leds.led0On();
161 return FAIL;
162 }
163 reset_state();
164 m_state = S_STARTED;
165 call InterruptFIFOP.enableFallingEdge(); // ready!
166 }
167 return SUCCESS;
168 }
169
170 /* AsyncSplitControl.stop:
171 *
172 * IMPORTANT: when AsyncSplitControl.stop is called,
173 * then either
174 * 1) the radio MUST still be in RxMode
175 * 2) it was never put in RxMode after
176 * AsyncSplitControl.start() was called
177 *
178 * => The radio may be switched off only *after* the
179 * stopDone() event was signalled.
180 */
181 async command error_t AsyncSplitControl.stop()
182 {
183 atomic {
184 if (m_state == S_STOPPED)
185 return EALREADY;
186 else {
187 m_stop = TRUE;
188 call InterruptFIFOP.disable();
189 if (!receivingPacket)
190 continueStop(); // it is safe to stop now
191 // else continueStop will be called after
192 // current Rx operation is finished
193 }
194 }
195 return SUCCESS;
196 }
197
198 void continueStop()
199 {
200 atomic {
201 if (!m_stop){
202 return;
203 }
204 m_stop = FALSE;
205 m_state = S_STOPPED;
206 }
207 post stopContinueTask();
208 }
209
210 task void stopContinueTask()
211 {
212 if (receivingPacket)
213 call Leds.led0On();
214 call SpiResource.release(); // may fail
215 atomic m_state = S_STOPPED;
216 signal AsyncSplitControl.stopDone(SUCCESS);
217 }
218
219 void switchToUnbufferedMode()
220 {
221 uint16_t mdmctrol1;
222 call CSN.set();
223 call CSN.clr();
224 call MDMCTRL1.read(&mdmctrol1);
225 mdmctrol1 &= ~0x03;
226 mdmctrol1 |= 0x01;
227 call MDMCTRL1.write(mdmctrol1);
228 call CSN.set();
229 }
230
231 void switchToBufferedMode()
232 {
233 uint16_t mdmctrol1;
234 call CSN.set();
235 call CSN.clr();
236 call MDMCTRL1.read(&mdmctrol1);
237 mdmctrol1 &= ~0x03;
238 call MDMCTRL1.write(mdmctrol1);
239 call CSN.set();
240 }
241
242 /***************** CC2420Receive Commands ****************/
243 /**
244 * Start frame delimiter signifies the beginning/end of a packet
245 * See the CC2420 datasheet for details.
246 */
247 async command void CC2420Receive.sfd( ieee154_reftime_t *time ) {
248 if (m_state == S_STOPPED)
249 return;
250 if ( m_timestamp_size < TIMESTAMP_QUEUE_SIZE ) {
251 uint8_t tail = ( ( m_timestamp_head + m_timestamp_size ) %
252 TIMESTAMP_QUEUE_SIZE );
253 memcpy(&m_timestamp_queue[ tail ], time, sizeof(ieee154_reftime_t) );
254 m_timestamp_size++;
255 }
256 }
257
258 async command void CC2420Receive.sfd_dropped() {
259 if (m_state == S_STOPPED)
260 return;
261 if ( m_timestamp_size ) {
262 m_timestamp_size--;
263 }
264 }
265
266 /***************** InterruptFIFOP Events ****************/
267 async event void InterruptFIFOP.fired() {
268 atomic {
269 if ( m_state == S_STARTED ) {
270 beginReceive();
271
272 } else {
273 m_missed_packets++;
274 }
275 }
276 }
277
278
279 /***************** SpiResource Events ****************/
280 event void SpiResource.granted() {
281 atomic {
282 switch (m_state)
283 {
284 case S_STOPPED: // this should never happen!
285 call Leds.led0On();
286 call SpiResource.release();
287 break;
288 default: receive();
289 }
290 }
291 }
292
293 uint8_t mhrLength(uint8_t *fcf)
294 {
295 uint8_t idCompression;
296 uint8_t len = MHR_INDEX_ADDRESS;
297
298 if (fcf[MHR_INDEX_FC1] & FC1_SECURITY_ENABLED)
299 return 0xFF; // not supported
300 idCompression = (fcf[0] & FC1_PAN_ID_COMPRESSION);
301 if (fcf[MHR_INDEX_FC2] & 0x08){ // short or ext. address
302 len += 4; // pan id + short address
303 if (fcf[MHR_INDEX_FC2] & 0x04) // ext. address
304 len += 6; // diff to short address
305 }
306 if (fcf[MHR_INDEX_FC2] & 0x80){ // short or ext. address
307 len += 2;
308 if (!idCompression)
309 len += 2;
310 if (fcf[MHR_INDEX_FC2] & 0x40) // ext. address
311 len += 6; // diff to short address
312 }
313 return len;
314 }
315
316
317 /***************** RXFIFO Events ****************/
318 /**
319 * We received some bytes from the SPI bus. Process them in the context
320 * of the state we're in. Remember the length byte is not part of the length
321 */
322 async event void RXFIFO.readDone( uint8_t* rx_buf, uint8_t rx_len,
323 error_t error ) {
324 uint8_t* buf;
325
326 atomic {
327 buf = (uint8_t*) &((ieee154_header_t*) m_rxFramePtr->header)->length;
328 rxFrameLength = ((ieee154_header_t*) m_rxFramePtr->header)->length;
329
330 switch( m_state ) {
331
332 case S_RX_LENGTH:
333 m_state = S_RX_FCF;
334 if ( rxFrameLength + 1 > m_bytes_left ) {
335 // Length of this packet is bigger than the RXFIFO, flush it out.
336 flush();
337
338 } else {
339 if ( !call FIFO.get() && !call FIFOP.get() ) {
340 //m_bytes_left -= rxFrameLength + 1;
341 flush();
342 }
343
344 //if(rxFrameLength <= MAC_PACKET_SIZE) {
345 if(rxFrameLength <= (sizeof(ieee154_header_t) - 1 + TOSH_DATA_LENGTH + 2)){
346 if(rxFrameLength > 0) {
347 if(rxFrameLength > SACK_HEADER_LENGTH) {
348 // This packet has an FCF byte plus at least one more byte to read
349 call RXFIFO.continueRead(buf + 1, SACK_HEADER_LENGTH);
350
351 } else {
352 // This is really a bad packet, skip FCF and get it out of here.
353 flush();
354 //m_state = S_RX_PAYLOAD;
355 //call RXFIFO.continueRead(buf + 1, rxFrameLength);
356 }
357
358 } else {
359 // Length == 0; start reading the next packet
360 flush();
361 /* atomic receivingPacket = FALSE;*/
362 /* call CSN.set();*/
363 /* call SpiResource.release();*/
364 /* waitForNextPacket();*/
365 }
366
367 } else {
368 // Length is too large; we have to flush the entire Rx FIFO
369 flush();
370 }
371 }
372 break;
373
374 case S_RX_FCF:
375 if (call FrameUtility.getMHRLength(buf[1], buf[2], &m_mhrLen) != SUCCESS ||
376 m_mhrLen > rxFrameLength - 2) {
377 // header size incorrect
378 flush();
379 break;
380 } else if (m_mhrLen > SACK_HEADER_LENGTH) {
381 m_state = S_RX_HEADER;
382 call RXFIFO.continueRead(buf + 1 + SACK_HEADER_LENGTH,
383 m_mhrLen - SACK_HEADER_LENGTH);
384 break;
385 } else {
386 // complete header has been read: fall through
387 }
388 // fall through
389
390 case S_RX_HEADER:
391 // JH: we are either using HW ACKs (normal receive mode) or don't ACK any
392 // packets (promiscuous mode)
393 // Didn't flip CSn, we're ok to continue reading.
394 if ((rxFrameLength - m_mhrLen - 2) > TOSH_DATA_LENGTH) // 2 for CRC
395 flush();
396 else {
397 m_state = S_RX_PAYLOAD;
398 call RXFIFO.continueRead((uint8_t*) m_rxFramePtr->data, rxFrameLength - m_mhrLen);
399 }
400 break;
401
402 case S_RX_PAYLOAD:
403 call CSN.set();
404
405 if(!m_missed_packets) {
406 // Release the SPI only if there are no more frames to download
407 call SpiResource.release();
408 }
409
410 if ( m_timestamp_size ) {
411 if ( rxFrameLength > 10 ) {
412 //((ieee154_metadata_t*) m_rxFramePtr->metadata)->timestamp = m_timestamp_queue[ m_timestamp_head ];
413 memcpy(&m_timestamp, &m_timestamp_queue[ m_timestamp_head ], sizeof(ieee154_reftime_t) );
414 m_timestampValid = TRUE;
415 m_timestamp_head = ( m_timestamp_head + 1 ) % TIMESTAMP_QUEUE_SIZE;
416 m_timestamp_size--;
417 }
418 } else {
419 /* metadata->time = 0xffff;*/
420 m_timestampValid = FALSE;
421 //((ieee154_metadata_t*) m_rxFramePtr->metadata)->timestamp = IEEE154_INVALID_TIMESTAMP;
422 }
423
424 // We may have received an ack that should be processed by Transmit
425 // buf[rxFrameLength] >> 7 checks the CRC
426 if ( ( m_rxFramePtr->data[ rxFrameLength - m_mhrLen - 1 ] >> 7 ) && rx_buf ) {
427 uint8_t type = ((ieee154_header_t*) m_rxFramePtr->header)->mhr[0] & 0x07;
428 /* signal CC2420Receive.receive( type, m_p_rx_buf );*/
429 signal CC2420Receive.receive( type, m_rxFramePtr );
430 /* if ( type == IEEE154_TYPE_DATA ) {*/
431 if ( (type != IEEE154_TYPE_ACK || call CC2420Config.isPromiscuousModeEnabled())
432 && !m_stop) {
433 post receiveDone_task();
434 return;
435 }
436 }
437
438 waitForNextPacket();
439 break;
440
441 default:
442 atomic receivingPacket = FALSE;
443 call CSN.set();
444 call SpiResource.release();
445 if (m_stop){
446 continueStop();
447 return;
448 }
449 break;
450
451 }
452 }
453
454 }
455
456 async event void RXFIFO.writeDone( uint8_t* tx_buf, uint8_t tx_len, error_t error ) {
457 }
458
459 /***************** Tasks *****************/
460 /**
461 * Fill in metadata details, pass the packet up the stack, and
462 * get the next packet.
463 */
464 task void receiveDone_task() {
465 uint8_t payloadLen = ((ieee154_header_t*) m_rxFramePtr->header)->length - m_mhrLen - 2;
466 ieee154_metadata_t *metadata = (ieee154_metadata_t*) m_rxFramePtr->metadata;
467
468 atomic {
469 if (m_state == S_STOPPED){
470 call Leds.led0On();
471 return;
472 }
473 }
474 ((ieee154_header_t*) m_rxFramePtr->header)->length = m_rxFramePtr->data[payloadLen+1] & 0x7f; // temp. LQI
475 metadata->rssi = m_rxFramePtr->data[payloadLen];
476 metadata->linkQuality = ((ieee154_header_t*) m_rxFramePtr->header)->length; // copy back
477 ((ieee154_header_t*) m_rxFramePtr->header)->length = payloadLen;
478 if (m_timestampValid)
479 metadata->timestamp = call ReferenceTime.toLocalTime(&m_timestamp);
480 else
481 metadata->timestamp = IEEE154_INVALID_TIMESTAMP;
482 m_rxFramePtr = signal CC2420Rx.received(m_rxFramePtr, &m_timestamp);
483
484 /* cc2420_metadata_t* metadata = call CC2420PacketBody.getMetadata( m_p_rx_buf );*/
485 /* uint8_t* buf = (uint8_t*) call CC2420PacketBody.getHeader( m_p_rx_buf );;*/
486 /* */
487 /* metadata->crc = buf[ rxFrameLength ] >> 7;*/
488 /* metadata->rssi = buf[ rxFrameLength - 1 ];*/
489 /* metadata->lqi = buf[ rxFrameLength ] & 0x7f;*/
490 // async event message_t* receiveDone( message_t *data );
491
492 /* m_p_rx_buf = signal Receive.receive( m_rxFramePtrm_p_rx_buf, m_p_rx_buf->data, */
493 /* rxFrameLength );*/
494
495 atomic receivingPacket = FALSE;
496 waitForNextPacket();
497 }
498
499
500 /****************** Functions ****************/
501 /**
502 * Attempt to acquire the SPI bus to receive a packet.
503 */
504 void beginReceive() {
505 atomic {
506 if (m_state == S_STOPPED || m_stop){
507 return;
508 }
509 m_state = S_RX_LENGTH;
510 receivingPacket = TRUE;
511
512 if(call SpiResource.isOwner()) {
513 receive();
514
515 } else if (call SpiResource.immediateRequest() == SUCCESS) {
516 receive();
517
518 } else {
519 call SpiResource.request();
520 }
521 }
522 }
523
524 /**
525 * Flush out the Rx FIFO
526 */
527 void flush() {
528 reset_state();
529 call CSN.set();
530 call CSN.clr();
531 call SFLUSHRX.strobe();
532 call SFLUSHRX.strobe();
533 call CSN.set();
534 call SpiResource.release();
535 waitForNextPacket();
536 }
537
538 /**
539 * The first byte of each packet is the length byte. Read in that single
540 * byte, and then read in the rest of the packet. The CC2420 could contain
541 * multiple packets that have been buffered up, so if something goes wrong,
542 * we necessarily want to flush out the FIFO unless we have to.
543 */
544 void receive() {
545 call CSN.set();
546 call CSN.clr();
547 //call RXFIFO.beginRead( (uint8_t*)(call CC2420PacketBody.getHeader( m_p_rx_buf )), 1 );
548 call RXFIFO.beginRead( &((ieee154_header_t*) m_rxFramePtr->header)->length, 1 );
549 }
550
551
552 /**
553 * Determine if there's a packet ready to go, or if we should do nothing
554 * until the next packet arrives
555 */
556 void waitForNextPacket() {
557 atomic {
558 if ( m_state == S_STOPPED) {
559 call SpiResource.release();
560 return;
561 }
562 receivingPacket = FALSE;
563 if (m_stop){
564 continueStop();
565 return;
566 }
567
568 if ( ( m_missed_packets && call FIFO.get() ) || !call FIFOP.get() ) {
569 // A new packet is buffered up and ready to go
570 if ( m_missed_packets ) {
571 m_missed_packets--;
572 }
573
574 beginReceive();
575
576 } else {
577 // Wait for the next packet to arrive
578 m_state = S_STARTED;
579 m_missed_packets = 0;
580 call SpiResource.release();
581 }
582 }
583 }
584
585 /**
586 * Reset this component
587 */
588 void reset_state() {
589 m_bytes_left = RXFIFO_SIZE;
590 atomic receivingPacket = FALSE;
591 m_timestamp_head = 0;
592 m_timestamp_size = 0;
593 m_missed_packets = 0;
594 }
595
596 }