5 #include "serial_irq.h"
12 * Communcation overview:
15 * bbb --init1--> mbed1
16 * bbb --init2--> mbed1 --init2---> mbed2
19 * bbb mbed1 ---sync---> mbed2
20 * bbb mbed1 <--sync---- mbed2
23 * bbb <--event1-- mbed1 mbed2
24 * bbb <--event2-- mbed1 <--event2-- mbed2
27 * Each mbed is initialized by the BBB by receiving an initialization
28 * message. The Device ID must be non-zero, and is saved for future
29 * messages. If the device is already initialized and a recevied Device ID
30 * does not match the configured Device ID, the messages is relayed to the
34 * When receiving events, an event message is sent from the mbed to the
35 * bbb. If the mbed receiving the event is not Device 1, the message is
36 * sent to mbed1 instead of the bbb.
39 * 1. Init messages may be received from the host instead of the bbb
40 * 2. Event messages may be sent to the host in addition to the bbb
43 /***************************
44 * Communication functions *
45 ***************************/
47 static int comm_device_id = 0;
48 static int comm_relay_mode = 0;
50 const uint64_t comm_sync_delay = NSEC_PER_SEC / 100;
51 static uint64_t comm_sync_due = 0;
53 static sirq_t *comm_sirq_dbg = 0;
54 static sirq_t *comm_sirq_bbb = 0;
55 static sirq_t *comm_sirq_mbed = 0;
57 static tdma_t *comm_tdma_rcv = 0;
58 static tdma_t *comm_tdma_xmt = 0;
61 * Convert world to local time
63 static uint64_t comm_read_time(ntime_t time)
65 return ((uint64_t)time.seconds) * NSEC_PER_SEC
66 + ((uint64_t)time.nanosec);
69 static ntime_t comm_write_time(uint64_t time)
72 buf.seconds = time / NSEC_PER_SEC;
73 buf.nanosec = time % NSEC_PER_SEC;
77 static int comm_time_stamp(tdma_t *port, uint64_t *local, uint64_t *world,
80 int valid = tdma_stamp(port, local);
81 *world = time_to_world(*local);
84 sirq_printf("%s -- missing\r\n", msg);
86 // time_printf(msg, current);
94 void comm_init(sirq_t *dbg, sirq_t *bbb, sirq_t *mbed,
95 tdma_t *rcv, tdma_t *xmt)
99 comm_sirq_mbed = mbed;
106 * Output time sync message
108 void comm_send_sync(uint64_t local)
110 if (comm_sync_due == 0 || local < comm_sync_due)
118 head.header = MSG_HEADER;
119 head.msgid = MSG_ID_SYNC;
120 head.length = sizeof(body);
121 head.cksum = 0; // todo
123 sirq_write(comm_sirq_mbed, &head, sizeof(head));
125 // Capture transmit time
126 tdma_stop(comm_tdma_rcv, 0);
127 tdma_start(comm_tdma_xmt);
129 sirq_transmit(comm_sirq_mbed);
131 tdma_stop(comm_tdma_xmt, 100);
132 tdma_start(comm_tdma_rcv);
134 // Save transmit time
135 uint64_t xmt_local = 0, xmt_world = 0;
136 comm_time_stamp(comm_tdma_xmt, &xmt_local, &xmt_world,
137 "sync time transmit");
140 //sirq_printf("sync time transmit\r\n");
141 //time_printf(" local", xmt_local);
142 //time_printf(" world", xmt_world);
144 // Write body with updated time and send
145 body.time = comm_write_time(xmt_world);
147 sirq_write(comm_sirq_mbed, &body, sizeof(body));
149 sirq_transmit(comm_sirq_mbed);
151 // Queue next transmit time
156 * Output external event received message
157 * event: id of the received event
158 * time: compensated timestamp of the event
160 void comm_send_event(uint16_t event, uint64_t local)
162 //time_printf("event received", local);
165 uint64_t world = time_to_world(local);
166 ntime_t ltime = comm_write_time(local);
167 ntime_t wtime = comm_write_time(world);
171 event_msg_t body = {};
173 // Transmit sync message
174 head.header = MSG_HEADER;
175 head.msgid = MSG_ID_EVENT;
176 head.length = sizeof(body);
177 head.cksum = 0; // todo
179 body.device = comm_device_id;
184 // Transmit message to BBB
185 if (comm_device_id == 1) {
186 sirq_write(comm_sirq_bbb, &head, sizeof(head));
187 sirq_write(comm_sirq_bbb, &body, sizeof(body));
188 } else if (comm_device_id > 1) {
189 sirq_write(comm_sirq_mbed, &head, sizeof(head));
190 sirq_write(comm_sirq_mbed, &body, sizeof(body));
192 sirq_printf("no device id, skipping event\r\n");
197 * Handle init message
199 void comm_handle_init(header_t *head, init_msg_t *body)
201 // Relay initialization from bbb to mbed
202 if (comm_device_id && body->device != comm_device_id) {
203 //sirq_printf("relaying init\r\n");
205 sirq_write(comm_sirq_mbed, head, sizeof(*head));
206 sirq_write(comm_sirq_mbed, body, sizeof(*body));
208 // Normally we transmit during the time sync but
209 // if we haven't started syncing yet, we need to
210 // push out the message now.
212 sirq_transmit(comm_sirq_mbed);
217 sirq_printf("initialize: %s %s %s %s %s\r\n",
218 body->control & MSG_CTL_VALID_DEVICE ? "DEV" : "dev",
219 body->control & MSG_CTL_VALID_START ? "START" : "start",
220 body->control & MSG_CTL_VALID_PERIOD ? "PERIOD" : "period",
221 body->control & MSG_CTL_VALID_WORLD ? "WORLD" : "world",
222 body->control & MSG_CTL_VALID_SYNC ? "SYNC" : "sync");
223 sirq_printf(" dev -- %d\r\n", body->device);
224 time_printf(" start ", comm_read_time(body->start));
225 time_printf(" period", comm_read_time(body->period));
226 time_printf(" world ", comm_read_time(body->world));
228 // Validate message parts and initialize
229 if (body->control & MSG_CTL_VALID_DEVICE)
230 comm_device_id = body->device;
232 if (body->control & MSG_CTL_VALID_START ||
233 body->control & MSG_CTL_VALID_PERIOD) {
234 uint64_t start = comm_read_time(body->start);
235 uint64_t period = comm_read_time(body->period);
236 emit_enable(start, period);
239 if (body->control & MSG_CTL_VALID_WORLD) {
240 uint64_t world = comm_read_time(body->world);
241 uint64_t local = tdma_time();
242 time_ext_init(local, world);
245 if (body->control & MSG_CTL_RELAY_MODE)
250 if (body->control & MSG_CTL_VALID_SYNC)
251 comm_sync_due = tdma_time() + comm_sync_delay;
255 * Handle sync message
257 void comm_handle_sync(header_t *head, sync_msg_t *body)
259 // Read receive timestamp
260 uint64_t local = 0, world = 0;
261 comm_time_stamp(comm_tdma_rcv, &local, &world,
262 "sync time receive ");
263 tdma_stop(comm_tdma_rcv, 0);
265 // Lookup reference time from message
266 uint64_t reference = comm_read_time(body->time);
269 //sirq_printf("sync time receive\r\n");
270 //time_printf(" local", local);
271 //time_printf(" world", world);
272 //time_printf(" ref ", reference);
274 // Synchronize the clocks
275 time_ext_sync(local, reference);
277 // Queue transmit to other board
278 comm_sync_due = tdma_time() + comm_sync_delay;
282 * Handle event message
284 void comm_handle_event(header_t *head, event_msg_t *body)
286 // Relay events from other mbeds
287 sirq_write(comm_sirq_bbb, head, sizeof(*head));
288 sirq_write(comm_sirq_bbb, body, sizeof(*body));