source: firmware/openos/openwsn/02a-MAC/IEEE802154E.c @ 1163

Revision 1163, 50.4 KB checked in by thomas, 21 months ago (diff)

Moving the synchronization function at the end of the slot, not to interfere with the slot timing. This is partially fixing #92.

Line 
1#include "openwsn.h"
2#include "IEEE802154E.h"
3#include "radio.h"
4#include "ieee154etimer.h"
5#include "IEEE802154.h"
6#include "openqueue.h"
7#include "idmanager.h"
8#include "openserial.h"
9#include "schedule.h"
10#include "packetfunctions.h"
11#include "scheduler.h"
12#include "leds.h"
13#include "neighbors.h"
14
15//=========================== variables =======================================
16
17typedef struct {
18   // misc
19   asn_t              asn;                  // current absolute slot number
20   uint16_t           deSyncTimeout;        // how many slots left before looses sync
21   bool               isSync;               // TRUE iff mote is synchronized to network
22   // as shown on the chronogram
23   uint8_t            state;                // state of the FSM
24   OpenQueueEntry_t*  dataToSend;           // pointer to the data to send
25   OpenQueueEntry_t*  dataReceived;         // pointer to the data received
26   OpenQueueEntry_t*  ackToSend;            // pointer to the ack to send
27   OpenQueueEntry_t*  ackReceived;          // pointer to the ack received
28   uint16_t           lastCapturedTime;     // last captured time
29   uint16_t           syncCapturedTime;     // captured time used to sync
30} ieee154e_vars_t;
31
32ieee154e_vars_t ieee154e_vars;
33
34// these statistics are reset every time they are reported
35typedef struct {
36   uint8_t            syncCounter;          // how many times we synchronized
37   int16_t            minCorrection;        // minimum time correction
38   int16_t            maxCorrection;        // maximum time correction
39   uint8_t            numDeSync;            // number of times a desync happened
40} ieee154e_stats_t;
41
42ieee154e_stats_t ieee154e_stats;
43
44//=========================== prototypes ======================================
45
46// SYNCHRONIZING
47void     activity_synchronize_newSlot();
48void     activity_synchronize_startOfFrame(uint16_t capturedTime);
49void     activity_synchronize_endOfFrame(uint16_t capturedTime);
50// TX
51void     activity_ti1ORri1();
52void     activity_ti2();
53void     activity_tie1();
54void     activity_ti3();
55void     activity_tie2();
56void     activity_ti4(uint16_t capturedTime);
57void     activity_tie3();
58void     activity_ti5(uint16_t capturedTime);
59void     activity_ti6();
60void     activity_tie4();
61void     activity_ti7();
62void     activity_tie5();
63void     activity_ti8(uint16_t capturedTime);
64void     activity_tie6();
65void     activity_ti9(uint16_t capturedTime);
66// RX
67void     activity_ri2();
68void     activity_rie1();
69void     activity_ri3();
70void     activity_rie2();
71void     activity_ri4(uint16_t capturedTime);
72void     activity_rie3();
73void     activity_ri5(uint16_t capturedTime);
74void     activity_ri6();
75void     activity_rie4();
76void     activity_ri7();
77void     activity_rie5();
78void     activity_ri8(uint16_t capturedTime);
79void     activity_rie6();
80void     activity_ri9(uint16_t capturedTime);
81// frame validity check
82bool     isValidAdv(ieee802154_header_iht*     ieee802514_header);
83bool     isValidRxFrame(ieee802154_header_iht* ieee802514_header);
84bool     isValidAck(ieee802154_header_iht*     ieee802514_header,
85                    OpenQueueEntry_t*          packetSent);
86// ASN handling
87void     asnWrite(OpenQueueEntry_t* advFrame);
88uint16_t asnRead (OpenQueueEntry_t* advFrame);
89// synchronization
90void     synchronizePacket(uint16_t timeReceived, open_addr_t* advFrom);
91void     synchronizeAck(int16_t timeCorrection, open_addr_t* advFrom);
92void     changeIsSync(bool newIsSync);
93// notifying upper layer
94void     notif_sendDone(OpenQueueEntry_t* packetSent, error_t error);
95void     notif_receive(OpenQueueEntry_t* packetReceived);
96// statistics
97void     resetStats();
98void     updateStats(int16_t timeCorrection);
99// misc
100uint8_t  calculateFrequency(asn_t asn, uint8_t channelOffset);
101void     changeState(uint8_t newstate);
102void     endSlot();
103bool     debugPrint_asn();
104bool     debugPrint_isSync();
105
106//=========================== admin ===========================================
107
108/**
109\brief This function initializes this module.
110
111Call this function once before any other function in this module, possibly
112during boot-up.
113*/
114void mac_init() {   
115   // initialize debug pins
116   DEBUG_PIN_FRAME_INIT();
117   DEBUG_PIN_SLOT_INIT();
118   DEBUG_PIN_FSM_INIT();
119   
120   // initialize variables
121   ieee154e_vars.asn                        = 0;
122   ieee154e_vars.deSyncTimeout              = 0;
123   if (idmanager_getIsDAGroot()==TRUE) {
124      changeIsSync(TRUE);
125   } else {
126      changeIsSync(FALSE);
127   }
128   ieee154e_vars.state                      = S_SLEEP;
129   ieee154e_vars.dataToSend                 = NULL;
130   ieee154e_vars.dataReceived               = NULL;
131   ieee154e_vars.ackToSend                  = NULL;
132   ieee154e_vars.ackReceived                = NULL;
133   ieee154e_vars.lastCapturedTime           = 0;
134   ieee154e_vars.syncCapturedTime           = 0;
135   
136   resetStats();
137   ieee154e_stats.numDeSync                 = 0;
138   
139   // initialize (and start) IEEE802.15.4e timer
140   ieee154etimer_init();
141}
142
143//=========================== public ==========================================
144
145__monitor asn_t ieee154e_getAsn() {
146   return ieee154e_vars.asn;
147}
148
149//======= events
150
151/**
152\brief Indicates a new slot has just started.
153
154This function executes in ISR mode, when the new slot timer fires.
155*/
156void isr_ieee154e_newSlot() {
157   TACCR0 =  TsSlotDuration;
158   if (ieee154e_vars.isSync==FALSE) {
159      activity_synchronize_newSlot();
160   } else {
161      activity_ti1ORri1();
162   }
163}
164
165/**
166\brief Indicates the FSM timer has fired.
167
168This function executes in ISR mode, when the FSM timer fires.
169*/
170void isr_ieee154e_timer() {
171   switch (ieee154e_vars.state) {
172      case S_TXDATAOFFSET:
173         activity_ti2();
174         break;
175      case S_TXDATAPREPARE:
176         activity_tie1();
177         break;
178      case S_TXDATAREADY:
179         activity_ti3();
180         break;
181      case S_TXDATADELAY:
182         activity_tie2();
183         break;
184      case S_TXDATA:
185         activity_tie3();
186         break;
187      case S_RXACKOFFSET:
188         activity_ti6();
189         break;
190      case S_RXACKPREPARE:
191         activity_tie4();
192         break;
193      case S_RXACKREADY:
194         activity_ti7();
195         break;
196      case S_RXACKLISTEN:
197         activity_tie5();
198         break;
199      case S_RXACK:
200         activity_tie6();
201         break;
202      case S_RXDATAOFFSET:
203         activity_ri2();
204         break;
205      case S_RXDATAPREPARE:
206         activity_rie1();
207         break;
208      case S_RXDATAREADY:
209         activity_ri3();
210         break;
211      case S_RXDATALISTEN:
212         activity_rie2();
213         break;
214      case S_RXDATA:
215         activity_rie3();
216         break;
217      case S_TXACKOFFSET:
218         activity_ri6();
219         break;
220      case S_TXACKPREPARE:
221         activity_rie4();
222         break;
223      case S_TXACKREADY:
224         activity_ri7();
225         break;
226      case S_TXACKDELAY:
227         activity_rie5();
228         break;
229      case S_TXACK:
230         activity_rie6();
231         break;
232      default:
233         // log the error
234         openserial_printError(COMPONENT_IEEE802154E,
235                               ERR_WRONG_STATE_IN_TIMERFIRES,
236                               ieee154e_vars.state,
237                               ieee154e_vars.asn%SCHEDULELENGTH);
238         // abort
239         endSlot();
240         break;
241   }
242}
243
244/**
245\brief Indicates the radio just received the first byte of a packet.
246
247This function executes in ISR mode.
248*/
249void ieee154e_startOfFrame(uint16_t capturedTime) {
250   if (ieee154e_vars.isSync==FALSE) {
251      activity_synchronize_startOfFrame(capturedTime);
252   } else {
253      switch (ieee154e_vars.state) {
254         case S_TXDATADELAY:
255            activity_ti4(capturedTime);
256            break;
257         case S_RXACKLISTEN:
258            activity_ti8(capturedTime);
259            break;
260         case S_RXDATALISTEN:
261            activity_ri4(capturedTime);
262            break;
263         case S_TXACKDELAY:
264            activity_ri8(capturedTime);
265            break;
266         default:
267            // log the error
268            openserial_printError(COMPONENT_IEEE802154E,
269                                  ERR_WRONG_STATE_IN_NEWSLOT,
270                                  ieee154e_vars.state,
271                                  ieee154e_vars.asn%SCHEDULELENGTH);
272            // abort
273            endSlot();
274            break;
275      }
276   }
277}
278
279/**
280\brief Indicates the radio just received the last byte of a packet.
281
282This function executes in ISR mode.
283*/
284void ieee154e_endOfFrame(uint16_t capturedTime) {
285   if (ieee154e_vars.isSync==FALSE) {
286      activity_synchronize_endOfFrame(capturedTime);
287   } else {
288      switch (ieee154e_vars.state) {
289         case S_TXDATA:
290            activity_ti5(capturedTime);
291            break;
292         case S_RXACK:
293            activity_ti9(capturedTime);
294            break;
295         case S_RXDATA:
296            activity_ri5(capturedTime);
297            break;
298         case S_TXACK:
299            activity_ri9(capturedTime);
300            break;
301         default:
302            // log the error
303            openserial_printError(COMPONENT_IEEE802154E,
304                                  ERR_WRONG_STATE_IN_ENDOFFRAME,
305                                  ieee154e_vars.state,
306                                  ieee154e_vars.asn%SCHEDULELENGTH);
307            // abort
308            endSlot();
309            break;
310      }
311   }
312}
313
314//======= misc
315
316bool debugPrint_asn() {
317   uint16_t output=0;
318   output = ieee154e_vars.asn;
319   openserial_printStatus(STATUS_ASN,(uint8_t*)&output,sizeof(uint16_t));
320   return TRUE;
321}
322
323bool debugPrint_isSync() {
324   uint8_t output=0;
325   output = ieee154e_vars.isSync;
326   openserial_printStatus(STATUS_ISSYNC,(uint8_t*)&output,sizeof(uint8_t));
327   return TRUE;
328}
329
330bool debugPrint_macStats() {
331   // send current stats over serial
332   openserial_printStatus(STATUS_MACSTATS,(uint8_t*)&ieee154e_stats,sizeof(ieee154e_stats_t));
333   return TRUE;
334}
335
336//=========================== private =========================================
337
338//======= SYNCHRONIZING
339
340inline void activity_synchronize_newSlot() {
341   // I'm in the middle of receiving a packet
342   if (ieee154e_vars.state==S_SYNCRX) {
343      return;
344   }
345   
346   // if this is the first time I call this function while not synchronized,
347   // switch on the radio in Rx mode
348   if (ieee154e_vars.state!=S_SYNCLISTEN) {
349      // change state
350      changeState(S_SYNCLISTEN);
351     
352      // turn off the radio (in case it wasn't yet)
353      radio_rfOff();
354     
355      // configure the radio to listen to the default synchronizing channel
356      radio_setFrequency(SYNCHRONIZING_CHANNEL);
357     
358      // switch on the radio in Rx mode.
359      radio_rxEnable();
360      radio_rxNow();
361   }
362
363   // we want to be able to receive and transmist serial even when not synchronized
364   // take turns every other slot to send or receive
365   openserial_stop();
366   if (ieee154e_vars.asn%2==0) {
367      openserial_startOutput();
368   } else {
369      openserial_startInput();
370   }
371}
372
373inline void activity_synchronize_startOfFrame(uint16_t capturedTime) {
374   
375   // don't care about packet if I'm not listening
376   if (ieee154e_vars.state!=S_SYNCLISTEN) {
377      return;
378   }
379   
380   // change state
381   changeState(S_SYNCRX);
382   
383   // stop the serial
384   openserial_stop();
385   
386   // record the captured time
387   ieee154e_vars.lastCapturedTime = capturedTime;
388   
389   // record the captured time (for sync)
390   ieee154e_vars.syncCapturedTime = capturedTime;
391}
392
393inline void activity_synchronize_endOfFrame(uint16_t capturedTime) {
394   ieee802154_header_iht ieee802514_header;
395   
396   // check state
397   if (ieee154e_vars.state!=S_SYNCRX) {
398      // log the error
399      openserial_printError(COMPONENT_IEEE802154E,
400                            ERR_WRONG_STATE_IN_ENDFRAME_SYNC,
401                            ieee154e_vars.state,
402                            0);
403      // abort
404      endSlot();
405   }
406   
407   // change state
408   changeState(S_SYNCPROC);
409   
410   // get a buffer to put the (received) frame in
411   ieee154e_vars.dataReceived = openqueue_getFreePacketBuffer();
412   if (ieee154e_vars.dataReceived==NULL) {
413      // log the error
414      openserial_printError(COMPONENT_IEEE802154E,
415                            ERR_NO_FREE_PACKET_BUFFER,
416                            0,
417                            0);
418      // abort
419      endSlot();
420      return;
421   }
422   
423   // declare ownership over that packet
424   ieee154e_vars.dataReceived->creator = COMPONENT_IEEE802154E;
425   ieee154e_vars.dataReceived->owner   = COMPONENT_IEEE802154E;
426   
427   // retrieve the received data frame from the radio's Rx buffer
428   radio_getReceivedFrame(ieee154e_vars.dataReceived);
429   
430   /*
431   The do-while loop that follows is a little parsing trick.
432   Because it contains a while(0) condition, it gets executed only once.
433   The behavior is:
434   - if a break occurs inside the do{} body, the error code below the loop
435     gets executed. This indicates something is wrong with the packet being
436     parsed.
437   - if a return occurs inside the do{} body, the error code below the loop
438     does not get executed. This indicates the received packet is correct.
439   */
440   do { // this "loop" is only executed once
441     
442      // break if invalid CRC
443      if (ieee154e_vars.dataReceived->l1_crc==FALSE) {
444         // break from the do-while loop and execute abort code below
445         break;
446      }
447     
448      // parse the IEEE802.15.4 header
449      ieee802154_retrieveHeader(ieee154e_vars.dataReceived,&ieee802514_header);
450     
451      // store header details in packet buffer
452      ieee154e_vars.dataReceived->l2_frameType = ieee802514_header.frameType;
453      ieee154e_vars.dataReceived->l2_dsn       = ieee802514_header.dsn;
454      memcpy(&(ieee154e_vars.dataReceived->l2_nextORpreviousHop),&(ieee802514_header.src),sizeof(open_addr_t));
455     
456      // toss the IEEE802.15.4 header
457      packetfunctions_tossHeader(ieee154e_vars.dataReceived,ieee802514_header.headerLength);
458     
459      // if I just received a valid ADV, handle
460      if (isValidAdv(&ieee802514_header)==TRUE) {
461         
462         // turn off the radio
463         radio_rfOff();
464         
465         // record the ASN from the ADV payload
466         ieee154e_vars.asn = asnRead(ieee154e_vars.dataReceived);
467         
468         // toss the ADV payload
469         packetfunctions_tossHeader(ieee154e_vars.dataReceived,sizeof(asn_t));
470         
471         // synchronize (for the first time) to the sender's ADV
472         synchronizePacket(ieee154e_vars.syncCapturedTime,&(ieee154e_vars.dataReceived->l2_nextORpreviousHop));
473         
474         // declare synchronized
475         changeIsSync(TRUE);
476         
477         // log the "error"
478         openserial_printError(COMPONENT_IEEE802154E,
479                               ERR_SYNCHRONIZED,
480                               ieee154e_vars.asn,
481                               0);
482         
483         // send received ADV up the stack so RES can update statistics (synchronizing)
484         notif_receive(ieee154e_vars.dataReceived);
485         
486         // clear local variable
487         ieee154e_vars.dataReceived = NULL;
488         
489         // official end of synchronization
490         endSlot();
491         
492         // everything went well, return here not to execute the error code below
493         return;
494      }
495   } while (0);
496   
497   // free the (invalid) received data buffer so RAM memory can be recycled
498   openqueue_freePacketBuffer(ieee154e_vars.dataReceived);
499   
500   // clear local variable
501   ieee154e_vars.dataReceived = NULL;
502}
503
504//======= TX
505
506inline void activity_ti1ORri1() {
507   uint8_t cellType;
508   open_addr_t neighbor;
509   
510   // stop outputting serial data
511   openserial_stop();
512   
513   // increment ASN (do this first so debug pins are in sync)
514   ieee154e_vars.asn++;
515   
516   // wiggle debug pins
517   DEBUG_PIN_SLOT_TOGGLE();
518   if (ieee154e_vars.asn%SCHEDULELENGTH==0) {
519      DEBUG_PIN_FRAME_TOGGLE();
520   }
521   
522   // desynchronize if needed
523   if (idmanager_getIsDAGroot()==FALSE) {
524      ieee154e_vars.deSyncTimeout--;
525      if (ieee154e_vars.deSyncTimeout==0) {
526         // declare myself desynchronized
527         changeIsSync(FALSE);
528         
529         // log the error
530         openserial_printError(COMPONENT_IEEE802154E,
531                               ERR_DESYNCHRONIZED,
532                               ieee154e_vars.asn,
533                               0);
534           
535         // update the statistics
536         ieee154e_stats.numDeSync++;
537           
538         // abort
539         endSlot();
540         return;
541      }
542   }
543
544   // if the previous slot took too long, we will not be in the right state
545   if (ieee154e_vars.state!=S_SLEEP) {
546      // log the error
547      openserial_printError(COMPONENT_IEEE802154E,
548                            ERR_WRONG_STATE_IN_STARTSLOT,
549                            ieee154e_vars.state,
550                            ieee154e_vars.asn%SCHEDULELENGTH);
551      // abort
552      endSlot();
553      return;
554   }
555
556   // check the schedule to see what type of slot this is
557   cellType = schedule_getType(ieee154e_vars.asn);
558   switch (cellType) {
559      case CELLTYPE_OFF:
560         // I have nothing to do
561         // abort
562         endSlot();
563         //start outputing serial
564         openserial_startOutput();
565         break;
566      case CELLTYPE_ADV:
567         ieee154e_vars.dataToSend = openqueue_macGetAdvPacket();
568         if (ieee154e_vars.dataToSend==NULL) {   // I will be listening for an ADV
569            // change state
570            changeState(S_RXDATAOFFSET);
571            // arm rt1
572            ieee154etimer_schedule(DURATION_rt1);
573         } else {                                // I will be sending an ADV
574            // change state
575            changeState(S_TXDATAOFFSET);
576            // change owner
577            ieee154e_vars.dataToSend->owner = COMPONENT_IEEE802154E;
578            // fill in the ASN field of the ADV
579            asnWrite(ieee154e_vars.dataToSend);
580            // record that I attempt to transmit this packet
581            ieee154e_vars.dataToSend->l2_numTxAttempts++;
582            // arm tt1
583            ieee154etimer_schedule(DURATION_tt1);
584         }
585         break;
586      case CELLTYPE_TX:
587         schedule_getNeighbor(ieee154e_vars.asn,&neighbor);
588         ieee154e_vars.dataToSend = openqueue_macGetDataPacket(&neighbor);
589         if (ieee154e_vars.dataToSend!=NULL) {   // I have a packet to send
590            // change state
591            changeState(S_TXDATAOFFSET);
592            // change owner
593            ieee154e_vars.dataToSend->owner = COMPONENT_IEEE802154E;
594            // record that I attempt to transmit this packet
595            ieee154e_vars.dataToSend->l2_numTxAttempts++;
596            // arm tt1
597            ieee154etimer_schedule(DURATION_tt1);
598         } else {
599            // abort
600            endSlot();
601         }
602         break;
603      case CELLTYPE_RX:
604         // I need to listen for packet
605         // change state
606         changeState(S_RXDATAOFFSET);
607         // arm rt1
608         ieee154etimer_schedule(DURATION_rt1);
609         break;
610      case CELLTYPE_SERIALRX:
611         // TODO
612         break;
613      default:
614         // log the error
615         openserial_printError(COMPONENT_IEEE802154E,
616                               ERR_WRONG_CELLTYPE,
617                               cellType,
618                               ieee154e_vars.asn%SCHEDULELENGTH);
619         // abort
620         endSlot();
621         break;
622   }
623}
624
625inline void activity_ti2() {
626   uint8_t frequency;
627   
628   // change state
629   changeState(S_TXDATAPREPARE);
630
631   // calculate the frequency to transmit on
632   frequency = calculateFrequency(ieee154e_vars.asn, schedule_getChannelOffset(ieee154e_vars.asn) );
633
634   // configure the radio for that frequency
635   radio_setFrequency(frequency);
636
637   // load the packet in the radio's Tx buffer
638   radio_loadPacket(ieee154e_vars.dataToSend);
639
640   // enable the radio in Tx mode. This does not send the packet.
641   radio_txEnable();
642
643   // arm tt2
644   ieee154etimer_schedule(DURATION_tt2);
645
646   // change state
647   changeState(S_TXDATAREADY);
648}
649
650inline void activity_tie1() {
651   // log the error
652   openserial_printError(COMPONENT_IEEE802154E,
653                         ERR_MAXTXDATAPREPARE_OVERFLOW,
654                         ieee154e_vars.state,
655                         ieee154e_vars.asn%SCHEDULELENGTH);
656
657   // abort
658   endSlot();
659}
660
661inline void activity_ti3() {
662   // change state
663   changeState(S_TXDATADELAY);
664   
665   // arm tt3
666   ieee154etimer_schedule(DURATION_tt3);
667   
668   // give the 'go' to transmit
669   radio_txNow();
670}
671
672inline void activity_tie2() {
673   // log the error
674   openserial_printError(COMPONENT_IEEE802154E,
675                         ERR_WDRADIO_OVERFLOW,
676                         ieee154e_vars.state,
677                         ieee154e_vars.asn%SCHEDULELENGTH);
678
679   // abort
680   endSlot();
681}
682
683inline void activity_ti4(uint16_t capturedTime) {
684   // change state
685   changeState(S_TXDATA);
686
687   // cancel tt3
688   ieee154etimer_cancel();
689
690   // record the captured time
691   ieee154e_vars.lastCapturedTime = capturedTime;
692   
693   // arm tt4
694   ieee154etimer_schedule(DURATION_tt4);
695}
696
697inline void activity_tie3() {
698   // log the error
699   openserial_printError(COMPONENT_IEEE802154E,
700                         ERR_WDDATADURATION_OVERFLOWS,
701                         ieee154e_vars.state,
702                         ieee154e_vars.asn%SCHEDULELENGTH);
703
704   // abort
705   endSlot();
706}
707
708inline void activity_ti5(uint16_t capturedTime) {
709   bool listenForAck;
710   
711   // change state
712   changeState(S_RXACKOFFSET);
713   
714   // cancel tt4
715   ieee154etimer_cancel();
716   
717   // turn off the radio
718   radio_rfOff();
719
720   // record the captured time
721   ieee154e_vars.lastCapturedTime = capturedTime;
722
723   // decides whether to listen for an ACK
724   if (packetfunctions_isBroadcastMulticast(&ieee154e_vars.dataToSend->l2_nextORpreviousHop)==TRUE) {
725      listenForAck = FALSE;
726   } else {
727      listenForAck = TRUE;
728   }
729
730   if (listenForAck==TRUE) {
731      // arm tt5
732      ieee154etimer_schedule(DURATION_tt5);
733   } else {
734      // indicate that the packet was sent successfully
735      notif_sendDone(ieee154e_vars.dataToSend,E_SUCCESS);
736      // reset local variable
737      ieee154e_vars.dataToSend = NULL;
738      // abort
739      endSlot();
740   }
741}
742
743inline void activity_ti6() {
744   uint8_t frequency;
745   
746   // change state
747   changeState(S_RXACKPREPARE);
748
749   // calculate the frequency to transmit on
750   frequency = calculateFrequency(ieee154e_vars.asn, schedule_getChannelOffset(ieee154e_vars.asn));
751
752   // configure the radio for that frequency
753   radio_setFrequency(frequency);
754
755   // enable the radio in Rx mode. The radio is not actively listening yet.
756   radio_rxEnable();
757
758   // arm tt6
759   ieee154etimer_schedule(DURATION_tt6);
760   
761   // change state
762   changeState(S_RXACKREADY);
763}
764
765inline void activity_tie4() {
766   // log the error
767   openserial_printError(COMPONENT_IEEE802154E,
768                         ERR_MAXRXACKPREPARE_OVERFLOWS,
769                         ieee154e_vars.state,
770                         ieee154e_vars.asn%SCHEDULELENGTH);
771
772   // abort
773   endSlot();
774}
775
776inline void activity_ti7() {
777   // change state
778   changeState(S_RXACKLISTEN);
779
780   // start listening
781   radio_rxNow();
782
783   // arm tt7
784   ieee154etimer_schedule(DURATION_tt7);
785}
786
787inline void activity_tie5() {
788   // transmit failed, decrement transmits left counter
789   ieee154e_vars.dataToSend->l2_retriesLeft--;
790
791   if (ieee154e_vars.dataToSend->l2_retriesLeft==0) {
792      // indicate tx fail if no more retries left
793      notif_sendDone(ieee154e_vars.dataToSend,E_FAIL);
794   } else {
795      // return packet to the virtual COMPONENT_RES_TO_IEEE802154E component
796      ieee154e_vars.dataToSend->owner = COMPONENT_RES_TO_IEEE802154E;
797   }
798
799   // reset local variable
800   ieee154e_vars.dataToSend = NULL;
801
802   // abort
803   endSlot();
804}
805
806inline void activity_ti8(uint16_t capturedTime) {
807   // change state
808   changeState(S_RXACK);
809   
810   // cancel tt7
811   ieee154etimer_cancel();
812
813   // record the captured time
814   ieee154e_vars.lastCapturedTime = capturedTime;
815
816   // arm tt8
817   ieee154etimer_schedule(DURATION_tt8);
818}
819
820inline void activity_tie6() {
821   // abort
822   endSlot();
823}
824
825inline void activity_ti9(uint16_t capturedTime) {
826   ieee802154_header_iht ieee802514_header;
827   volatile int16_t  timeCorrection;
828   
829   // change state
830   changeState(S_TXPROC);
831   
832   // cancel tt8
833   ieee154etimer_cancel();
834   
835   // turn off the radio
836   radio_rfOff();
837
838   // record the captured time
839   ieee154e_vars.lastCapturedTime = capturedTime;
840   
841   // get a buffer to put the (received) ACK in
842   ieee154e_vars.ackReceived = openqueue_getFreePacketBuffer();
843   if (ieee154e_vars.ackReceived==NULL) {
844      // log the error
845      openserial_printError(COMPONENT_IEEE802154E,
846                            ERR_NO_FREE_PACKET_BUFFER,
847                            0,
848                            0);
849      // abort
850      endSlot();
851      return;
852   }
853   
854   // declare ownership over that packet
855   ieee154e_vars.ackReceived->creator = COMPONENT_IEEE802154E;
856   ieee154e_vars.ackReceived->owner   = COMPONENT_IEEE802154E;
857   
858   // retrieve the received ack frame from the radio's Rx buffer
859   radio_getReceivedFrame(ieee154e_vars.ackReceived);
860   
861   /*
862   The do-while loop that follows is a little parsing trick.
863   Because it contains a while(0) condition, it gets executed only once.
864   Below the do-while loop is some code to cleans up the ack variable.
865   Anywhere in the do-while loop, a break statement can be called to jump to
866   the clean up code early. If the loop ends without a break, the received
867   packet was correct. If it got aborted early (through a break), the packet
868   was faulty.
869   */
870   do { // this "loop" is only executed once
871     
872      // break if invalid CRC
873      if (ieee154e_vars.ackReceived->l1_crc==FALSE) {
874         // break from the do-while loop and execute the clean-up code below
875         break;
876      }
877     
878      // parse the IEEE802.15.4 header
879      ieee802154_retrieveHeader(ieee154e_vars.ackReceived,&ieee802514_header);
880     
881      // store header details in packet buffer
882      ieee154e_vars.ackReceived->l2_frameType  = ieee802514_header.frameType;
883      ieee154e_vars.ackReceived->l2_dsn        = ieee802514_header.dsn;
884      memcpy(&(ieee154e_vars.ackReceived->l2_nextORpreviousHop),&(ieee802514_header.src),sizeof(open_addr_t));
885     
886      // toss the IEEE802.15.4 header
887      packetfunctions_tossHeader(ieee154e_vars.ackReceived,ieee802514_header.headerLength);
888     
889      // if frame is a valid ACK, handle
890      if (isValidAck(&ieee802514_header,ieee154e_vars.dataToSend)==TRUE) {
891         
892         // resynchronize
893         timeCorrection = (int16_t)(ieee154e_vars.ackReceived->payload[1]<<8 | ieee154e_vars.ackReceived->payload[0]);
894         synchronizeAck(timeCorrection,&(ieee154e_vars.ackReceived->l2_nextORpreviousHop));
895         
896         // inform upper layer
897         notif_sendDone(ieee154e_vars.dataToSend,E_SUCCESS);
898         ieee154e_vars.dataToSend = NULL;
899      }
900     
901      // in any case, execute the clean-up code below
902   } while (0);
903   
904   // free the received ack so corresponding RAM memory can be recycled
905   openqueue_freePacketBuffer(ieee154e_vars.ackReceived);
906   
907   // clear local variable
908   ieee154e_vars.ackReceived = NULL;
909
910   // official end of Tx slot
911   endSlot();
912}
913
914//======= RX
915
916inline void activity_ri2() {
917   uint8_t frequency;
918   
919   // change state
920   changeState(S_RXDATAPREPARE);
921
922   // calculate the frequency to transmit on
923   frequency = calculateFrequency(ieee154e_vars.asn, schedule_getChannelOffset(ieee154e_vars.asn) );
924
925   // configure the radio for that frequency
926   radio_setFrequency(frequency);
927
928   // enable the radio in Rx mode. The radio does not actively listen yet.
929   radio_rxEnable();
930
931   // arm rt2
932   ieee154etimer_schedule(DURATION_rt2);
933
934   // change state
935   changeState(S_RXDATAREADY);
936}
937
938inline void activity_rie1() {
939   // log the error
940   openserial_printError(COMPONENT_IEEE802154E,
941                         ERR_MAXRXDATAPREPARE_OVERFLOWS,
942                         ieee154e_vars.state,
943                         ieee154e_vars.asn%SCHEDULELENGTH);
944
945   // abort
946   endSlot();
947}
948
949inline void activity_ri3() {
950   // change state
951   changeState(S_RXDATALISTEN);
952
953   // give the 'go' to receive
954   radio_rxNow();
955
956   // arm rt3
957   ieee154etimer_schedule(DURATION_rt3);
958}
959
960inline void activity_rie2() {
961   // abort
962   endSlot();
963}
964
965inline void activity_ri4(uint16_t capturedTime) {
966   // change state
967   changeState(S_RXDATA);
968   
969   // cancel rt3
970   ieee154etimer_cancel();
971
972   // record the captured time
973   ieee154e_vars.lastCapturedTime = capturedTime;
974   
975   // record the captured time to sync
976   ieee154e_vars.syncCapturedTime = capturedTime;
977
978   // arm rt4
979   ieee154etimer_schedule(DURATION_rt4);
980}
981
982inline void activity_rie3() {
983   // log the error
984   openserial_printError(COMPONENT_IEEE802154E,
985                         ERR_WDDATADURATION_OVERFLOWS,
986                         ieee154e_vars.state,
987                         ieee154e_vars.asn%SCHEDULELENGTH);
988   
989   // abort
990   endSlot();
991}
992
993inline void activity_ri5(uint16_t capturedTime) {
994   ieee802154_header_iht ieee802514_header;
995   
996   // change state
997   changeState(S_TXACKOFFSET);
998   
999   // cancel rt4
1000   ieee154etimer_cancel();
1001   
1002   // turn off the radio
1003   radio_rfOff();
1004   
1005   // get a buffer to put the (received) data in
1006   ieee154e_vars.dataReceived = openqueue_getFreePacketBuffer();
1007   if (ieee154e_vars.dataReceived==NULL) {
1008      // log the error
1009      openserial_printError(COMPONENT_IEEE802154E,
1010                            ERR_NO_FREE_PACKET_BUFFER,
1011                            0,
1012                            0);
1013      // abort
1014      endSlot();
1015      return;
1016   }
1017   
1018   // declare ownership over that packet
1019   ieee154e_vars.dataReceived->creator = COMPONENT_IEEE802154E;
1020   ieee154e_vars.dataReceived->owner   = COMPONENT_IEEE802154E;
1021   
1022   // retrieve the received data frame from the radio's Rx buffer
1023   radio_getReceivedFrame(ieee154e_vars.dataReceived);
1024
1025   /*
1026   The do-while loop that follows is a little parsing trick.
1027   Because it contains a while(0) condition, it gets executed only once.
1028   The behavior is:
1029   - if a break occurs inside the do{} body, the error code below the loop
1030     gets executed. This indicates something is wrong with the packet being
1031     parsed.
1032   - if a return occurs inside the do{} body, the error code below the loop
1033     does not get executed. This indicates the received packet is correct.
1034   */
1035   do { // this "loop" is only executed once
1036     
1037      // if CRC doesn't check, stop
1038      if (ieee154e_vars.dataReceived->l1_crc==FALSE) {
1039         // jump to the error code below this do-while loop
1040         break;
1041      }
1042     
1043      // parse the IEEE802.15.4 header
1044      ieee802154_retrieveHeader(ieee154e_vars.dataReceived,&ieee802514_header);
1045     
1046      // store header details in packet buffer
1047      ieee154e_vars.dataReceived->l2_frameType = ieee802514_header.frameType;
1048      ieee154e_vars.dataReceived->l2_dsn       = ieee802514_header.dsn;
1049      memcpy(&(ieee154e_vars.dataReceived->l2_nextORpreviousHop),&(ieee802514_header.src),sizeof(open_addr_t));
1050     
1051      // toss the IEEE802.15.4 header
1052      packetfunctions_tossHeader(ieee154e_vars.dataReceived,ieee802514_header.headerLength);
1053     
1054      // if I just received a valid ADV, record the ASN and toss the payload
1055      if (isValidAdv(&ieee802514_header)==TRUE) {
1056         if (idmanager_getIsDAGroot()==FALSE) {
1057            if (ieee154e_vars.asn != asnRead(ieee154e_vars.dataReceived)) {
1058               // log the error
1059               openserial_printError(COMPONENT_IEEE802154E,
1060                                     ERR_ASN_MISALIGNEMENT,
1061                                     0,
1062                                     0);
1063               // update the ASN to try to recover
1064               ieee154e_vars.asn = asnRead(ieee154e_vars.dataReceived);
1065            };
1066         }
1067         // toss the ADV payload
1068         packetfunctions_tossHeader(ieee154e_vars.dataReceived,sizeof(asn_t));
1069      }
1070     
1071      // record the captured time
1072      ieee154e_vars.lastCapturedTime = capturedTime;
1073     
1074      // if I just received an invalid frame, stop
1075      if (isValidRxFrame(&ieee802514_header)==FALSE) {
1076         // jump to the error code below this do-while loop
1077         break;
1078      }
1079     
1080      // check if ack requested
1081      if (ieee802514_header.ackRequested==1) {
1082         // arm rt5
1083         ieee154etimer_schedule(DURATION_rt5);
1084      } else {
1085         // synchronize to the received packet
1086         synchronizePacket(ieee154e_vars.syncCapturedTime,&(ieee154e_vars.dataReceived->l2_nextORpreviousHop));
1087         // indicate reception to upper layer (no ACK asked)
1088         notif_receive(ieee154e_vars.dataReceived);
1089         // reset local variable
1090         ieee154e_vars.dataReceived = NULL;
1091         // abort
1092         endSlot();
1093      }
1094     
1095      // everything went well, return here not to execute the error code below
1096      return;
1097     
1098   } while(0);
1099   
1100   // free the (invalid) received data so RAM memory can be recycled
1101   openqueue_freePacketBuffer(ieee154e_vars.dataReceived);
1102   
1103   // clear local variable
1104   ieee154e_vars.dataReceived = NULL;
1105   
1106   // abort
1107   endSlot();
1108}
1109
1110inline void activity_ri6() {
1111   int16_t timeCorrection;
1112   uint8_t frequency;
1113   
1114   // change state
1115   changeState(S_TXACKPREPARE);
1116   
1117   // get a buffer to put the ack to send in
1118   ieee154e_vars.ackToSend = openqueue_getFreePacketBuffer();
1119   if (ieee154e_vars.ackToSend==NULL) {
1120      // log the error
1121      openserial_printError(COMPONENT_IEEE802154E,
1122                            ERR_NO_FREE_PACKET_BUFFER,
1123                            0,
1124                            0);
1125      // indicate we received a packet anyway (we don't want to loose any)
1126      notif_receive(ieee154e_vars.dataReceived);
1127      // free local variable
1128      ieee154e_vars.dataReceived = NULL;
1129      // abort
1130      endSlot();
1131      return;
1132   }
1133   
1134   // declare ownership over that packet
1135   ieee154e_vars.ackToSend->creator = COMPONENT_IEEE802154E;
1136   ieee154e_vars.ackToSend->owner   = COMPONENT_IEEE802154E;
1137   
1138   // calculate the time timeCorrection
1139   timeCorrection = (int16_t)((int16_t)ieee154e_vars.syncCapturedTime-(int16_t)TsTxOffset);
1140   
1141   // add the payload to the ACK (i.e. the timeCorrection)
1142   packetfunctions_reserveHeaderSize(ieee154e_vars.ackToSend,sizeof(IEEE802154E_ACK_ht));
1143   ((IEEE802154E_ACK_ht*)(ieee154e_vars.ackToSend->payload))->timeCorrection[0] = (timeCorrection >> 0) & 0xff;
1144   ((IEEE802154E_ACK_ht*)(ieee154e_vars.ackToSend->payload))->timeCorrection[1] = (timeCorrection >> 8) & 0xff;
1145   
1146   // prepend the IEEE802.15.4 header to the ACK
1147   ieee154e_vars.ackToSend->l2_frameType = IEEE154_TYPE_ACK;
1148   ieee154e_vars.ackToSend->l2_dsn       = ieee154e_vars.dataReceived->l2_dsn;
1149   ieee802154_prependHeader(ieee154e_vars.ackToSend,
1150                            ieee154e_vars.ackToSend->l2_frameType,
1151                            IEEE154_SEC_NO_SECURITY,
1152                            ieee154e_vars.dataReceived->l2_dsn,
1153                            &(ieee154e_vars.dataReceived->l2_nextORpreviousHop)
1154                            );
1155   
1156   // space for 2-byte CRC
1157   packetfunctions_reserveFooterSize(ieee154e_vars.ackToSend,2);
1158   
1159   // calculate the frequency to transmit on
1160   frequency = calculateFrequency(ieee154e_vars.asn, schedule_getChannelOffset(ieee154e_vars.asn) );
1161   
1162   // configure the radio for that frequency
1163   radio_setFrequency(frequency);
1164   
1165   // load the packet in the radio's Tx buffer
1166   radio_loadPacket(ieee154e_vars.ackToSend);
1167   
1168   // enable the radio in Tx mode. This does not send that packet.
1169   radio_txEnable();
1170   
1171   // arm rt6
1172   ieee154etimer_schedule(DURATION_rt6);
1173   
1174   // change state
1175   changeState(S_TXACKREADY);
1176}
1177
1178inline void activity_rie4() {
1179   // log the error
1180   openserial_printError(COMPONENT_IEEE802154E,
1181                         ERR_MAXTXACKPREPARE_OVERFLOWS,
1182                         ieee154e_vars.state,
1183                         ieee154e_vars.asn%SCHEDULELENGTH);
1184   
1185   // abort
1186   endSlot();
1187}
1188
1189inline void activity_ri7() {
1190   // change state
1191   changeState(S_TXACKDELAY);
1192   
1193   // arm rt7
1194   ieee154etimer_schedule(DURATION_rt7);
1195   
1196   // give the 'go' to transmit
1197   radio_txNow();
1198}
1199
1200inline void activity_rie5() {
1201   // log the error
1202   openserial_printError(COMPONENT_IEEE802154E,
1203                         ERR_WDRADIOTX_OVERFLOWS,
1204                         ieee154e_vars.state,
1205                         ieee154e_vars.asn%SCHEDULELENGTH);
1206   
1207   // abort
1208   endSlot();
1209}
1210
1211inline void activity_ri8(uint16_t capturedTime) {
1212   // change state
1213   changeState(S_TXACK);
1214   
1215   // cancel rt7
1216   ieee154etimer_cancel();
1217   
1218   // record the captured time
1219   ieee154e_vars.lastCapturedTime = capturedTime;
1220   
1221   // arm rt8
1222   ieee154etimer_schedule(DURATION_rt8);
1223}
1224
1225inline void activity_rie6() {
1226   // log the error
1227   openserial_printError(COMPONENT_IEEE802154E,
1228                         ERR_WDACKDURATION_OVERFLOWS,
1229                         ieee154e_vars.state,
1230                         ieee154e_vars.asn%SCHEDULELENGTH);
1231   
1232   // abort
1233   endSlot();
1234}
1235
1236inline void activity_ri9(uint16_t capturedTime) {
1237   // change state
1238   changeState(S_RXPROC);
1239   
1240   // cancel rt8
1241   ieee154etimer_cancel();
1242   
1243   // record the captured time
1244   ieee154e_vars.lastCapturedTime = capturedTime;
1245   
1246   // free the ack we just sent so corresponding RAM memory can be recycled
1247   openqueue_freePacketBuffer(ieee154e_vars.ackToSend);
1248   
1249   // clear local variable
1250   ieee154e_vars.ackToSend = NULL;
1251   
1252   // synchronize to the received packet
1253   synchronizePacket(ieee154e_vars.syncCapturedTime,&(ieee154e_vars.dataReceived->l2_nextORpreviousHop));
1254   
1255   // inform upper layer of reception (after ACK sent)
1256   notif_receive(ieee154e_vars.dataReceived);
1257   
1258   // clear local variable
1259   ieee154e_vars.dataReceived = NULL;
1260   
1261   // official end of Rx slot
1262   endSlot();
1263}
1264
1265//======= frame validity check
1266
1267/**
1268\brief Decides whether the packet I just received is a valid ADV
1269
1270\param [in] ieee802514_header IEEE802.15.4 header of the packet I just received
1271
1272\returns TRUE if packet is a valid ADV, FALSE otherwise
1273*/
1274inline bool isValidAdv(ieee802154_header_iht* ieee802514_header) {
1275   return ieee802514_header->valid==TRUE                                                              && \
1276          ieee802514_header->frameType==IEEE154_TYPE_BEACON                                           && \
1277          packetfunctions_sameAddress(&ieee802514_header->panid,idmanager_getMyID(ADDR_PANID))        && \
1278          ieee154e_vars.dataReceived->length==sizeof(IEEE802154E_ADV_ht);
1279}
1280
1281/**
1282\brief Decides whether the packet I just received is valid received frame.
1283
1284A valid Rx frame satisfies the following constraints:
1285- its IEEE802.15.4 header is well formatted
1286- its a DATA of BEACON frame (i.e. not ACK and not COMMAND)
1287- its sent on the same PANid as mine
1288- its for me (unicast or broadcast)
1289-
1290
1291\param [in] ieee802514_header IEEE802.15.4 header of the packet I just received
1292
1293\returns TRUE if packet is valid received frame, FALSE otherwise
1294*/
1295inline bool isValidRxFrame(ieee802154_header_iht* ieee802514_header) {
1296   return ieee802514_header->valid==TRUE                                                           && \
1297          (
1298             ieee802514_header->frameType==IEEE154_TYPE_DATA                   ||
1299             ieee802514_header->frameType==IEEE154_TYPE_BEACON
1300          )                                                                                        && \
1301          packetfunctions_sameAddress(&ieee802514_header->panid,idmanager_getMyID(ADDR_PANID))     && \
1302          (
1303             idmanager_isMyAddress(&ieee802514_header->dest)                   ||
1304             packetfunctions_isBroadcastMulticast(&ieee802514_header->dest)
1305          );
1306}
1307
1308/**
1309\brief Decides whether the packet I just received is a valid ACK
1310
1311A packet is a valid ACK if it satisfies the following conditions:
1312- the IEEE802.15.4 header is valid
1313- the frame type is 'ACK'
1314- the sequence number in the ACK matches the sequence number of the packet sent
1315- the ACK contains my PANid
1316- the packet is unicast to me
1317- the packet comes from the neighbor I sent the data to
1318
1319\param [in] ieee802514_header IEEE802.15.4 header of the packet I just received
1320\param [in] packetSent points to the packet I just sent
1321
1322\returns TRUE if packet is a valid ACK, FALSE otherwise
1323*/
1324inline bool isValidAck(ieee802154_header_iht* ieee802514_header,
1325                       OpenQueueEntry_t*      packetSent) {
1326   return ieee802514_header->valid==TRUE                                                           && \
1327          ieee802514_header->frameType==IEEE154_TYPE_ACK                                           && \
1328          ieee802514_header->dsn==packetSent->l2_dsn                                               && \
1329          packetfunctions_sameAddress(&ieee802514_header->panid,idmanager_getMyID(ADDR_PANID))     && \
1330          idmanager_isMyAddress(&ieee802514_header->dest)                                          && \
1331          packetfunctions_sameAddress(&ieee802514_header->src,&packetSent->l2_nextORpreviousHop);
1332}
1333
1334//======= ASN handling
1335
1336inline void asnWrite(OpenQueueEntry_t* advFrame) {
1337   ((IEEE802154E_ADV_ht*)(advFrame->l2_payload))->asn[0] = ieee154e_vars.asn/256;
1338   ((IEEE802154E_ADV_ht*)(advFrame->l2_payload))->asn[1] = ieee154e_vars.asn%256;
1339}
1340
1341inline uint16_t asnRead(OpenQueueEntry_t* advFrame) {
1342   uint16_t returnVal;
1343   returnVal  = 0;
1344   returnVal += 256*((IEEE802154E_ADV_ht*)(ieee154e_vars.dataReceived->payload))->asn[0];
1345   returnVal +=     ((IEEE802154E_ADV_ht*)(ieee154e_vars.dataReceived->payload))->asn[1];
1346   return returnVal;
1347}
1348
1349//======= synchronization
1350
1351void synchronizePacket(uint16_t timeReceived,open_addr_t* advFrom) {
1352   int16_t  timeCorrection;
1353   uint16_t newTaccr0;
1354   uint16_t currentTar;
1355   uint16_t currentTaccr0;
1356   // record the current states of the TAR and TACCR0 registers
1357   currentTar           =  TAR;
1358   currentTaccr0        =  TACCR0;
1359   // only resynchronize if I'm not a DAGroot and this is my preferred parent
1360   if (idmanager_getIsDAGroot()==FALSE && neighbors_isPreferredParent(advFrom)) {
1361      timeCorrection    =  (int16_t)((int16_t)timeReceived-(int16_t)TsTxOffset);
1362      newTaccr0         =  TsSlotDuration;
1363      // detect whether I'm too close to the edge of the slot, in that case,
1364      // skip a slot and increase the temporary slot length to be 2 slots long
1365      if (currentTar<timeReceived ||
1366          currentTaccr0-currentTar<RESYNCHRONIZATIONGUARD) {
1367         DEBUG_PIN_SLOT_TOGGLE();
1368         TACTL         &= ~TAIFG;
1369         newTaccr0     +=  TsSlotDuration;
1370         ieee154e_vars.asn++;
1371         DEBUG_PIN_SLOT_TOGGLE();
1372      }
1373      newTaccr0         =  (uint16_t)((int16_t)newTaccr0+timeCorrection);
1374      TACCR0            =  newTaccr0;
1375      ieee154e_vars.deSyncTimeout = DESYNCTIMEOUT;
1376      // update statistics
1377      updateStats(timeCorrection);
1378   }
1379}
1380
1381void synchronizeAck(int16_t timeCorrection,open_addr_t* advFrom) {
1382   uint16_t newTaccr0;
1383   uint16_t currentTaccr0;
1384   // record the current states of the TAR and TACCR0 registers
1385   currentTaccr0        =  TACCR0;
1386   // only resynchronize if I'm not a DAGroot and this is my preferred parent
1387   if (idmanager_getIsDAGroot()==FALSE && neighbors_isPreferredParent(advFrom)) {
1388      newTaccr0         =  (uint16_t)((int16_t)currentTaccr0-timeCorrection);
1389      TACCR0            =  newTaccr0;
1390      ieee154e_vars.deSyncTimeout = DESYNCTIMEOUT;
1391      // update statistics
1392      updateStats(timeCorrection);
1393   }
1394}
1395
1396void changeIsSync(bool newIsSync) {
1397   ieee154e_vars.isSync = newIsSync;
1398   if (ieee154e_vars.isSync==TRUE) {
1399      LED_SYNC_ON();
1400      resetStats();
1401   } else {
1402      LED_SYNC_OFF();
1403   }
1404}
1405
1406//======= notifying upper layer
1407
1408void notif_sendDone(OpenQueueEntry_t* packetSent, error_t error) {
1409   // record the outcome of the trasmission attempt
1410   packetSent->l2_sendDoneError    = error;
1411   // record the current ASN
1412   packetSent->l2_TxRxAsnTimestamp = ieee154e_vars.asn;
1413   // associate this packet with the virtual component
1414   // COMPONENT_IEEE802154E_TO_RES so RES can knows it's for it
1415   packetSent->owner              = COMPONENT_IEEE802154E_TO_RES;
1416   // post RES's sendDone task
1417   scheduler_push_task(TASKID_RESNOTIF_TXDONE);
1418   // wake up the scheduler
1419   SCHEDULER_WAKEUP();
1420}
1421
1422void notif_receive(OpenQueueEntry_t* packetReceived) {
1423   // record the current ASN
1424   packetReceived->l2_TxRxAsnTimestamp = ieee154e_vars.asn;
1425   // associate this packet with the virtual component
1426   // COMPONENT_IEEE802154E_TO_RES so RES can knows it's for it
1427   packetReceived->owner          = COMPONENT_IEEE802154E_TO_RES;
1428   // post RES's Receive task
1429   scheduler_push_task(TASKID_RESNOTIF_RX);
1430   // wake up the scheduler
1431   SCHEDULER_WAKEUP();
1432}
1433
1434//======= stats
1435
1436inline void resetStats() {
1437   ieee154e_stats.syncCounter     =    0;
1438   ieee154e_stats.minCorrection   =  127;
1439   ieee154e_stats.maxCorrection   = -127;
1440   // do not reset the number of de-synchronizations
1441}
1442
1443void updateStats(int16_t timeCorrection) {
1444   
1445   ieee154e_stats.syncCounter++;
1446   
1447   if (timeCorrection<ieee154e_stats.minCorrection) {
1448     ieee154e_stats.minCorrection = timeCorrection;
1449   }
1450   
1451   if(timeCorrection>ieee154e_stats.maxCorrection) {
1452     ieee154e_stats.maxCorrection = timeCorrection;
1453   }
1454}
1455
1456//======= misc
1457
1458/**
1459\brief Calculates the frequency to transmit on, based on the
1460absolute slot number and the channel offset of the requested slot.
1461
1462During normal operation, the frequency used is a function of the
1463channelOffset indicating in the schedule, and of the ASN of the
1464slot. This ensures channel hopping, consecutive packets sent in the same slot
1465in the schedule are done on a difference frequency channel.
1466
1467During development, you can force single channel operation by having this
1468function return a constant channel number (between 11 and 26). This allows you
1469to use a single-channel sniffer; but you can not schedule two links on two
1470different channel offsets in the same slot.
1471
1472\param [in] asn Absolute Slot Number
1473\param [in] channelOffset channel offset for the current slot
1474
1475\returns The calculated frequency channel, an integer between 11 and 26.
1476*/
1477inline uint8_t calculateFrequency(asn_t asn, uint8_t channelOffset) {
1478   //return 11+(asn+channelOffset)%16;
1479   //poipoi: no channel hopping
1480   return 26;
1481}
1482
1483/**
1484\brief Changes the state of the IEEE802.15.4e FSM.
1485
1486Besides simply updating the state global variable,
1487this function toggles the FSM debug pin.
1488
1489\param [in] newstate The state the IEEE802.15.4e FSM is now in.
1490*/
1491void changeState(uint8_t newstate) {
1492   // update the state
1493   ieee154e_vars.state = newstate;
1494   // wiggle the FSM debug pin
1495   switch (ieee154e_vars.state) {
1496      case S_SYNCLISTEN:
1497      case S_TXDATAOFFSET:
1498         DEBUG_PIN_FSM_SET();
1499         break;
1500      case S_SLEEP:
1501      case S_RXDATAOFFSET:
1502         DEBUG_PIN_FSM_CLR();
1503         break;
1504      case S_SYNCRX:
1505      case S_SYNCPROC:
1506      case S_TXDATAPREPARE:
1507      case S_TXDATAREADY:
1508      case S_TXDATADELAY:
1509      case S_TXDATA:
1510      case S_RXACKOFFSET:
1511      case S_RXACKPREPARE:
1512      case S_RXACKREADY:
1513      case S_RXACKLISTEN:
1514      case S_RXACK:
1515      case S_TXPROC:
1516      case S_RXDATAPREPARE:
1517      case S_RXDATAREADY:
1518      case S_RXDATALISTEN:
1519      case S_RXDATA:
1520      case S_TXACKOFFSET:
1521      case S_TXACKPREPARE:
1522      case S_TXACKREADY:
1523      case S_TXACKDELAY:
1524      case S_TXACK:
1525      case S_RXPROC:
1526         DEBUG_PIN_FSM_TOGGLE();
1527         break;
1528   }
1529}
1530
1531/**
1532\brief Housekeeping tasks to do at the end of each slot.
1533
1534This functions is called once in each slot, when there is nothing more
1535to do. This might be when an error occured, or when everything went well.
1536This function resets the state of the FSM so it is ready for the next slot.
1537
1538Note that by the time this function is called, any received packet should already
1539have been sent to the upper layer. Similarly, in a Tx slot, the sendDone
1540function should already have been done. If this is not the case, this function
1541will do that for you, but assume that something went wrong.
1542*/
1543void endSlot() {
1544   // turn off the radio
1545   radio_rfOff();
1546   
1547   // clear any pending timer
1548   ieee154etimer_cancel();
1549   
1550   // reset capturedTimes
1551   ieee154e_vars.lastCapturedTime = 0;
1552   ieee154e_vars.syncCapturedTime = 0;
1553   
1554   // clean up dataToSend
1555   if (ieee154e_vars.dataToSend!=NULL) {
1556      // if everything went well, dataToSend was set to NULL in ti9
1557      // transmit failed, decrement transmits left counter
1558      ieee154e_vars.dataToSend->l2_retriesLeft--;
1559      if (ieee154e_vars.dataToSend->l2_retriesLeft==0) {
1560         // indicate tx fail if no more retries left
1561         notif_sendDone(ieee154e_vars.dataToSend,E_FAIL);
1562      } else {
1563         // return packet to the virtual COMPONENT_RES_TO_IEEE802154E component
1564         ieee154e_vars.dataToSend->owner = COMPONENT_RES_TO_IEEE802154E;
1565      }
1566      // reset local variable
1567      ieee154e_vars.dataToSend = NULL;
1568   }
1569   
1570   // clean up dataReceived
1571   if (ieee154e_vars.dataReceived!=NULL) {
1572      // assume something went wrong. If everything went well, dataReceived
1573      // would have been set to NULL in ri9.
1574      // indicate  "received packet" to upper layer since we don't want to loose packets
1575      notif_receive(ieee154e_vars.dataReceived);
1576      // reset local variable
1577      ieee154e_vars.dataReceived = NULL;
1578   }
1579   
1580   // clean up ackToSend
1581   if (ieee154e_vars.ackToSend!=NULL) {
1582      // free ackToSend so corresponding RAM memory can be recycled
1583      openqueue_freePacketBuffer(ieee154e_vars.ackToSend);
1584      // reset local variable
1585      ieee154e_vars.ackToSend = NULL;
1586   }
1587   
1588   // clean up ackReceived
1589   if (ieee154e_vars.ackReceived!=NULL) {
1590      // free ackReceived so corresponding RAM memory can be recycled
1591      openqueue_freePacketBuffer(ieee154e_vars.ackReceived);
1592      // reset local variable
1593      ieee154e_vars.ackReceived = NULL;
1594   }
1595   
1596   // change state
1597   changeState(S_SLEEP);
1598}
Note: See TracBrowser for help on using the repository browser.