]> Pileus Git - ~andy/csm213a-hw/blob - hw2/main.cpp
108000ee6dfbf42a81bf5bb47f2181498d9f7f6d
[~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  *   local: drift compensated wall-clock time
35  *   world: nanoseconds in world time world
36  *   valid: local timestamp at valid valid
37  */
38 //uint64_t time_to_local(uint64_t world, uint64_t valid)
39 //{
40 //      uint64_t now =
41 //      local =  + (stamp);
42 //}
43
44 /**
45  * Generate time stamp for an async event:
46  *   time:  drift compensated wall-clock time
47  *   stamp: event timestamp from PIT Module
48  */
49 uint64_t time_to_world(uint64_t local)
50 {
51         uint64_t elapsed = local - time_last_local;
52         return time_last_world + elapsed;
53 }
54
55 /**
56  * Compensate the Real-Time-Clock oscillator for
57  * temperature and drift errors. Called at 1Hz and
58  * synchronous to the RTC 1Hz output.
59  */
60 void time_rtc_comp(void)
61 {
62         // todo
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_init(uint64_t local, uint64_t world)
72 {
73         sirq_printf("initialize clocks: %d -> %d\r\n",
74                         (int)(local/NSEC_PER_SEC),
75                         (int)(world/NSEC_PER_SEC));
76
77         time_last_local = local;
78         time_last_world = world;
79 }
80
81 /**
82  * Synchronize the timer internal state with updates
83  * from an external time sync message.
84  *   local: our internal timestamp for the event
85  *   world: reference timestamp from the other device
86  */
87 void time_ext_sync(uint64_t local, uint64_t world)
88 {
89         uint64_t guess = time_to_world(local);
90         uint64_t error = world > guess ? world - guess :
91                          guess > world ? guess - world : 0;
92         int      ahead = guess > world;
93
94         time_last_local = local;
95         time_last_world = guess/2 + world/2;
96
97         world = time_last_world;
98
99         sirq_printf("syncing clocks: %d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n",
100                         (int)((local / NSEC_PER_SEC)),
101                         (int)((guess / NSEC_PER_SEC)),
102                         (int)((guess % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
103                         (int)((world / NSEC_PER_SEC)),
104                         (int)((world % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
105                         ahead ? "-" : "",
106                         (int32_t )(error / (int64_t)NSEC_PER_SEC),
107                         (uint32_t)(error % (int64_t)NSEC_PER_SEC));
108 }
109
110 /************************
111  * Serial I/O functions *
112  ************************/
113
114 typedef struct {
115         int      index;
116         int      state;
117         uint8_t  buffer[256];
118 } parser_t;
119
120 const  uint64_t serial_sync_delay = NSEC_PER_SEC / 10; // 1hz
121 static uint64_t serial_sync_due   = 0;
122
123 static tdma_t  *serial_tdma_rcv   = NULL;
124 static tdma_t  *serial_tdma_xmt   = NULL;
125
126 static uint64_t serial_prev_local = 0;
127 static uint64_t serial_prev_seq   = 0;
128
129 static uint64_t serial_xmt_local  = 0;
130 static uint64_t serial_xmt_seq    = 0;
131
132 /**
133  * Output time sync message
134  */
135 void serial_send_sync(sirq_t *port, uint64_t now)
136 {
137         if (serial_sync_due == 0 || now < serial_sync_due)
138                 return; // not ready
139
140         // Calculate world time
141         uint64_t world = time_to_world(serial_xmt_local);
142
143         // Message data
144         header_t   head;
145         sync_msg_t body;
146
147         // Transmit sync message
148         head.header = MSG_HEADER;
149         head.msgid  = MSG_ID_SYNC;
150         head.length = sizeof(body);
151         head.cksum  = 0; // todo
152
153         body.seq          = serial_xmt_seq;
154         body.time.seconds = world / NSEC_PER_SEC;
155         body.time.nanosec = world % NSEC_PER_SEC;
156
157         sirq_write(port, &head, sizeof(head));
158         sirq_write(port, &body, sizeof(body));
159
160         serial_xmt_seq  += 1;
161         serial_sync_due  = 0;
162
163         // Debug
164         //sirq_printf("sync msg transmit\r\n");
165
166         // save transmit time
167         for (int i = 0; i < 1000; i++)
168                 asm("nop");
169         int valid = tdma_stamp(serial_tdma_xmt, &serial_xmt_local);
170         if (!valid)
171                 sirq_printf("missing sync transmit time\r\n");
172         tdma_reset(serial_tdma_rcv);
173         tdma_reset(serial_tdma_xmt);
174 }
175
176 /**
177  * Output external event received message
178  *   event: id of the received event
179  *   time:  compensated timestamp of the event
180  */
181 void serial_send_event(uint16_t event, uint64_t local)
182 {
183         uint64_t world = time_to_world(local);
184
185         ntime_t time = {};
186         time.seconds = (uint32_t)(world / NSEC_PER_SEC);
187         time.nanosec = (uint32_t)(world % NSEC_PER_SEC);
188
189         sirq_printf("event received - %08x:%08x - %u.%09u\r\n",
190                 (uint32_t)(local >> 32), (uint32_t)local,
191                 time.seconds, time.nanosec);
192         // todo
193 }
194
195 /**
196  * Handle sync message
197  */
198 void serial_handle_sync(sync_msg_t *msg)
199 {
200         // Read receive timestamp for next time sync message
201         uint64_t current = 0;
202         int valid = tdma_stamp(serial_tdma_rcv, &current);
203         if (!valid)
204                 sirq_printf("missing sync receive time\r\n");
205         tdma_reset(serial_tdma_rcv);
206         tdma_reset(serial_tdma_xmt);
207
208         // Lookup times
209         uint64_t world = ((uint64_t)msg->time.seconds) * NSEC_PER_SEC
210                        + ((uint64_t)msg->time.nanosec);
211
212         // Initialize
213         if (msg->seq == 0) {
214                 uint64_t local = tdma_time();
215                 time_ext_init(local, world);
216         }
217
218         // Valid times timestamp
219         if (serial_prev_seq == (msg->seq-1)) {
220                 uint64_t local = serial_prev_local;
221                 time_ext_sync(local, world);
222         }
223
224         // Queue transmit to other board
225         serial_sync_due   = tdma_time() + serial_sync_delay;
226
227         // Update states
228         serial_prev_local = current;
229         serial_prev_seq   = msg->seq;
230 }
231
232 /**
233  * Handle event message
234  */
235 void serial_handle_event(event_msg_t *msg)
236 {
237 }
238
239 /**
240  * Deliver message
241  */
242 void serial_deliver(int msgid, void *body)
243 {
244         switch (msgid) {
245                 case MSG_ID_SYNC:
246                         //sirq_printf("received sync msg\r\n");
247                         serial_handle_sync((sync_msg_t*)body);
248                         break;
249                 case MSG_ID_EVENT:
250                         //sirq_printf("received event msg\r\n");
251                         serial_handle_event((event_msg_t*)body);
252                         break;
253         }
254 }
255
256 /**
257  * Process serial receive messages
258  */
259 void serial_receive(parser_t *parser, int byte)
260 {
261         //sirq_printf("serial_receive - %02x\r\n", byte);
262
263         // Lookup pointers
264         header_t *head = (header_t*)parser->buffer;
265         void     *body = (void*)(head+1);
266         const int max_length = sizeof(parser->buffer)-sizeof(header_t);
267
268         // Process uart messages
269         parser->buffer[parser->index++] = byte;
270         switch (parser->state) {
271                 case 0: // Search
272                         if (parser->index == sizeof(uint16_t)) {
273                                 if (head->header == MSG_HEADER) {
274                                         parser->state = 1;
275                                 } else {
276                                         parser->buffer[0] = parser->buffer[1];
277                                         parser->index = 1;
278                                 }
279                         }
280                         break;
281                 case 1: // Header
282                         if (parser->index == sizeof(header_t)) {
283                                 if (head->length <= max_length &&
284                                     head->msgid  <= MSG_MAXID) {
285                                         parser->state = 2;
286                                 } else {
287                                         parser->index = 0;
288                                         parser->state = 0;
289                                 }
290                         }
291                         break;
292                 case 2: // Data
293                         if (parser->index == (int)sizeof(header_t)+head->length) {
294                                 serial_deliver(head->msgid, body);
295                                 parser->index = 0;
296                                 parser->state = 0;
297                         }
298                         break;
299         }
300 }
301
302 /********************
303  * Data definitions *
304  ********************/
305
306 // LEDs
307 DigitalOut led1(LED1);
308 DigitalOut led2(LED2);
309
310 // Message Parsers
311 parser_t   parser_dbg;
312 parser_t   parser_bbb;
313 parser_t   parser_mbed;
314
315 // Serial IRQ
316 sirq_t    *sirq_dbg;
317 sirq_t    *sirq_bbb;
318 sirq_t    *sirq_mbed;
319
320 // Timer DMA
321 tdma_t    *tdma_evt;
322 tdma_t    *tdma_rcv;
323 tdma_t    *tdma_xmt;
324
325 /*********
326  * Tasks *
327  *********/
328
329 void task_serial(uint64_t local, uint64_t world)
330 {
331         while (sirq_ready(sirq_dbg)) {
332                 //sirq_printf("serial recv - dbg\r\n");
333                 serial_receive(&parser_dbg,  sirq_getc(sirq_dbg));
334         }
335
336         while (sirq_ready(sirq_bbb)) {
337                 //sirq_printf("serial recv - bbb\r\n");
338                 serial_receive(&parser_bbb,  sirq_getc(sirq_bbb));
339         }
340
341         while (sirq_ready(sirq_mbed)) {
342                 //sirq_printf("serial recv - mbed\r\n");
343                 serial_receive(&parser_mbed, sirq_getc(sirq_mbed));
344         }
345 }
346
347 void task_events(uint64_t local, uint64_t world)
348 {
349         uint64_t event = 0;
350
351 #ifdef VERBOSE
352         if (tdma_stamp(tdma_evt, &event)) {
353                 sirq_printf("event received - evt\r\n");
354         if (tdma_stamp(tdma_rcv, &event))
355                 sirq_printf("event received - rcv\r\n");
356         if (tdma_stamp(tdma_xmt, &event))
357                 sirq_printf("event received - xmt\r\n");
358 #endif
359
360         if (tdma_stamp(tdma_evt, &event))
361                 serial_send_event(0, event);
362         tdma_reset(tdma_evt);
363 }
364
365 void task_sync(uint64_t local, uint64_t world)
366 {
367         serial_send_sync(sirq_mbed, local);
368 }
369
370 void task_leds(uint64_t local, uint64_t world)
371 {
372         static uint32_t which = 0;
373         led1 = (which == 0);
374         led2 = (which == 1);
375         which ^= 1;
376 }
377
378 void task_debug(uint64_t local, uint64_t world)
379 {
380         //tdma_debug(tdma_rcv);
381 #ifdef VERBOSE
382         sirq_printf("background - %6u.%02u -> %u.%02u\r\n",
383                         (uint32_t)(local / NSEC_PER_SEC),
384                         (uint32_t)(local % NSEC_PER_SEC / 10000000),
385                         (uint32_t)(world / NSEC_PER_SEC),
386                         (uint32_t)(world % NSEC_PER_SEC / 10000000));
387 #endif
388 }
389
390 /********
391  * Main *
392  ********/
393
394 #define N_ELEM(x) (sizeof(x) / sizeof((x)[0]))
395
396 extern void test_main(void);
397 extern serial_t stdio_uart;
398
399 static struct {
400         void (*task)(uint64_t, uint64_t);
401         uint64_t period;
402         uint64_t due;
403 } tasks[] = {
404         { task_serial, 0          }, // always
405         { task_events, 1000000000 }, // always
406         { task_sync,   0          }, // always
407         { task_leds,   100000000  }, // 10hz
408         { task_debug,  1000000000 }, // 1hz
409 };
410
411 void background(void)
412 {
413         // Debugging
414         uint64_t local = tdma_time();
415         uint64_t world = time_to_world(local);
416
417         // Run the scheduler
418         for (unsigned i = 0; i < N_ELEM(tasks); i++) {
419                 if (local >= tasks[i].due) {
420                         tasks[i].task(local, world);
421                         tasks[i].due += tasks[i].period;
422                 }
423         }
424 }
425
426 int main(int argc, char **argv)
427 {
428         tdma_init();
429
430         // Open serial ports
431         sirq_dbg   = sirq_open(SIRQ_UART0, USBTX, USBRX, 115200); // to pc
432         sirq_bbb   = sirq_open(SIRQ_UART1, PTE0,  PTE1,  115200); // to bbb
433         sirq_mbed  = sirq_open(SIRQ_UART2, PTD3,  PTD2,  115200); // to mbed
434
435
436         // Setup timers
437         tdma_evt   = tdma_open(TDMA_CHAN0, 3, PTC9,  PullDown); // async event
438
439         // mbed time sync
440         tdma_rcv   = tdma_open(TDMA_CHAN2, 3, PTD2,  PullUp);   // time sync rcv
441         tdma_xmt   = tdma_open(TDMA_CHAN3, 3, PTD3,  PullUp);   // time sync xmt
442
443         // host time sync
444         //tdma_rcv   = tdma_open(TDMA_CHAN2, 2, USBRX, PullUp); // time sync rcv
445         //tdma_xmt   = tdma_open(TDMA_CHAN3, 2, USBTX, PullUp); // time sync xmt
446
447         // Serial timestamping
448         serial_tdma_rcv = tdma_rcv;
449         serial_tdma_xmt = tdma_xmt;
450
451         // Run background loop
452         printf("hello");
453         while (true)
454                 background();
455
456         // Run tests
457         //test_main();
458
459         return 0;
460 }