From 2682a4a1a463b43e91e1b61344f4d2be5eb13c52 Mon Sep 17 00:00:00 2001 From: Andy Spencer Date: Mon, 10 Mar 2014 13:21:02 +0000 Subject: [PATCH] Add output event and more messages --- hw2/main.cpp | 215 ++++++++++++++++++++++++++++++++++++++++++++----- hw2/messages.h | 18 ++++- 2 files changed, 210 insertions(+), 23 deletions(-) diff --git a/hw2/main.cpp b/hw2/main.cpp index 87bca11..d4c0b04 100644 --- a/hw2/main.cpp +++ b/hw2/main.cpp @@ -98,9 +98,6 @@ void time_ext_init(uint64_t local, uint64_t world) void time_ext_sync(uint64_t local, uint64_t world) { uint64_t guess = time_to_world(local); - uint64_t error = world > guess ? world - guess : - guess > world ? guess - world : 0; - int ahead = guess > world; time_last_local = local; time_last_world = (guess/2) + (world/2); @@ -116,6 +113,9 @@ void time_ext_sync(uint64_t local, uint64_t world) //#ifdef VERBOSE #if 0 + 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)), @@ -150,6 +150,101 @@ void time_printf(const char *label, uint64_t local) (int)(world % NSEC_PER_SEC)); } +/********************* + * Signal generation * + *********************/ + +static uint32_t *emit_pcr = 0; // transmit pin name + +static uint64_t emit_start = 0; // transmit start time +static uint64_t emit_period = 0; // transmit period +static uint64_t emit_due = 0; // next transmit time + +static uint32_t emit_slack = 0; // how far ahead we need to schedule +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_TPM0_MASK; + + SIM->SOPT2 |= SIM_SOPT2_TPMSRC(1); + SIM->SOPT4 |= SIM_SOPT4_TPM1CLKSEL_MASK; + + // Set pin mode + emit_pcr[0] = PORT_PCR_ISF_MASK + | PORT_PCR_MUX(alt) + | mode; + + // Setup Timer/PWM Module + TPM0->SC = TPM_SC_TOF_MASK + | TPM_SC_PS(1); // 24 MHz clock ? + TPM0->CNT = TPM_CNT_COUNT(0); + TPM0->MOD = TPM_MOD_MOD(0xFFFF); + + TPM0->CONTROLS[0].CnSC = TPM_CnSC_CHF_MASK // clear flag + | TPM_CnSC_MSB_MASK // pulse output on match + | TPM_CnSC_MSA_MASK // .. + | TPM_CnSC_ELSA_MASK; // pulse high + + TPM0->CONTROLS[0].CnV = 0xFFFF; // time delay + + TPM0->STATUS = TPM_STATUS_CH0F_MASK + | TPM_STATUS_TOF_MASK; + + TPM0->CONF = TPM_CONF_CSOO_MASK; +} + +void emit_enable(uint64_t start, uint64_t period) +{ + emit_start = start; + emit_period = period; + emit_due = start + period; + + emit_slack = 10000; // tune based on emit_worst + + time_printf("scheuled emit - ", emit_due); +} + +void emit_schedule(uint64_t when) +{ + uint64_t now = tdma_time(); + uint16_t delay = (uint16_t)(when-now); + + // Clear pending flags + //emit_pcr[0] |= PORT_PCR_ISF_MASK + + // Disable timer + TPM0->SC = TPM_SC_TOF_MASK; + + // Set transmit time + TPM0->CNT = TPM_CNT_COUNT(0); + TPM0->CONTROLS[0].CnV = delay; + + // Start the timer + TPM0->SC = TPM_SC_TOF_MASK + | TPM_SC_CMOD(1); +} + +void emit_transmit(void) +{ + static uint64_t prev; + + // Get a fresh timestamp + uint64_t world = tdma_time(); + + // Record how how much time we have to reschedule + if (prev && world - prev > emit_worst) + emit_worst = prev; + + // Schedule task if needed + if (world+emit_slack > emit_due) + emit_schedule(emit_due); +} + /************************ * Serial I/O functions * ************************/ @@ -160,17 +255,43 @@ typedef struct { uint8_t buffer[256]; } parser_t; -const uint64_t serial_sync_delay = NSEC_PER_SEC / 100; // 1hz -static uint64_t serial_sync_due = 0; +static uint32_t serial_device_id = 0; + +const uint64_t serial_sync_delay = NSEC_PER_SEC / 100; // 1hz +static uint64_t serial_sync_due = 0; + +static tdma_t *serial_tdma_rcv = NULL; +static tdma_t *serial_tdma_xmt = NULL; + +static uint64_t serial_prev_local = 0; +static uint64_t serial_prev_seq = 0; + +static uint64_t serial_xmt_local = 0; +static uint64_t serial_xmt_seq = 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); +} -static uint64_t serial_prev_local = 0; -static uint64_t serial_prev_seq = 0; +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; +} -static uint64_t serial_xmt_local = 0; -static uint64_t serial_xmt_seq = 0; +/** + * Output initialization message init message + */ +void serial_send_init(uint16_t device, uint64_t local) +{ +} /** * Output time sync message @@ -236,7 +357,12 @@ void serial_send_sync(sirq_t *port, uint64_t now) */ void serial_send_event(uint16_t event, uint64_t local) { - uint64_t world = time_to_world(local); +// uint64_t world = time_to_world(local); + + // Message data +#if 0 + header_t head; + event_msg_t body; ntime_t time = {}; time.seconds = (uint32_t)(world / NSEC_PER_SEC); @@ -245,7 +371,50 @@ void serial_send_event(uint16_t event, uint64_t local) sirq_printf("event received - %08x:%08x - %u.%09u\r\n", (uint32_t)(local >> 32), (uint32_t)local, time.seconds, time.nanosec); - // todo + + // Transmit sync message + head.header = MSG_HEADER; + head.msgid = MSG_ID_SYNC; + head.length = sizeof(body); + head.cksum = 0; // todo + + body.seq = serial_xmt_seq; + body.time.seconds = world / NSEC_PER_SEC; + body.time.nanosec = world % NSEC_PER_SEC; + + tdma_stop(serial_tdma_rcv); + + test_xmt_enab = 1; + test_xmt_time0 = 0; + test_xmt_time1 = 0; + + tdma_start(serial_tdma_xmt); + sirq_write(port, &head, sizeof(head)); + sirq_write(port, &body, sizeof(body)); + tdma_stop(serial_tdma_xmt); +#endif +} + +/** + * Handle init message + */ +void serial_handle_init(init_msg_t *msg) +{ + 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); + } } /** @@ -266,12 +435,6 @@ void serial_handle_sync(sync_msg_t *msg) uint64_t world = ((uint64_t)msg->time.seconds) * NSEC_PER_SEC + ((uint64_t)msg->time.nanosec); - // Initialize - if (msg->seq == 0) { - uint64_t local = tdma_time(); - time_ext_init(local, world); - } - // Valid times timestamp if (serial_prev_seq == (msg->seq-1)) { uint64_t local = serial_prev_local; @@ -299,6 +462,10 @@ void serial_handle_event(event_msg_t *msg) void serial_deliver(int msgid, void *body) { switch (msgid) { + case MSG_ID_INIT: + //sirq_printf("received init msg\r\n"); + serial_handle_init((init_msg_t*)body); + break; case MSG_ID_SYNC: //sirq_printf("received sync msg\r\n"); serial_handle_sync((sync_msg_t*)body); @@ -338,7 +505,7 @@ void serial_receive(parser_t *parser, int byte) case 1: // Header if (parser->index == sizeof(header_t)) { if (head->length <= max_length && - head->msgid <= MSG_MAXID) { + head->msgid <= MSG_MAX_ID) { parser->state = 2; } else { parser->index = 0; @@ -433,6 +600,11 @@ void task_leds(uint64_t local, uint64_t world) which ^= 1; } +void task_emit(uint64_t local, uint64_t world) +{ + emit_transmit(); +} + void task_debug(uint64_t local, uint64_t world) { //tdma_debug(tdma_rcv); @@ -464,8 +636,9 @@ static struct { uint64_t due; } tasks[] = { { task_serial, 0 }, // always - { task_events, 1000000000 }, // always + { task_events, 1000000000 }, // always -- testing { task_sync, 0 }, // always + { task_emit, 0 }, // always { task_leds, 100000000 }, // 10hz { task_debug, 1000000000 }, // 1hz }; diff --git a/hw2/messages.h b/hw2/messages.h index 20887cc..e18166b 100644 --- a/hw2/messages.h +++ b/hw2/messages.h @@ -4,14 +4,20 @@ #include -#define MSG_HEADER 0x1234 -#define MSG_MAXID 2 +#define MSG_HEADER 0x1234 + +#define MSG_VALID_DEVICE 0x0001 +#define MSG_VALID_START 0x0002 +#define MSG_VALID_PERIOD 0x0004 +#define MSG_VALID_WORLD 0x0008 #pragma pack(1) typedef enum { + MSG_ID_INIT, // Device initialization MSG_ID_SYNC, // Time synchronization MSG_ID_EVENT, // Event occurred + MSG_MAX_ID, // Maximum message ID } msgid_t; typedef struct { @@ -26,6 +32,14 @@ typedef struct { uint16_t cksum; // Body checksum } header_t; +typedef struct { + uint16_t valid; // Message valid bits + uint16_t device; // Device ID to use + ntime_t start; // Transmit start time + ntime_t period; // Transmit period + ntime_t world; // World time (since 1970) +} init_msg_t; + typedef struct { uint32_t seq; // Current sequence counter ntime_t time; // Time of previous message -- 2.43.2