]> Pileus Git - ~andy/csm213a-hw/commitdiff
Refactor main into separate files
authorAndy Spencer <andy753421@gmail.com>
Sat, 15 Mar 2014 03:28:04 +0000 (03:28 +0000)
committerAndy Spencer <andy753421@gmail.com>
Sat, 15 Mar 2014 03:28:38 +0000 (03:28 +0000)
12 files changed:
hw2/main.cpp
hw2/main_comm.c [new file with mode: 0644]
hw2/main_comm.h [new file with mode: 0644]
hw2/main_emit.c [new file with mode: 0644]
hw2/main_emit.h [new file with mode: 0644]
hw2/main_time.c [new file with mode: 0644]
hw2/main_time.h [new file with mode: 0644]
hw2/makefile
hw2/messages.c
hw2/messages.h
hw2/timer_dma.c
hw2/timer_dma.h

index 1bc0cda280da2e3effc2cfe5ab90a815989024fa..2c2d86d2ce72990fb057b93044e00ccc581976ba 100644 (file)
@@ -5,6 +5,10 @@
 #include "serial_dma.h"
 #include "timer_dma.h"
 
+#include "main_time.h"
+#include "main_emit.h"
+#include "main_comm.h"
+
 /**
  * Mode of operation:
  *   Devices 1 and 2 synchronize clocks using serial messages.
  */
 
 /*******************
- * Timer functions *
+ * Tasks Scheduler *
  *******************/
 
-#define NSEC_PER_SEC 1000000000ULL
-
-uint64_t time_last_local; // timestamp at last time sync
-uint64_t time_last_world; // offset at last time sync
-
-/**
- * Generate time stamp for an async event:
- *   time:  drift compensated wall-clock time
- *   stamp: event timestamp from PIT Module
- */
-uint64_t time_to_world(uint64_t local)
-{
-       uint64_t elapsed = local - time_last_local;
-       return time_last_world + elapsed;
-}
-
-uint64_t time_to_local(uint64_t world)
-{
-       uint64_t elapsed = world - time_last_world;
-       return time_last_local + elapsed;
-}
-
-/**
- * Synchronize the timer internal state with updates
- * from an external time sync message.
- *   local: our internal timestamp for the event
- *   world: reference timestamp from the other device
- */
-void time_ext_init(uint64_t local, uint64_t world)
-{
-       sirq_printf("initialize clocks: %d -> %d\r\n",
-                       (int)(local/NSEC_PER_SEC),
-                       (int)(world/NSEC_PER_SEC));
-
-       time_last_local = local;
-       time_last_world = world;
-}
-
-/**
- * Synchronize the timer internal state with updates
- * from an external time sync message.
- *   local: our internal timestamp for the event
- *   world: reference timestamp from the other device
- */
-void time_ext_sync(uint64_t local, uint64_t world)
-{
-       uint64_t guess = time_to_world(local);
-
-       time_last_local = local;
-       time_last_world = (guess/2) + (world/2);
-       //time_last_world = (guess * 3 / 4) + (world * 1 / 4);
-       //time_last_world =
-       //      (guess - (        guess / 2)) +
-       //      (world - (world - world / 2));
-       //time_last_world =
-       //      (guess - (guess - guess / 4)) +
-       //      (world - (        world / 4));
-
-       world = time_last_world;
-
-//#ifdef VERBOSE
-#if 1
-       uint64_t error = world > guess ? world - guess :
-                        guess > world ? guess - world : 0;
-       int      ahead = guess > world;
-       sirq_printf("syncing clocks: %6d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n",
-                       (int)((local / NSEC_PER_SEC)),
-                       (int)((guess / NSEC_PER_SEC)),
-                       (int)((guess % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
-                       (int)((world / NSEC_PER_SEC)),
-                       (int)((world % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
-                       ahead ? "-" : " ",
-                       (int32_t )(error / (int64_t)NSEC_PER_SEC),
-                       (uint32_t)(error % (int64_t)NSEC_PER_SEC));
-#endif
-//#endif
-}
-
-void time_printf(const char *label, uint64_t local)
-{
-       uint64_t world = time_to_world(local);
-       sirq_printf("%s -- %d.%09u -> %d.%09u\r\n",
-                       label,
-                       (int)(local / NSEC_PER_SEC),
-                       (int)(local % NSEC_PER_SEC),
-                       (int)(world / NSEC_PER_SEC),
-                       (int)(world % NSEC_PER_SEC));
-}
-
-/*********************
- * Signal generation *
- *********************/
-
-// for 50 Mhz clock  50/1000 = 1/20  (PLL/2)
-
-// for 48 Mhz clock  48/1000 = 6/125 (FLL)
-// for 24 Mhz clock, 24/1000 = 3/125
-// for 12 Mhz clock, 12/1000 = 3/250
-// for  6 Mhz clock,  6/1000 = 3/500
-// for  3 Mhz clock,  3/1000 = 3/1000
-
-#define EMIT_PS 1
-
-//#if EMIT_PS == 0
-//#define EMIT_CLOCKS(nsec) ((uint16_t)((nsec)   / 20))
-//#define EMIT_NSEC(clocks) ((uint16_t)((clocks) * 20))
-
-#if EMIT_PS == 0
-#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 6 / 125))
-#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 125 / 6))
-#elif EMIT_PS == 1
-#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 125))
-#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 125 / 3))
-#elif EMIT_PS == 2
-#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 250))
-#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 250 / 3))
-#elif EMIT_PS == 3
-#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 500))
-#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 500 / 3))
-#elif EMIT_PS == 4
-#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 1000))
-#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 1000 / 3))
-#endif
-
-static uint32_t *emit_pcr    = 0; // transmit pin name
-
-static uint64_t  emit_start  = 0; // transmit start time (world time)
-static uint64_t  emit_period = 0; // transmit period
-static uint64_t  emit_due    = 0; // next transmit (world time)
-
-static uint32_t  emit_slack  = 0; // how far ahead we need to schedule, in us
-static uint32_t  emit_worst  = 0; // worst-case latency in task table
-
-void emit_init(int alt, PinName pin, PinMode mode)
-{
-       // Find pin
-       emit_pcr = (uint32_t*)(PORTA_BASE + pin);
-
-       // Enable clocks
-       SIM->SCGC6            |= SIM_SCGC6_TPM1_MASK;
-       SIM->SOPT2            |= SIM_SOPT2_TPMSRC(1);
-
-       // Reset PLL Source
-       //SIM->SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
-
-       // Debug print on SOPT2
-       // -- mbed may set PLLFLL when configuring UART0
-       // SOPT2: u0src=1 tpmsrc=1 USBSRC PLL/2 clkos=0 rtcos
-       sirq_printf("SOPT2: u0src=%d tpmsrc=%d %s %s clkos=%d %s\r\n",
-               (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     >> SIM_SOPT2_UART0SRC_SHIFT,
-               (SIM->SOPT2 & SIM_SOPT2_TPMSRC_MASK)       >> SIM_SOPT2_TPMSRC_SHIFT,
-               (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     ? "USBSRC" : "usbsrc",
-               (SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK)    ? "PLL/2"  : "FLL",
-               (SIM->SOPT2 & SIM_SOPT2_CLKOUTSEL_MASK)    >> SIM_SOPT2_CLKOUTSEL_SHIFT,
-               (SIM->SOPT2 & SIM_SOPT2_RTCCLKOUTSEL_MASK) ? "RTCOS"  : "rtcos");
-
-       // Set pin mode
-       emit_pcr[0]            = PORT_PCR_ISF_MASK
-                              | PORT_PCR_MUX(alt)
-                              | mode;
-
-       // Setup Timer/PWM Module
-       TPM1->SC               = TPM_SC_TOF_MASK;
-       TPM1->CNT              = TPM_CNT_COUNT(0);
-       TPM1->MOD              = TPM_MOD_MOD(0xFFFF);
-
-       TPM1->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK    // clear flag
-                              | TPM_CnSC_MSB_MASK    // set output highon match,
-                              | TPM_CnSC_ELSB_MASK   // cleared on overflow
-                              | TPM_CnSC_ELSA_MASK;  // ..
-
-       TPM1->STATUS           = TPM_STATUS_CH0F_MASK
-                               | TPM_STATUS_TOF_MASK;
-
-       TPM1->CONF             = TPM_CONF_CSOO_MASK;
-}
-
-void emit_enable(uint64_t start, uint64_t period)
-{
-       const int slack_clocks = 0x4000; // tune based on emit_worst
-
-       emit_start  = start;
-       emit_period = period;
-       emit_due    = start + period;
-
-       emit_slack  = EMIT_NSEC(slack_clocks);
-
-       time_printf("emit scheduled", emit_due);
-}
-
-void emit_schedule(uint64_t when)
-{
-       uint64_t local  = time_to_local(when) * 3 / 125;
-       uint32_t width  = EMIT_CLOCKS(10000);
-
-       // Disable timer
-       TPM1->SC               = TPM_SC_TOF_MASK;
-
-       __disable_irq();
-
-       uint64_t now    = ((uint64_t)~PIT->LTMR64H << 32)
-                       | ((uint64_t)~PIT->LTMR64L);
-       uint32_t delta  = local - now;
-       uint32_t start  = delta >> (EMIT_PS-1); // convert to clocks
-       uint32_t stop   = start + width;        // end time
-
-       // Set transmit time
-       TPM1->CONTROLS[0].CnV  = start;
-       TPM1->MOD              = TPM_MOD_MOD(stop);
-
-       // Start the timer
-       TPM1->SC               = TPM_SC_TOF_MASK
-                              | TPM_SC_PS(EMIT_PS)
-                              | TPM_SC_CMOD(1);
-
-       __enable_irq();
-
-       // Test
-       //int64_t  cnv = TPM1->CONTROLS[0].CnV;
-       //int64_t  mod = TPM1->MOD;
-       //int64_t  due = local - tdma_time();
-       //sirq_printf("%6d -- cnv=%04x mod=%04x due=%04x start=%04x\r\n",
-       //              (int)(cnv - EMIT_CLOCKS(due)),
-       //              (int)cnv, (int)mod,
-       //              (int)EMIT_CLOCKS(due), EMIT_CLOCKS(start));
-
-       // Clock testing
-       //uint32_t test_tpm0 =  TPM1->CNT;
-       //uint32_t test_pit0 = ~PIT->CHANNEL[0].CVAL;
-       //for (int i = 0; i < 100; i++)
-       //      asm("nop");
-       //uint32_t test_tpm1 =  TPM1->CNT;
-       //uint32_t test_pit1 = ~PIT->CHANNEL[0].CVAL;
-
-       //uint32_t test_tpm  = test_tpm1 - test_tpm0;
-       //uint32_t test_pit  = test_pit1 - test_pit0;
-       //sirq_printf("pit/tpm: %d - tpm=%08x/%08x=%d pit=%08x/%08x=%d\r\n",
-       //              test_tpm - test_pit,
-       //              test_tpm0, test_tpm1, test_tpm,
-       //              test_pit0, test_pit1, test_pit);
-
-       // Debug output
-       //time_printf("emitting event", when);
-}
-
-void emit_transmit(uint64_t local, uint64_t world)
-{
-       static uint64_t prev = 0;
-
-       // Record how how much time we have to reschedule
-       if (prev && (local-prev) > emit_worst)
-               emit_worst = (local-prev);
-       prev = local;
-
-       // Schedule task if needed
-       if (emit_due && emit_period &&
-           world+emit_slack > emit_due) {
-               emit_schedule(emit_due);
-               emit_due += emit_period;
-       }
-}
-
-/************************
- * Serial I/O functions *
- ************************/
-
-static uint32_t serial_device_id   = 0;
-
-const  uint64_t serial_sync_delay  = NSEC_PER_SEC / 100;
-static uint64_t serial_sync_due    = 0;
-
-static tdma_t  *serial_tdma_rcv    = NULL;
-static tdma_t  *serial_tdma_xmt    = NULL;
-
-/**
- * Convert world to local time
- */
-uint64_t serial_read_time(ntime_t time)
-{
-       return ((uint64_t)time.seconds) * NSEC_PER_SEC
-            + ((uint64_t)time.nanosec);
-}
-
-ntime_t serial_write_time(uint64_t time)
-{
-       ntime_t buf = {};
-       buf.seconds = time / NSEC_PER_SEC;
-       buf.nanosec = time % NSEC_PER_SEC;
-       return buf;
-}
-
-int serial_time_stamp(tdma_t *port, uint64_t *local, uint64_t *world,
-               const char *msg)
-{
-       int valid = tdma_stamp(port, local);
-       *world = time_to_world(*local);
-
-       if (!valid)
-               sirq_printf("%s -- missing\r\n", msg);
-       //else
-       //      time_printf(msg, current);
-
-       return valid;
-}
-
-/**
- * Output initialization message init message
- */
-void serial_send_init(uint16_t device, uint64_t local)
-{
-}
-
-/**
- * Output time sync message
- */
-void serial_send_sync(sirq_t *port, uint64_t now)
-{
-       if (serial_sync_due == 0 || now < serial_sync_due)
-               return; // not ready
-
-       // Message data
-       header_t   head;
-       sync_msg_t body;
-
-       // Write header
-       head.header = MSG_HEADER;
-       head.msgid  = MSG_ID_SYNC;
-       head.length = sizeof(body);
-       head.cksum  = 0; // todo
-
-       tdma_stop(serial_tdma_rcv, 0);
-       tdma_start(serial_tdma_xmt);
-
-       sirq_write(port, &head, sizeof(head));
-
-       tdma_stop(serial_tdma_xmt, 100);
-       tdma_start(serial_tdma_rcv);
-
-       // Save transmit time
-       uint64_t local = 0, world = 0;
-       serial_time_stamp(serial_tdma_xmt, &local, &world,
-                       "sync time transmit");
-
-       // Debug output
-       //sirq_printf("sync time transmit\r\n");
-       //time_printf("  local", local);
-       //time_printf("  world", world);
-
-       // Write body with updated time and send
-       body.time = serial_write_time(world);
-
-       sirq_write(port, &body, sizeof(body));
-
-       // Queue next transmit time
-       serial_sync_due  = 0;
-}
-
-/**
- * Output external event received message
- *   event: id of the received event
- *   time:  compensated timestamp of the event
- */
-void serial_send_event(sirq_t *port, uint16_t event, uint64_t local)
-{
-       //time_printf("event received", local);
-
-       // Convert timestamp
-       uint64_t world = time_to_world(local);
-       ntime_t  ltime = serial_write_time(local);
-       ntime_t  wtime = serial_write_time(world);
-
-       // Message data
-       header_t    head = {};
-       event_msg_t body = {};
-
-       // Transmit sync message
-       head.header = MSG_HEADER;
-       head.msgid  = MSG_ID_EVENT;
-       head.length = sizeof(body);
-       head.cksum  = 0; // todo
-
-       body.device = serial_device_id;
-       body.event  = event;
-       body.world  = wtime;
-       body.local  = ltime;
-
-       // Transmit message to BBB
-       sirq_write(port, &head, sizeof(head));
-       sirq_write(port, &body, sizeof(body));
-}
-
-/**
- * Handle init message
- */
-void serial_handle_init(int msgid, init_msg_t *msg)
-{
-       sirq_printf("initialize: %s %s %s %s %s\r\n",
-               msg->valid & MSG_VALID_DEVICE ? "DEV"    : "dev",
-               msg->valid & MSG_VALID_START  ? "START"  : "start",
-               msg->valid & MSG_VALID_PERIOD ? "PERIOD" : "period",
-               msg->valid & MSG_VALID_WORLD  ? "WORLD"  : "world",
-               msg->valid & MSG_VALID_SYNC   ? "SYNC"   : "sync");
-       sirq_printf("  dev    -- %d\r\n", msg->device);
-       time_printf("  start ", serial_read_time(msg->start));
-       time_printf("  period", serial_read_time(msg->period));
-       time_printf("  world ", serial_read_time(msg->world));
-
-       if (msg->valid & MSG_VALID_DEVICE)
-               serial_device_id = msg->device;
-
-       if (msg->valid & MSG_VALID_START ||
-           msg->valid & MSG_VALID_PERIOD) {
-               uint64_t start  = serial_read_time(msg->start);
-               uint64_t period = serial_read_time(msg->period);
-               emit_enable(start, period);
-       }
-
-       if (msg->valid & MSG_VALID_WORLD) {
-               uint64_t world = serial_read_time(msg->world);
-               uint64_t local = tdma_time();
-               time_ext_init(local, world);
-       }
-
-       if (msg->valid & MSG_VALID_SYNC)
-               serial_sync_due = tdma_time() + serial_sync_delay;
-}
-
-/**
- * Handle sync message
- */
-void serial_handle_sync(int msgid, sync_msg_t *msg)
-{
-       // Read receive timestamp
-       uint64_t local = 0, world = 0;
-       serial_time_stamp(serial_tdma_rcv, &local, &world,
-                       "sync time receive ");
-       tdma_stop(serial_tdma_rcv, 0);
-
-       // Lookup reference time from message
-       uint64_t reference = serial_read_time(msg->time);
-
-       // Debug output
-       //sirq_printf("sync time receive\r\n");
-       //time_printf("  local", local);
-       //time_printf("  world", world);
-       //time_printf("  ref  ", reference);
-
-       // Synchronize the clocks
-       time_ext_sync(local, reference);
-
-       // Queue transmit to other board
-       serial_sync_due   = tdma_time() + serial_sync_delay;
-}
+// Macros
+#define N_ELEM(x) (sizeof(x) / sizeof((x)[0]))
 
-/**
- * Handle event message
- */
-void serial_handle_event(int msgid, event_msg_t *msg)
-{
-}
+// Task entry
+typedef struct {
+       void (*task)(uint64_t, uint64_t);
+       uint64_t period;
+       uint64_t due;
+} task_t;
+
+// Task functions
+void task_serial(uint64_t local, uint64_t world);
+void task_events(uint64_t local, uint64_t world);
+void task_sync(uint64_t local, uint64_t world);
+void task_leds(uint64_t local, uint64_t world);
+void task_emit(uint64_t local, uint64_t world);
+void task_debug(uint64_t local, uint64_t world);
+
+// Task table
+task_t tasks[] = {
+       { task_serial, 0          }, // always
+       { task_events, 0          }, // always -- testing
+       { task_sync,   0          }, // always
+       { task_emit,   0          }, // always
+       { task_leds,   100000000  }, // 10hz
+       { task_debug,  1000000000 }, // 1hz
+};
 
 /********************
  * Data definitions *
@@ -544,14 +115,14 @@ void task_events(uint64_t local, uint64_t world)
 #endif
 
        if (tdma_stamp(tdma_evt, &event))
-               serial_send_event(sirq_bbb, 0, event);
+               comm_send_event(sirq_bbb, 0, event);
        tdma_stop(tdma_evt, 0);
        tdma_start(tdma_evt);
 }
 
 void task_sync(uint64_t local, uint64_t world)
 {
-       serial_send_sync(sirq_mbed, local);
+       comm_send_sync(sirq_mbed, local);
 }
 
 void task_leds(uint64_t local, uint64_t world)
@@ -574,7 +145,7 @@ void task_debug(uint64_t local, uint64_t world)
 
        //sirq_debug(sirq_mbed);
 
-       serial_send_event(sirq_bbb, 1, local);
+       comm_send_event(sirq_bbb, 1, local);
 
 #ifdef VERBOSE
        sirq_printf("background - %6u.%02u -> %u.%02u\r\n",
@@ -589,24 +160,6 @@ void task_debug(uint64_t local, uint64_t world)
  * Main *
  ********/
 
-#define N_ELEM(x) (sizeof(x) / sizeof((x)[0]))
-
-extern void test_main(void);
-extern serial_t stdio_uart;
-
-static struct {
-       void (*task)(uint64_t, uint64_t);
-       uint64_t period;
-       uint64_t due;
-} tasks[] = {
-       { task_serial, 0          }, // always
-       { task_events, 0          }, // always -- testing
-       { task_sync,   0          }, // always
-       { task_emit,   0          }, // always
-       { task_leds,   100000000  }, // 10hz
-       { task_debug,  1000000000 }, // 1hz
-};
-
 void background(void)
 {
        // Debugging
@@ -624,8 +177,6 @@ void background(void)
 
 int main(int argc, char **argv)
 {
-       tdma_init();
-
        // Open serial ports
        sirq_dbg   = sirq_open(SIRQ_UART0, USBTX, USBRX, 115200); // to pc
        sirq_bbb   = sirq_open(SIRQ_UART1, PTE0,  PTE1,  115200); // to bbb
@@ -636,31 +187,30 @@ int main(int argc, char **argv)
        tdma_rcv   = tdma_open(TDMA_CHAN2, 3, PTD2,  PullUp);   // time sync rcv
        tdma_xmt   = tdma_open(TDMA_CHAN3, 3, PTD3,  PullUp);   // time sync xmt
 
+       // Setup event generation
+       time_init();
+       emit_init(3, PTE20, PullDown);
+       comm_init(sirq_dbg, sirq_bbb, sirq_mbed,
+                       tdma_rcv, tdma_xmt);
+
        // Register messages
-       msg_register(&parser_dbg,  MSG_ID_INIT,  (handler_t)serial_handle_init);
-       msg_register(&parser_dbg,  MSG_ID_SYNC,  (handler_t)serial_handle_sync);
-       msg_register(&parser_dbg,  MSG_ID_EVENT, (handler_t)serial_handle_event);
-       msg_register(&parser_bbb,  MSG_ID_INIT,  (handler_t)serial_handle_init);
-       msg_register(&parser_mbed, MSG_ID_SYNC,  (handler_t)serial_handle_sync);
+       msg_register(&parser_dbg,  MSG_ID_INIT,  (handler_t)comm_handle_init);
+       msg_register(&parser_dbg,  MSG_ID_SYNC,  (handler_t)comm_handle_sync);
+       msg_register(&parser_dbg,  MSG_ID_EVENT, (handler_t)comm_handle_event);
+
+       msg_register(&parser_bbb,  MSG_ID_INIT,  (handler_t)comm_handle_init);
+
+       msg_register(&parser_mbed, MSG_ID_SYNC,  (handler_t)comm_handle_sync);
+       msg_register(&parser_mbed, MSG_ID_EVENT, (handler_t)comm_handle_event);
 
        // start timers
        tdma_start(tdma_evt);
        tdma_start(tdma_rcv);
        tdma_start(tdma_xmt);
 
-       // Serial timestamping
-       serial_tdma_rcv = tdma_rcv;
-       serial_tdma_xmt = tdma_xmt;
-
-       // Setup event generation
-       emit_init(3, PTE20, PullDown);
-
        // Run background loop
        while (true)
                background();
 
-       // Run tests
-       //test_main();
-
        return 0;
 }
diff --git a/hw2/main_comm.c b/hw2/main_comm.c
new file mode 100644 (file)
index 0000000..e31fc56
--- /dev/null
@@ -0,0 +1,231 @@
+#include <stdint.h>
+
+#include "messages.h"
+
+#include "serial_irq.h"
+#include "timer_dma.h"
+
+#include "main_time.h"
+#include "main_emit.h"
+
+/***************************
+ * Communication functions *
+ ***************************/
+
+static uint32_t comm_device_id   = 0;
+
+const  uint64_t comm_sync_delay  = NSEC_PER_SEC / 100;
+static uint64_t comm_sync_due    = 0;
+
+static sirq_t  *comm_sirq_dbg    = 0;
+static sirq_t  *comm_sirq_bbb    = 0;
+static sirq_t  *comm_sirq_mbed   = 0;
+
+static tdma_t  *comm_tdma_rcv    = 0;
+static tdma_t  *comm_tdma_xmt    = 0;
+
+/**
+ * Initialization
+ */
+void comm_init(sirq_t *dbg, sirq_t *bbb, sirq_t *mbed,
+               tdma_t *rcv, tdma_t *xmt)
+{
+       comm_sirq_dbg  = dbg;
+       comm_sirq_bbb  = bbb;
+       comm_sirq_mbed = mbed;
+
+       comm_tdma_rcv  = rcv;
+       comm_tdma_xmt  = xmt;
+}
+
+/**
+ * Convert world to local time
+ */
+uint64_t comm_read_time(ntime_t time)
+{
+       return ((uint64_t)time.seconds) * NSEC_PER_SEC
+            + ((uint64_t)time.nanosec);
+}
+
+ntime_t comm_write_time(uint64_t time)
+{
+       ntime_t buf = {};
+       buf.seconds = time / NSEC_PER_SEC;
+       buf.nanosec = time % NSEC_PER_SEC;
+       return buf;
+}
+
+int comm_time_stamp(tdma_t *port, uint64_t *local, uint64_t *world,
+               const char *msg)
+{
+       int valid = tdma_stamp(port, local);
+       *world = time_to_world(*local);
+
+       if (!valid)
+               sirq_printf("%s -- missing\r\n", msg);
+       //else
+       //      time_printf(msg, current);
+
+       return valid;
+}
+
+/**
+ * Output initialization message init message
+ */
+void comm_send_init(uint16_t device, uint64_t local)
+{
+}
+
+/**
+ * Output time sync message
+ */
+void comm_send_sync(sirq_t *port, uint64_t now)
+{
+       if (comm_sync_due == 0 || now < comm_sync_due)
+               return; // not ready
+
+       // Message data
+       header_t   head;
+       sync_msg_t body;
+
+       // Write header
+       head.header = MSG_HEADER;
+       head.msgid  = MSG_ID_SYNC;
+       head.length = sizeof(body);
+       head.cksum  = 0; // todo
+
+       tdma_stop(comm_tdma_rcv, 0);
+       tdma_start(comm_tdma_xmt);
+
+       sirq_write(port, &head, sizeof(head));
+
+       tdma_stop(comm_tdma_xmt, 100);
+       tdma_start(comm_tdma_rcv);
+
+       // Save transmit time
+       uint64_t local = 0, world = 0;
+       comm_time_stamp(comm_tdma_xmt, &local, &world,
+                       "sync time transmit");
+
+       // Debug output
+       //sirq_printf("sync time transmit\r\n");
+       //time_printf("  local", local);
+       //time_printf("  world", world);
+
+       // Write body with updated time and send
+       body.time = comm_write_time(world);
+
+       sirq_write(port, &body, sizeof(body));
+
+       // Queue next transmit time
+       comm_sync_due  = 0;
+}
+
+/**
+ * Output external event received message
+ *   event: id of the received event
+ *   time:  compensated timestamp of the event
+ */
+void comm_send_event(sirq_t *port, uint16_t event, uint64_t local)
+{
+       //time_printf("event received", local);
+
+       // Convert timestamp
+       uint64_t world = time_to_world(local);
+       ntime_t  ltime = comm_write_time(local);
+       ntime_t  wtime = comm_write_time(world);
+
+       // Message data
+       header_t    head = {};
+       event_msg_t body = {};
+
+       // Transmit sync message
+       head.header = MSG_HEADER;
+       head.msgid  = MSG_ID_EVENT;
+       head.length = sizeof(body);
+       head.cksum  = 0; // todo
+
+       body.device = comm_device_id;
+       body.event  = event;
+       body.world  = wtime;
+       body.local  = ltime;
+
+       // Transmit message to BBB
+       sirq_write(port, &head, sizeof(head));
+       sirq_write(port, &body, sizeof(body));
+}
+
+/**
+ * Handle init message
+ */
+void comm_handle_init(int msgid, init_msg_t *body)
+{
+       sirq_printf("initialize: %s %s %s %s %s\r\n",
+               body->valid & MSG_VALID_DEVICE ? "DEV"    : "dev",
+               body->valid & MSG_VALID_START  ? "START"  : "start",
+               body->valid & MSG_VALID_PERIOD ? "PERIOD" : "period",
+               body->valid & MSG_VALID_WORLD  ? "WORLD"  : "world",
+               body->valid & MSG_VALID_SYNC   ? "SYNC"   : "sync");
+       sirq_printf("  dev    -- %d\r\n", body->device);
+       time_printf("  start ", comm_read_time(body->start));
+       time_printf("  period", comm_read_time(body->period));
+       time_printf("  world ", comm_read_time(body->world));
+
+       if (body->valid & MSG_VALID_DEVICE)
+               comm_device_id = body->device;
+
+       if (body->valid & MSG_VALID_START ||
+           body->valid & MSG_VALID_PERIOD) {
+               uint64_t start  = comm_read_time(body->start);
+               uint64_t period = comm_read_time(body->period);
+               emit_enable(start, period);
+       }
+
+       if (body->valid & MSG_VALID_WORLD) {
+               uint64_t world = comm_read_time(body->world);
+               uint64_t local = tdma_time();
+               time_ext_init(local, world);
+       }
+
+       if (body->valid & MSG_VALID_SYNC)
+               comm_sync_due = tdma_time() + comm_sync_delay;
+}
+
+/**
+ * Handle sync message
+ */
+void comm_handle_sync(int msgid, sync_msg_t *body)
+{
+       // Read receive timestamp
+       uint64_t local = 0, world = 0;
+       comm_time_stamp(comm_tdma_rcv, &local, &world,
+                       "sync time receive ");
+       tdma_stop(comm_tdma_rcv, 0);
+
+       // Lookup reference time from message
+       uint64_t reference = comm_read_time(body->time);
+
+       // Debug output
+       //sirq_printf("sync time receive\r\n");
+       //time_printf("  local", local);
+       //time_printf("  world", world);
+       //time_printf("  ref  ", reference);
+
+       // Synchronize the clocks
+       time_ext_sync(local, reference);
+
+       // Queue transmit to other board
+       comm_sync_due   = tdma_time() + comm_sync_delay;
+}
+
+/**
+ * Handle event message
+ */
+void comm_handle_event(header_t *head, event_msg_t *body)
+{
+       // Relay event from mbed to bbb
+       if (comm_device_id == 1) {
+               sirq_write(comm_sirq_bbb, &head, sizeof(head));
+               sirq_write(comm_sirq_bbb, &body, sizeof(body));
+       }
+}
diff --git a/hw2/main_comm.h b/hw2/main_comm.h
new file mode 100644 (file)
index 0000000..299b223
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef MAIN_COMM_H
+#define MAIN_COMM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "timer_dma.h"
+#include "serial_irq.h"
+
+/**
+ * Initialization
+ */
+void comm_init(sirq_t *dbg, sirq_t *bbb, sirq_t *mbed,
+               tdma_t *rcv, tdma_t *xmt);
+
+/**
+ * Output initialization message init message
+ */
+void comm_send_init(uint16_t device, uint64_t local);
+void comm_send_sync(sirq_t *port, uint64_t now);
+void comm_send_event(sirq_t *port, uint16_t event, uint64_t local);
+
+/**
+ * Handle init message
+ */
+void comm_handle_init(int msgid, init_msg_t *msg);
+void comm_handle_sync(int msgid, sync_msg_t *msg);
+void comm_handle_event(int msgid, event_msg_t *msg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw2/main_emit.c b/hw2/main_emit.c
new file mode 100644 (file)
index 0000000..ffec296
--- /dev/null
@@ -0,0 +1,179 @@
+#include <stdint.h>
+
+#include "serial_irq.h"
+#include "main_time.h"
+#include "main_emit.h"
+
+/*********************
+ * Signal generation *
+ *********************/
+
+// for 50 Mhz clock  50/1000 = 1/20  (PLL/2)
+
+// for 48 Mhz clock  48/1000 = 6/125 (FLL)
+// for 24 Mhz clock, 24/1000 = 3/125
+// for 12 Mhz clock, 12/1000 = 3/250
+// for  6 Mhz clock,  6/1000 = 3/500
+// for  3 Mhz clock,  3/1000 = 3/1000
+
+#define EMIT_PS 1
+
+//#if EMIT_PS == 0
+//#define EMIT_CLOCKS(nsec) ((uint16_t)((nsec)   / 20))
+//#define EMIT_NSEC(clocks) ((uint16_t)((clocks) * 20))
+
+#if EMIT_PS == 0
+#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 6 / 125))
+#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 125 / 6))
+#elif EMIT_PS == 1
+#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 125))
+#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 125 / 3))
+#elif EMIT_PS == 2
+#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 250))
+#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 250 / 3))
+#elif EMIT_PS == 3
+#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 500))
+#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 500 / 3))
+#elif EMIT_PS == 4
+#define EMIT_CLOCKS(nsec) ((uint32_t)((nsec)   * 3 / 1000))
+#define EMIT_NSEC(clocks) ((uint32_t)((clocks) * 1000 / 3))
+#endif
+
+static uint32_t *emit_pcr    = 0; // transmit pin name
+
+static uint64_t  emit_start  = 0; // transmit start time (world time)
+static uint64_t  emit_period = 0; // transmit period
+static uint64_t  emit_due    = 0; // next transmit (world time)
+
+static uint32_t  emit_slack  = 0; // how far ahead we need to schedule, in us
+static uint32_t  emit_worst  = 0; // worst-case latency in task table
+
+void emit_init(int alt, PinName pin, PinMode mode)
+{
+       // Find pin
+       emit_pcr = (uint32_t*)(PORTA_BASE + pin);
+
+       // Enable clocks
+       SIM->SCGC6            |= SIM_SCGC6_TPM1_MASK;
+       SIM->SOPT2            |= SIM_SOPT2_TPMSRC(1);
+
+       // Reset PLL Source
+       //SIM->SOPT2 &= ~SIM_SOPT2_PLLFLLSEL_MASK;
+
+       // Debug print on SOPT2
+       // -- mbed may set PLLFLL when configuring UART0
+       // SOPT2: u0src=1 tpmsrc=1 USBSRC PLL/2 clkos=0 rtcos
+       sirq_printf("SOPT2: u0src=%d tpmsrc=%d %s %s clkos=%d %s\r\n",
+               (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     >> SIM_SOPT2_UART0SRC_SHIFT,
+               (SIM->SOPT2 & SIM_SOPT2_TPMSRC_MASK)       >> SIM_SOPT2_TPMSRC_SHIFT,
+               (SIM->SOPT2 & SIM_SOPT2_UART0SRC_MASK)     ? "USBSRC" : "usbsrc",
+               (SIM->SOPT2 & SIM_SOPT2_PLLFLLSEL_MASK)    ? "PLL/2"  : "FLL",
+               (SIM->SOPT2 & SIM_SOPT2_CLKOUTSEL_MASK)    >> SIM_SOPT2_CLKOUTSEL_SHIFT,
+               (SIM->SOPT2 & SIM_SOPT2_RTCCLKOUTSEL_MASK) ? "RTCOS"  : "rtcos");
+
+       // Set pin mode
+       emit_pcr[0]            = PORT_PCR_ISF_MASK
+                              | PORT_PCR_MUX(alt)
+                              | mode;
+
+       // Setup Timer/PWM Module
+       TPM1->SC               = TPM_SC_TOF_MASK;
+       TPM1->CNT              = TPM_CNT_COUNT(0);
+       TPM1->MOD              = TPM_MOD_MOD(0xFFFF);
+
+       TPM1->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK    // clear flag
+                              | TPM_CnSC_MSB_MASK    // set output highon match,
+                              | TPM_CnSC_ELSB_MASK   // cleared on overflow
+                              | TPM_CnSC_ELSA_MASK;  // ..
+
+       TPM1->STATUS           = TPM_STATUS_CH0F_MASK
+                               | TPM_STATUS_TOF_MASK;
+
+       TPM1->CONF             = TPM_CONF_CSOO_MASK;
+}
+
+void emit_enable(uint64_t start, uint64_t period)
+{
+       const int slack_clocks = 0x4000; // tune based on emit_worst
+
+       emit_start  = start;
+       emit_period = period;
+       emit_due    = start + period;
+
+       emit_slack  = EMIT_NSEC(slack_clocks);
+
+       time_printf("emit scheduled", emit_due);
+}
+
+void emit_schedule(uint64_t when)
+{
+       uint64_t local  = time_to_local(when) * 3 / 125;
+       uint32_t width  = EMIT_CLOCKS(10000);
+
+       // Disable timer
+       TPM1->SC               = TPM_SC_TOF_MASK;
+
+       __disable_irq();
+
+       uint64_t now    = ((uint64_t)~PIT->LTMR64H << 32)
+                       | ((uint64_t)~PIT->LTMR64L);
+       uint32_t delta  = local - now;
+       uint32_t start  = delta >> (EMIT_PS-1); // convert to clocks
+       uint32_t stop   = start + width;        // end time
+
+       // Set transmit time
+       TPM1->CONTROLS[0].CnV  = start;
+       TPM1->MOD              = TPM_MOD_MOD(stop);
+
+       // Start the timer
+       TPM1->SC               = TPM_SC_TOF_MASK
+                              | TPM_SC_PS(EMIT_PS)
+                              | TPM_SC_CMOD(1);
+
+       __enable_irq();
+
+       // Test
+       //int64_t  cnv = TPM1->CONTROLS[0].CnV;
+       //int64_t  mod = TPM1->MOD;
+       //int64_t  due = local - tdma_time();
+       //sirq_printf("%6d -- cnv=%04x mod=%04x due=%04x start=%04x\r\n",
+       //              (int)(cnv - EMIT_CLOCKS(due)),
+       //              (int)cnv, (int)mod,
+       //              (int)EMIT_CLOCKS(due), EMIT_CLOCKS(start));
+
+       // Clock testing
+       //uint32_t test_tpm0 =  TPM1->CNT;
+       //uint32_t test_pit0 = ~PIT->CHANNEL[0].CVAL;
+       //for (int i = 0; i < 100; i++)
+       //      asm("nop");
+       //uint32_t test_tpm1 =  TPM1->CNT;
+       //uint32_t test_pit1 = ~PIT->CHANNEL[0].CVAL;
+
+       //uint32_t test_tpm  = test_tpm1 - test_tpm0;
+       //uint32_t test_pit  = test_pit1 - test_pit0;
+       //sirq_printf("pit/tpm: %d - tpm=%08x/%08x=%d pit=%08x/%08x=%d\r\n",
+       //              test_tpm - test_pit,
+       //              test_tpm0, test_tpm1, test_tpm,
+       //              test_pit0, test_pit1, test_pit);
+
+       // Debug output
+       //time_printf("emitting event", when);
+}
+
+void emit_transmit(uint64_t local, uint64_t world)
+{
+       static uint64_t prev = 0;
+
+       // Record how how much time we have to reschedule
+       if (prev && (local-prev) > emit_worst)
+               emit_worst = (local-prev);
+       prev = local;
+
+       // Schedule task if needed
+       if (emit_due && emit_period &&
+           world+emit_slack > emit_due) {
+               emit_schedule(emit_due);
+               emit_due += emit_period;
+       }
+}
+
diff --git a/hw2/main_emit.h b/hw2/main_emit.h
new file mode 100644 (file)
index 0000000..577174a
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef MAIN_EMIT_H
+#define MAIN_EMIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Signal generation init */
+void emit_init(int alt, PinName pin, PinMode mode);
+
+/* Configure GPIO output */
+void emit_enable(uint64_t start, uint64_t period);
+
+/* Queue GPIO signal if due */
+void emit_transmit(uint64_t local, uint64_t world);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/hw2/main_time.c b/hw2/main_time.c
new file mode 100644 (file)
index 0000000..e022c6a
--- /dev/null
@@ -0,0 +1,101 @@
+#include <stdint.h>
+
+#include "serial_irq.h"
+#include "main_time.h"
+
+/*******************
+ * Timer functions *
+ *******************/
+
+uint64_t time_last_local; // timestamp at last time sync
+uint64_t time_last_world; // offset at last time sync
+
+/* Initialization */
+void time_init(void)
+{
+       // nothing for now
+}
+
+/**
+ * Generate time stamp for an async event:
+ *   time:  drift compensated wall-clock time
+ *   stamp: event timestamp from PIT Module
+ */
+uint64_t time_to_world(uint64_t local)
+{
+       uint64_t elapsed = local - time_last_local;
+       return time_last_world + elapsed;
+}
+
+uint64_t time_to_local(uint64_t world)
+{
+       uint64_t elapsed = world - time_last_world;
+       return time_last_local + elapsed;
+}
+
+/**
+ * Synchronize the timer internal state with updates
+ * from an external time sync message.
+ *   local: our internal timestamp for the event
+ *   world: reference timestamp from the other device
+ */
+void time_ext_init(uint64_t local, uint64_t world)
+{
+       sirq_printf("initialize clocks: %d -> %d\r\n",
+                       (int)(local/NSEC_PER_SEC),
+                       (int)(world/NSEC_PER_SEC));
+
+       time_last_local = local;
+       time_last_world = world;
+}
+
+/**
+ * Synchronize the timer internal state with updates
+ * from an external time sync message.
+ *   local: our internal timestamp for the event
+ *   world: reference timestamp from the other device
+ */
+void time_ext_sync(uint64_t local, uint64_t world)
+{
+       uint64_t guess = time_to_world(local);
+
+       time_last_local = local;
+       time_last_world = (guess/2) + (world/2);
+       //time_last_world = (guess * 3 / 4) + (world * 1 / 4);
+       //time_last_world =
+       //      (guess - (        guess / 2)) +
+       //      (world - (world - world / 2));
+       //time_last_world =
+       //      (guess - (guess - guess / 4)) +
+       //      (world - (        world / 4));
+
+       world = time_last_world;
+
+//#ifdef VERBOSE
+#if 1
+       uint64_t error = world > guess ? world - guess :
+                        guess > world ? guess - world : 0;
+       int      ahead = guess > world;
+       sirq_printf("syncing clocks: %6d=%d.%04u -> %d.%04u (err: %s%ld.%09lu)\r\n",
+                       (int)((local / NSEC_PER_SEC)),
+                       (int)((guess / NSEC_PER_SEC)),
+                       (int)((guess % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
+                       (int)((world / NSEC_PER_SEC)),
+                       (int)((world % NSEC_PER_SEC)/(NSEC_PER_SEC/10000)),
+                       ahead ? "-" : " ",
+                       (int32_t )(error / (int64_t)NSEC_PER_SEC),
+                       (uint32_t)(error % (int64_t)NSEC_PER_SEC));
+#endif
+//#endif
+}
+
+void time_printf(const char *label, uint64_t local)
+{
+       uint64_t world = time_to_world(local);
+       sirq_printf("%s -- %d.%09u -> %d.%09u\r\n",
+                       label,
+                       (int)(local / NSEC_PER_SEC),
+                       (int)(local % NSEC_PER_SEC),
+                       (int)(world / NSEC_PER_SEC),
+                       (int)(world % NSEC_PER_SEC));
+}
diff --git a/hw2/main_time.h b/hw2/main_time.h
new file mode 100644 (file)
index 0000000..e0d2733
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef MAIN_TIME_H
+#define MAIN_TIME_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+/* Constants */
+#define NSEC_PER_SEC 1000000000ULL
+
+/* Initialization */
+void time_init(void);
+
+/* Time conversino functions */
+uint64_t time_to_world(uint64_t local);
+uint64_t time_to_local(uint64_t world);
+
+/* External time syncronization */ 
+void time_ext_init(uint64_t local, uint64_t world);
+void time_ext_sync(uint64_t local, uint64_t world);
+
+/* Helper functions */
+void time_printf(const char *label, uint64_t local);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
index aba2af875cb9ac92d1d3250800def469a482257f..8e8b2ee95b2bd38d2a8858dfd50ccd6938e881ab 100644 (file)
@@ -7,7 +7,7 @@ CPPFLAGS =
 LDFLAGS  = -lm
 
 # Common rules
-default: mbed-run
+default: all
 
 all: mbed.elf tester.elf control
 
@@ -19,7 +19,8 @@ dist:
        zip mbed.zip makefile ../common.mk *.{c,cpp,h} */*.{cpp,.h}
 
 # Primary mbed (mbed1/mbed2)
-mbed.elf: main.o serial_irq.o serial_dma.o timer_dma.o messages.o
+mbed.elf: main.o main_time.o main_emit.o main_comm.o \
+       serial_irq.o serial_dma.o timer_dma.o messages.o
 
 mbed-run: mbed.bin control install.sh
        @./install.sh $<
index eeeff80d207f1aa4edc0be56c4e2bfadd3d1c9f1..dd18ed36a8762480364709037268a793af900e93 100644 (file)
@@ -43,7 +43,7 @@ void msg_receive(parser_t *parser, int byte)
                        if (parser->index == (int)sizeof(header_t)+head->length) {
                                handler_t handler = parser->handler[head->msgid];
                                if (handler)
-                                       handler(head->msgid, body);
+                                       handler(head, body);
 
                                parser->index = 0;
                                parser->state = 0;
index 2e84107aee849df9c071657aa05e103727c60520..9f7dd712e9518bd7040635da21af9c5f4ca8de07 100644 (file)
@@ -65,7 +65,7 @@ typedef struct {
  * Message Parser *
  ******************/
 
-typedef void (*handler_t)(int msgid, void *msg);
+typedef void (*handler_t)(header_t *head, void *body);
 
 typedef struct {
        int       index;
index f80572e51fad8956f02879e5728f58d031bd7aab..a5eb78e211f4fc17420f2d4c4c3751cf27e406f5 100644 (file)
@@ -49,6 +49,10 @@ static tdma_t tdma_ports[TDMA_NUM_CHAN];
 /* Global timer initialization */\r
 void tdma_init(void)\r
 {\r
+       static int tdma_init_done = 0;\r
+       if (tdma_init_done)\r
+               return;\r
+\r
        // Enable DMA Cock\r
        SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;\r
        SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK;\r
@@ -73,6 +77,9 @@ void tdma_init(void)
        // Start timers\r
        PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK;\r
        PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;\r
+\r
+       // Done\r
+       tdma_init_done = 1;\r
 }\r
 \r
 /* DMA Functions */\r
@@ -84,6 +91,9 @@ tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode)
 \r
        int irqc = mode == PullUp ? 1 : 2;\r
 \r
+       // Initialize global registers\r
+       tdma_init();\r
+\r
        // Allocate port\r
        tdma_t *port    = &tdma_ports[chan];\r
 \r
index 41370fbe7e5ceb9e257f254b8eb76a10538162f5..cfc174bb58921ccdbccb343801f01c2fb0f76042 100644 (file)
@@ -23,9 +23,6 @@ typedef enum {
 /* Port */
 typedef struct tdma_t tdma_t;
 
-/* Open */
-void tdma_init(void);
-
 /* Open */
 tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode);