]> Pileus Git - ~andy/csm213a-hw/blob - hw2/main.cpp
Cleanup comments and move test.cpp
[~andy/csm213a-hw] / hw2 / main.cpp
1 #include "messages.h"
2
3 #include "mbed.h"
4 #include "serial_irq.h"
5 #include "serial_dma.h"
6 #include "timer_dma.h"
7
8 /**
9  * Mode of operation:
10  *   Devices 1 and 2 synchronize clocks using serial messages.
11  *
12  *   1. Each serial message timestamped using the hardware timer capture
13  *      registers in both the sender and receiver.
14  *   2. The sender transmits the send timestamp during the next time-sync
15  *      message.
16  *   3. The receiver then compares the senders timestamp with it's own
17  *      timestamp for the corresponding messages and calculates an offset.
18  *   4. The offset is used to compensate the receivers local clock.
19  *
20  *   Time synchronization is performed in both directions.
21  */
22
23 /*******************
24  * Timer functions *
25  *******************/
26
27 #define NSEC_PER_SEC 1000000000ULL
28
29 uint64_t time_last_local; // timestamp at last time sync
30 uint64_t time_last_world; // offset at last time sync
31
32 /**
33  * Generate time stamp for an async event:
34  *   time:  drift compensated wall-clock time
35  *   stamp: event timestamp from PIT Module
36  */
37 uint64_t time_to_world(uint64_t local)
38 {
39         uint64_t elapsed = local - time_last_local;
40         return time_last_world + elapsed;
41 }
42
43 uint64_t time_to_local(uint64_t world)
44 {
45         uint64_t elapsed = world - time_last_world;
46         return time_last_local + elapsed;
47 }
48
49 /**
50  * Synchronize the timer internal state with updates
51  * from an external time sync message.
52  *   local: our internal timestamp for the event
53  *   world: reference timestamp from the other device
54  */
55 void time_ext_init(uint64_t local, uint64_t world)
56 {
57         sirq_printf("initialize clocks: %d -> %d\r\n",
58                         (int)(local/NSEC_PER_SEC),
59                         (int)(world/NSEC_PER_SEC));
60
61         time_last_local = local;
62         time_last_world = world;
63 }
64
65 /**
66  * Synchronize the timer internal state with updates
67  * from an external time sync message.
68  *   local: our internal timestamp for the event
69  *   world: reference timestamp from the other device
70  */
71 void time_ext_sync(uint64_t local, uint64_t world)
72 {
73         uint64_t guess = time_to_world(local);
74
75         time_last_local = local;
76         time_last_world = (guess/2) + (world/2);
77         //time_last_world = (guess * 3 / 4) + (world * 1 / 4);
78         //time_last_world =
79         //      (guess - (        guess / 2)) +
80         //      (world - (world - world / 2));
81         //time_last_world =
82         //      (guess - (guess - guess / 4)) +
83         //      (world - (        world / 4));
84
85         world = time_last_world;
86
87 //#ifdef VERBOSE
88 #if 0
89         uint64_t error = world > guess ? world - guess :
90                          guess > world ? guess - world : 0;
91         int      ahead = guess > world;
92         sirq_printf("syncing clocks: %6d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n",
93                         (int)((local / NSEC_PER_SEC)),
94                         (int)((guess / NSEC_PER_SEC)),
95                         (int)((guess % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
96                         (int)((world / NSEC_PER_SEC)),
97                         (int)((world % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
98                         ahead ? "-" : " ",
99                         (int32_t )(error / (int64_t)NSEC_PER_SEC),
100                         (uint32_t)(error % (int64_t)NSEC_PER_SEC));
101 #endif
102 //#endif
103 }
104
105 void time_printf(const char *label, uint64_t local)
106 {
107         uint64_t world = time_to_world(local);
108         sirq_printf("%s -- %d.%09u -> %d.%09u\r\n",
109                         label,
110                         (int)(local / NSEC_PER_SEC),
111                         (int)(local % NSEC_PER_SEC),
112                         (int)(world / NSEC_PER_SEC),
113                         (int)(world % NSEC_PER_SEC));
114 }
115
116 /*********************
117  * Signal generation *
118  *********************/
119
120 // for 50 Mhz clock  50/1000 = 1/20  (PLL/2)
121
122 // for 48 Mhz clock  48/1000 = 6/125 (FLL)
123 // for 24 Mhz clock, 24/1000 = 3/125
124 // for 12 Mhz clock, 12/1000 = 3/250
125 // for  6 Mhz clock,  6/1000 = 3/500
126 // for  3 Mhz clock,  3/1000 = 3/1000
127
128 #define EMIT_PS 1
129
130 //#if EMIT_PS == 0
131 //#define EMIT_CLOCKS(nsec) ((uint16_t)((nsec)   / 20))
132 //#define EMIT_NSEC(clocks) ((uint16_t)((clocks) * 20))
133
134 #if EMIT_PS == 0
135 #define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 6 / 125))
136 #define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 125 / 6))
137 #elif EMIT_PS == 1
138 #define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 125))
139 #define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 125 / 3))
140 #elif EMIT_PS == 2
141 #define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 250))
142 #define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 250 / 3))
143 #elif EMIT_PS == 3
144 #define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 500))
145 #define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 500 / 3))
146 #elif EMIT_PS == 4
147 #define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 1000))
148 #define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 1000 / 3))
149 #endif
150
151 static uint32_t *emit_pcr    = 0; // transmit pin name
152
153 static uint64_t  emit_start  = 0; // transmit start time (world time)
154 static uint64_t  emit_period = 0; // transmit period
155 static uint64_t  emit_due    = 0; // next transmit (world time)
156
157 static uint32_t  emit_slack  = 0; // how far ahead we need to schedule, in us
158 static uint32_t  emit_worst  = 0; // worst-case latency in task table
159
160 void emit_init(int alt, PinName pin, PinMode mode)
161 {
162         // Find pin
163         emit_pcr = (uint32_t*)(PORTA_BASE + pin);
164
165         // Enable clocks
166         SIM->SCGC6            |= SIM_SCGC6_TPM1_MASK;
167         SIM->SOPT2            |= SIM_SOPT2_TPMSRC(1);
168
169         // Reset PLL Source
170         //SIM->SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
171
172         // Debug print on SOPT2
173         // -- mbed may set PLLFLL when configuring UART0
174         // SOPT2: u0src=1 tpmsrc=1 USBSRC PLL/2 clkos=0 rtcos
175         sirq_printf("SOPT2: u0src=%d tpmsrc=%d %s %s clkos=%d %s\r\n",
176                 (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     >> SIM_SOPT2_UART0SRC_SHIFT,
177                 (SIM->SOPT2 & SIM_SOPT2_TPMSRC_MASK)       >> SIM_SOPT2_TPMSRC_SHIFT,
178                 (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     ? "USBSRC" : "usbsrc",
179                 (SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK)    ? "PLL/2"  : "FLL",
180                 (SIM->SOPT2 & SIM_SOPT2_CLKOUTSEL_MASK)    >> SIM_SOPT2_CLKOUTSEL_SHIFT,
181                 (SIM->SOPT2 & SIM_SOPT2_RTCCLKOUTSEL_MASK) ? "RTCOS"  : "rtcos");
182
183         // Set pin mode
184         emit_pcr[0]            = PORT_PCR_ISF_MASK
185                                | PORT_PCR_MUX(alt)
186                                | mode;
187
188         // Setup Timer/PWM Module
189         TPM1->SC               = TPM_SC_TOF_MASK;
190         TPM1->CNT              = TPM_CNT_COUNT(0);
191         TPM1->MOD              = TPM_MOD_MOD(0xFFFF);
192
193         TPM1->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK    // clear flag
194                                | TPM_CnSC_MSB_MASK    // set output highon match,
195                                | TPM_CnSC_ELSB_MASK   // cleared on overflow
196                                | TPM_CnSC_ELSA_MASK;  // ..
197
198         TPM1->STATUS           = TPM_STATUS_CH0F_MASK
199                                | TPM_STATUS_TOF_MASK;
200
201         TPM1->CONF             = TPM_CONF_CSOO_MASK;
202 }
203
204 void emit_enable(uint64_t start, uint64_t period)
205 {
206         const int slack_clocks = 0x4000; // tune based on emit_worst
207
208         emit_start  = start;
209         emit_period = period;
210         emit_due    = start + period;
211
212         emit_slack  = EMIT_NSEC(slack_clocks);
213
214         time_printf("emit scheduled", emit_due);
215 }
216
217 void emit_schedule(uint64_t when)
218 {
219         uint64_t local  = time_to_local(when) * 3 / 125;
220         uint32_t width  = EMIT_CLOCKS(10000);
221
222         // Disable timer
223         TPM1->SC               = TPM_SC_TOF_MASK;
224
225         __disable_irq();
226
227         uint64_t now    = ((uint64_t)~PIT->LTMR64H << 32)
228                         | ((uint64_t)~PIT->LTMR64L);
229         uint32_t delta  = local - now;
230         uint32_t start  = delta >> (EMIT_PS-1); // convert to clocks
231         uint32_t stop   = start + width;        // end time
232
233         // Set transmit time
234         TPM1->CONTROLS[0].CnV  = start;
235         TPM1->MOD              = TPM_MOD_MOD(stop);
236
237         // Start the timer
238         TPM1->SC               = TPM_SC_TOF_MASK
239                                | TPM_SC_PS(EMIT_PS)
240                                | TPM_SC_CMOD(1);
241
242         __enable_irq();
243
244         // Test
245         //int64_t  cnv = TPM1->CONTROLS[0].CnV;
246         //int64_t  mod = TPM1->MOD;
247         //int64_t  due = local - tdma_time();
248         //sirq_printf("%6d -- cnv=%04x mod=%04x due=%04x start=%04x\r\n",
249         //              (int)(cnv - EMIT_CLOCKS(due)),
250         //              (int)cnv, (int)mod,
251         //              (int)EMIT_CLOCKS(due), EMIT_CLOCKS(start));
252
253         // Clock testing
254         //uint32_t test_tpm0 =  TPM1->CNT;
255         //uint32_t test_pit0 = ~PIT->CHANNEL[0].CVAL;
256         //for (int i = 0; i < 100; i++)
257         //      asm("nop");
258         //uint32_t test_tpm1 =  TPM1->CNT;
259         //uint32_t test_pit1 = ~PIT->CHANNEL[0].CVAL;
260
261         //uint32_t test_tpm  = test_tpm1 - test_tpm0;
262         //uint32_t test_pit  = test_pit1 - test_pit0;
263         //sirq_printf("pit/tpm: %d - tpm=%08x/%08x=%d pit=%08x/%08x=%d\r\n",
264         //              test_tpm - test_pit,
265         //              test_tpm0, test_tpm1, test_tpm,
266         //              test_pit0, test_pit1, test_pit);
267
268         // Debug output
269         //time_printf("emitting event", when);
270 }
271
272 void emit_transmit(uint64_t local, uint64_t world)
273 {
274         static uint64_t prev = 0;
275
276         // Record how how much time we have to reschedule
277         if (prev && (local-prev) > emit_worst)
278                 emit_worst = (local-prev);
279         prev = local;
280
281         // Schedule task if needed
282         if (emit_due && emit_period &&
283             world+emit_slack > emit_due) {
284                 emit_schedule(emit_due);
285                 emit_due += emit_period;
286         }
287 }
288
289 /************************
290  * Serial I/O functions *
291  ************************/
292
293 typedef struct {
294         int      index;
295         int      state;
296         uint8_t  buffer[256];
297 } parser_t;
298
299 static uint32_t serial_device_id   = 0;
300
301 const  uint64_t serial_sync_delay  = NSEC_PER_SEC / 100;
302 static uint64_t serial_sync_due    = 0;
303
304 static tdma_t  *serial_tdma_rcv    = NULL;
305 static tdma_t  *serial_tdma_xmt    = NULL;
306
307 /**
308  * Convert world to local time
309  */
310 uint64_t serial_read_time(ntime_t time)
311 {
312         return ((uint64_t)time.seconds) * NSEC_PER_SEC
313              + ((uint64_t)time.nanosec);
314 }
315
316 ntime_t serial_write_time(uint64_t time)
317 {
318         ntime_t buf = {};
319         buf.seconds = time / NSEC_PER_SEC;
320         buf.nanosec = time % NSEC_PER_SEC;
321         return buf;
322 }
323
324 int serial_time_stamp(tdma_t *port, uint64_t *local, uint64_t *world,
325                 const char *msg)
326 {
327         int valid = tdma_stamp(port, local);
328         *world = time_to_world(*local);
329
330         if (!valid)
331                 sirq_printf("%s -- missing\r\n", msg);
332         //else
333         //      time_printf(msg, current);
334
335         return valid;
336 }
337
338 /**
339  * Output initialization message init message
340  */
341 void serial_send_init(uint16_t device, uint64_t local)
342 {
343 }
344
345 /**
346  * Output time sync message
347  */
348 void serial_send_sync(sirq_t *port, uint64_t now)
349 {
350         if (serial_sync_due == 0 || now < serial_sync_due)
351                 return; // not ready
352
353         // Message data
354         header_t   head;
355         sync_msg_t body;
356
357         // Write header
358         head.header = MSG_HEADER;
359         head.msgid  = MSG_ID_SYNC;
360         head.length = sizeof(body);
361         head.cksum  = 0; // todo
362
363         tdma_stop(serial_tdma_rcv, 0);
364         tdma_start(serial_tdma_xmt);
365
366         sirq_write(port, &head, sizeof(head));
367
368         tdma_stop(serial_tdma_xmt, 100);
369         tdma_start(serial_tdma_rcv);
370
371         // Save transmit time
372         uint64_t local = 0, world = 0;
373         serial_time_stamp(serial_tdma_xmt, &local, &world,
374                         "sync time transmit");
375
376         // Debug output
377         //sirq_printf("sync time transmit\r\n");
378         //time_printf("  local", local);
379         //time_printf("  world", world);
380
381         // Write body with updated time and send
382         body.time = serial_write_time(world);
383
384         sirq_write(port, &body, sizeof(body));
385
386         // Queue next transmit time
387         serial_sync_due  = 0;
388 }
389
390 /**
391  * Output external event received message
392  *   event: id of the received event
393  *   time:  compensated timestamp of the event
394  */
395 void serial_send_event(sirq_t *port, uint16_t event, uint64_t local)
396 {
397         //time_printf("event received", local);
398
399         // Convert timestamp
400         uint64_t world = time_to_world(local);
401         ntime_t  ltime = serial_write_time(local);
402         ntime_t  wtime = serial_write_time(world);
403
404         // Message data
405         header_t    head = {};
406         event_msg_t body = {};
407
408         // Transmit sync message
409         head.header = MSG_HEADER;
410         head.msgid  = MSG_ID_EVENT;
411         head.length = sizeof(body);
412         head.cksum  = 0; // todo
413
414         body.device = serial_device_id;
415         body.event  = event;
416         body.world  = wtime;
417         body.local  = ltime;
418
419         // Transmit message to BBB
420         sirq_write(port, &head, sizeof(head));
421         sirq_write(port, &body, sizeof(body));
422 }
423
424 /**
425  * Handle init message
426  */
427 void serial_handle_init(init_msg_t *msg)
428 {
429         sirq_printf("initialize: %s %s %s %s %s\r\n",
430                 msg->valid & MSG_VALID_DEVICE ? "DEV"    : "dev",
431                 msg->valid & MSG_VALID_START  ? "START"  : "start",
432                 msg->valid & MSG_VALID_PERIOD ? "PERIOD" : "period",
433                 msg->valid & MSG_VALID_WORLD  ? "WORLD"  : "world",
434                 msg->valid & MSG_VALID_SYNC   ? "SYNC"   : "sync");
435         sirq_printf("  dev    -- %d\r\n", msg->device);
436         time_printf("  start ", serial_read_time(msg->start));
437         time_printf("  period", serial_read_time(msg->period));
438         time_printf("  world ", serial_read_time(msg->world));
439
440         if (msg->valid & MSG_VALID_DEVICE)
441                 serial_device_id = msg->device;
442
443         if (msg->valid & MSG_VALID_START ||
444             msg->valid & MSG_VALID_PERIOD) {
445                 uint64_t start  = serial_read_time(msg->start);
446                 uint64_t period = serial_read_time(msg->period);
447                 emit_enable(start, period);
448         }
449
450         if (msg->valid & MSG_VALID_WORLD) {
451                 uint64_t world = serial_read_time(msg->world);
452                 uint64_t local = tdma_time();
453                 time_ext_init(local, world);
454         }
455
456         if (msg->valid & MSG_VALID_SYNC)
457                 serial_sync_due = tdma_time() + serial_sync_delay;
458 }
459
460 /**
461  * Handle sync message
462  */
463 void serial_handle_sync(sync_msg_t *msg)
464 {
465         // Read receive timestamp
466         uint64_t local = 0, world = 0;
467         serial_time_stamp(serial_tdma_rcv, &local, &world,
468                         "sync time receive ");
469         tdma_stop(serial_tdma_rcv, 0);
470
471         // Lookup reference time from message
472         uint64_t reference = serial_read_time(msg->time);
473
474         // Debug output
475         //sirq_printf("sync time receive\r\n");
476         //time_printf("  local", local);
477         //time_printf("  world", world);
478         //time_printf("  ref  ", reference);
479
480         // Synchronize the clocks
481         time_ext_sync(local, reference);
482
483         // Queue transmit to other board
484         serial_sync_due   = tdma_time() + serial_sync_delay;
485 }
486
487 /**
488  * Handle event message
489  */
490 void serial_handle_event(event_msg_t *msg)
491 {
492 }
493
494 /**
495  * Deliver message
496  */
497 void serial_deliver(int msgid, void *body)
498 {
499         switch (msgid) {
500                 case MSG_ID_INIT:
501                         //sirq_printf("received init msg\r\n");
502                         serial_handle_init((init_msg_t*)body);
503                         break;
504                 case MSG_ID_SYNC:
505                         //sirq_printf("received sync msg\r\n");
506                         serial_handle_sync((sync_msg_t*)body);
507                         break;
508                 case MSG_ID_EVENT:
509                         //sirq_printf("received event msg\r\n");
510                         serial_handle_event((event_msg_t*)body);
511                         break;
512         }
513 }
514
515 /**
516  * Process serial receive messages
517  */
518 void serial_receive(parser_t *parser, int byte)
519 {
520         //sirq_printf("serial_receive - %02x\r\n", byte);
521
522         // Lookup pointers
523         header_t *head = (header_t*)parser->buffer;
524         void     *body = (void*)(head+1);
525         const int max_length = sizeof(parser->buffer)-sizeof(header_t);
526
527         // Process uart messages
528         parser->buffer[parser->index++] = byte;
529         switch (parser->state) {
530                 case 0: // Search
531                         if (parser->index == sizeof(uint16_t)) {
532                                 if (head->header == MSG_HEADER) {
533                                         parser->state = 1;
534                                 } else {
535                                         parser->buffer[0] = parser->buffer[1];
536                                         parser->index = 1;
537                                 }
538                         }
539                         break;
540                 case 1: // Header
541                         if (parser->index == sizeof(header_t)) {
542                                 if (head->length <= max_length &&
543                                     head->msgid  <= MSG_MAX_ID) {
544                                         parser->state = 2;
545                                 } else {
546                                         parser->index = 0;
547                                         parser->state = 0;
548                                 }
549                         }
550                         break;
551                 case 2: // Data
552                         if (parser->index == (int)sizeof(header_t)+head->length) {
553                                 serial_deliver(head->msgid, body);
554                                 parser->index = 0;
555                                 parser->state = 0;
556                         }
557                         break;
558         }
559 }
560
561 /********************
562  * Data definitions *
563  ********************/
564
565 // LEDs
566 DigitalOut led1(LED1);
567 DigitalOut led2(LED2);
568
569 // Message Parsers
570 parser_t   parser_dbg;
571 parser_t   parser_bbb;
572 parser_t   parser_mbed;
573
574 // Serial IRQ
575 sirq_t    *sirq_dbg;
576 sirq_t    *sirq_bbb;
577 sirq_t    *sirq_mbed;
578
579 // Timer DMA
580 tdma_t    *tdma_evt;
581 tdma_t    *tdma_rcv;
582 tdma_t    *tdma_xmt;
583
584 /*********
585  * Tasks *
586  *********/
587
588 void task_serial(uint64_t local, uint64_t world)
589 {
590         while (sirq_ready(sirq_dbg)) {
591                 //sirq_printf("serial recv - dbg\r\n");
592                 serial_receive(&parser_dbg,  sirq_getc(sirq_dbg));
593         }
594
595         while (sirq_ready(sirq_bbb)) {
596                 //sirq_printf("serial recv - bbb\r\n");
597                 serial_receive(&parser_bbb,  sirq_getc(sirq_bbb));
598         }
599
600         while (sirq_ready(sirq_mbed)) {
601                 //sirq_printf("serial recv - mbed\r\n");
602                 serial_receive(&parser_mbed, sirq_getc(sirq_mbed));
603         }
604 }
605
606 void task_events(uint64_t local, uint64_t world)
607 {
608         uint64_t event = 0;
609
610 #ifdef VERBOSE
611         if (tdma_stamp(tdma_evt, &event)) {
612                 sirq_printf("event received - evt\r\n");
613         if (tdma_stamp(tdma_rcv, &event))
614                 sirq_printf("event received - rcv\r\n");
615         if (tdma_stamp(tdma_xmt, &event))
616                 sirq_printf("event received - xmt\r\n");
617 #endif
618
619         if (tdma_stamp(tdma_evt, &event))
620                 serial_send_event(sirq_bbb, 0, event);
621         tdma_stop(tdma_evt, 0);
622         tdma_start(tdma_evt);
623 }
624
625 void task_sync(uint64_t local, uint64_t world)
626 {
627         serial_send_sync(sirq_mbed, local);
628 }
629
630 void task_leds(uint64_t local, uint64_t world)
631 {
632         static uint32_t which = 0;
633         led1 = (which == 0);
634         led2 = (which == 1);
635         which ^= 1;
636 }
637
638 void task_emit(uint64_t local, uint64_t world)
639 {
640         emit_transmit(local, world);
641 }
642
643 void task_debug(uint64_t local, uint64_t world)
644 {
645         //tdma_debug(tdma_rcv);
646         //tdma_debug(tdma_xmt);
647
648         //sirq_debug(sirq_mbed);
649
650         //serial_send_event(sirq_bbb, 1, local);
651
652 #ifdef VERBOSE
653         sirq_printf("background - %6u.%02u -> %u.%02u\r\n",
654                         (uint32_t)(local / NSEC_PER_SEC),
655                         (uint32_t)(local % NSEC_PER_SEC / 10000000),
656                         (uint32_t)(world / NSEC_PER_SEC),
657                         (uint32_t)(world % NSEC_PER_SEC / 10000000));
658 #endif
659 }
660
661 /********
662  * Main *
663  ********/
664
665 #define N_ELEM(x) (sizeof(x) / sizeof((x)[0]))
666
667 extern void test_main(void);
668 extern serial_t stdio_uart;
669
670 static struct {
671         void (*task)(uint64_t, uint64_t);
672         uint64_t period;
673         uint64_t due;
674 } tasks[] = {
675         { task_serial, 0          }, // always
676         { task_events, 0          }, // always -- testing
677         { task_sync,   0          }, // always
678         { task_emit,   0          }, // always
679         { task_leds,   100000000  }, // 10hz
680         { task_debug,  1000000000 }, // 1hz
681 };
682
683 void background(void)
684 {
685         // Debugging
686         uint64_t local = tdma_time();
687         uint64_t world = time_to_world(local);
688
689         // Run the scheduler
690         for (unsigned i = 0; i < N_ELEM(tasks); i++) {
691                 if (local >= tasks[i].due) {
692                         tasks[i].task(local, world);
693                         tasks[i].due += tasks[i].period;
694                 }
695         }
696 }
697
698 int main(int argc, char **argv)
699 {
700         tdma_init();
701
702         //pin = 1;
703
704         // Open serial ports
705         sirq_dbg   = sirq_open(SIRQ_UART0, USBTX, USBRX, 115200); // to pc
706         sirq_bbb   = sirq_open(SIRQ_UART1, PTE0,  PTE1,  115200); // to bbb
707         sirq_mbed  = sirq_open(SIRQ_UART2, PTD3,  PTD2,  115200); // to mbed
708
709         // Setup timers
710         tdma_evt   = tdma_open(TDMA_CHAN0, 3, PTC9,  PullDown); // async event
711
712         // mbed time sync
713         tdma_rcv   = tdma_open(TDMA_CHAN2, 3, PTD2,  PullUp);   // time sync rcv
714         tdma_xmt   = tdma_open(TDMA_CHAN3, 3, PTD3,  PullUp);   // time sync xmt
715
716         // host time sync
717         //tdma_rcv   = tdma_open(TDMA_CHAN2, 2, USBRX, PullUp); // time sync rcv
718         //tdma_xmt   = tdma_open(TDMA_CHAN3, 2, USBTX, PullUp); // time sync xmt
719
720         // start timers
721         tdma_start(tdma_evt);
722         tdma_start(tdma_rcv);
723         tdma_start(tdma_xmt);
724
725         // Serial timestamping
726         serial_tdma_rcv = tdma_rcv;
727         serial_tdma_xmt = tdma_xmt;
728
729         // Setup event generation
730         emit_init(3, PTE20, PullDown);
731
732         // Run background loop
733         while (true)
734                 background();
735
736         // Run tests
737         //test_main();
738
739         return 0;
740 }