1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "sync_clock.h"
18
19#include <asm/byteorder.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <inttypes.h>
23#include <linux/usbdevice_fs.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <sys/inotify.h>
28#include <sys/ioctl.h>
29#include <sys/time.h>
30#include <time.h>
31#include <unistd.h>
32
33
34#ifdef __ANDROID__
35    #include <android/log.h>
36    #define  LOGD(...)  __android_log_print(ANDROID_LOG_VERBOSE, "ClockSyncNative", __VA_ARGS__)
37#else
38    #define  LOGD(...)  printf(__VA_ARGS__)
39#endif
40
41
42// How many times to repeat the 1..9 digit sequence it's a tradeoff between
43// precision and how long it takes.
44// TODO: investigate better combination of constants for repeats and wait times
45const int kSyncRepeats = 7;
46const int kMillion = 1000000;
47
48
49/**
50uptimeMicros() - returns microseconds elapsed since boot.
51Same time as Android's SystemClock.uptimeMillis() but in microseconds.
52
53Adapted from Android:
54platform/system/core/libutils/Timers.cpp
55platform/system/core/include/utils/Timers.h
56
57See:
58http://developer.android.com/reference/android/os/SystemClock.html
59https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
60*/
61int64_t uptimeMicros() {
62    struct timespec ts;
63    clock_gettime(CLOCK_MONOTONIC, &ts);
64    return ((int64_t)ts.tv_sec) * kMillion + ts.tv_nsec / 1000;
65}
66
67
68// Sleeps us microseconds
69int microsleep(int us) {
70    struct timespec ts;
71    ts.tv_sec = us / kMillion;
72    us %= kMillion;
73    ts.tv_nsec = us*1000;
74    return nanosleep(&ts, NULL);
75}
76
77
78// *********************** Generic USB functions *******************************
79
80static int send_char_async(int fd, int endpoint, char msg, char * label) {
81    // TODO: Do we really need a buffer longer than 1 char here?
82    char buffer[256] = {0};
83    buffer[0] = msg;
84    int length = 1;
85
86    // TODO: free() the memory used for URBs.
87    // Circular buffer of URBs? Cleanup at the end of clock sync?
88    // Several may be used simultaneously, no signal when done.
89    struct usbdevfs_urb *urb = calloc(1, sizeof(struct usbdevfs_urb));
90    memset(urb, 0, sizeof(struct usbdevfs_urb));
91
92    int res;
93    urb->status = -1;
94    urb->buffer = buffer;
95    urb->buffer_length = length;
96    urb->endpoint = endpoint;
97    urb->type = USBDEVFS_URB_TYPE_BULK;
98    urb->usercontext = label; // This is hackish
99    do {
100        res = ioctl(fd, USBDEVFS_SUBMITURB, urb);
101    } while((res < 0) && (errno == EINTR));
102    return res;
103}
104
105
106// Send or read using USBDEVFS_BULK. Allows to set a timeout.
107static int bulk_talk(int fd, int endpoint, char * buffer, int length) {
108    // Set some reasonable timeout. 20ms is plenty time for most transfers but
109    // short enough to fail quickly if all transfers and retries fail with
110    // timeout.
111    const int kTimeoutMs = 20;
112    struct usbdevfs_bulktransfer ctrl;
113    // TODO: need to limit request size to avoid EINVAL
114
115    ctrl.ep = endpoint;
116    ctrl.len = length;
117    ctrl.data = buffer;
118    ctrl.timeout = kTimeoutMs;
119    int ret = ioctl(fd, USBDEVFS_BULK, &ctrl);
120    return ret;
121}
122
123
124/*******************************************************************************
125* Clock sync specific stuff below.
126* Most data is stored in the clock_connection struct variable.
127*/
128
129// Send a single character to the remote in a blocking mode
130int send_cmd(struct clock_connection *clk, char cmd) {
131    return bulk_talk(clk->fd, clk->endpoint_out, &cmd, 1);
132}
133
134// Schedule a single character to be sent to the remote - async.
135int send_async(struct clock_connection *clk, char cmd) {
136    return send_char_async(clk->fd, clk->endpoint_out, cmd, NULL);
137}
138
139
140int bulk_read(struct clock_connection *clk) {
141    memset(clk->buffer, 0, sizeof(clk->buffer));
142    int ret = bulk_talk(clk->fd, clk->endpoint_in, clk->buffer, sizeof(clk->buffer));
143    return ret;
144}
145
146// microseconds elapsed since clk->t_base
147int micros(struct clock_connection *clk) {
148    return uptimeMicros() - clk->t_base;
149}
150
151// Clear all incoming data that's already waiting somewhere in kernel buffers
152// and discard it.
153void flush_incoming(struct clock_connection *clk) {
154    // When bulk_read times out errno = ETIMEDOUT=110, retval =-1
155    // should we check for this?
156
157    while(bulk_read(clk) >= 0) {
158        // TODO: fail nicely if waiting too long to avoid hangs
159    }
160}
161
162// Ask the remote to send its timestamps
163// for the digits previously sent to it.
164void read_remote_timestamps(struct clock_connection *clk, int * times_remote) {
165    int i;
166    int t_remote;
167    // Go over the digits [1, 2 ... 9]
168    for (i = 0; i < 9; i++) {
169        char digit = i + '1';
170        send_cmd(clk, CMD_SYNC_READOUT);
171        bulk_read(clk);
172        if (clk->buffer[0] != digit) {
173            LOGD("Error, bad reply for R%d: %s", i+1, clk->buffer);
174        }
175        // The reply string looks like digit + space + timestamp
176        // Offset by 2 to ignore the digit and the space
177        t_remote = atoi(clk->buffer + 2);
178        times_remote[i] = t_remote;
179    }
180}
181
182
183// Preliminary rough sync with a single message - CMD_SYNC_ZERO = 'Z'.
184// This is not strictly necessary but greatly simplifies debugging
185// by removing the need to look at very long numbers.
186void zero_remote(struct clock_connection *clk) {
187    flush_incoming(clk);
188    clk->t_base = uptimeMicros();
189    send_cmd(clk, CMD_SYNC_ZERO);
190    bulk_read(clk); // TODO, make sure we got 'z'
191    clk->maxE = micros(clk);
192    clk->minE = 0;
193
194    LOGD("Sent a 'Z', reply '%c' in %d us\n", clk->buffer[0], clk->maxE);
195}
196
197
198
199void improve_minE(struct clock_connection *clk) {
200    int times_local_sent[9] = {0};
201    int times_remote_received[9] = {0};
202
203    // Set sleep time as 1/kSleepTimeDivider of the current bounds interval,
204    // but never less or more than k(Min/Max)SleepUs. All pretty random
205    // numbers that could use some tuning and may behave differently on
206    // different devices.
207    const int kMaxSleepUs = 700;
208    const int kMinSleepUs = 70;
209    const int kSleepTimeDivider = 10;
210    int minE = clk->minE;
211    int sleep_time = (clk->maxE - minE) / kSleepTimeDivider;
212    if(sleep_time > kMaxSleepUs) sleep_time = kMaxSleepUs;
213    if(sleep_time < kMinSleepUs) sleep_time = kMinSleepUs;
214
215    flush_incoming(clk);
216    // Send digits to remote side
217    int i;
218    for (i = 0; i < 9; i++) {
219        char c = i + '1';
220        times_local_sent[i] = micros(clk);
221        send_async(clk, c);
222        microsleep(sleep_time);
223    }
224
225    // Read out receive times from the other side
226    read_remote_timestamps(clk, times_remote_received);
227
228    // Do stats
229    for (i = 0; i < 9; i++) {
230        int tls = times_local_sent[i];
231        int trr = times_remote_received[i];
232
233        int dt;
234
235        // Look at outgoing digits
236        dt = tls - trr;
237        if (tls != 0 && trr != 0 && dt > minE) {
238            minE = dt;
239        }
240
241    }
242
243    clk->minE = minE;
244
245    LOGD("E is between %d and %d us, sleep_time=%d\n", clk->minE, clk->maxE, sleep_time);
246}
247
248void improve_maxE(struct clock_connection *clk) {
249    int times_remote_sent[9] = {0};
250    int times_local_received[9] = {0};
251
252    // Tell the remote to send us digits with delays
253    // TODO: try tuning / configuring the delay time on remote side
254    send_async(clk, CMD_SYNC_SEND);
255
256    // Read and timestamp the incoming digits, they may arrive out of order.
257    // TODO: Try he same with USBDEVFS_REAPURB, it might be faster
258    int i;
259    for (i = 0; i < 9; ++i) {
260        int retval = bulk_read(clk);
261        // TODO: deal with retval = (bytes returned) > 1. shouldn't happen.
262        // Can it happen on some devices?
263        int t_local = micros(clk);
264        int digit = atoi(clk->buffer);
265        if (digit <=0 || digit > 9) {
266            LOGD("Error, bad incoming digit: %s\n", clk->buffer);
267        }
268        times_local_received[digit-1] = t_local;
269    }
270
271    // Flush whatever came after the digits. As of this writing, it's usually
272    // a single linefeed character.
273    flush_incoming(clk);
274    // Read out the remote timestamps of when the digits were sent
275    read_remote_timestamps(clk, times_remote_sent);
276
277    // Do stats
278    int maxE = clk->maxE;
279    for (i = 0; i < 9; i++) {
280        int trs = times_remote_sent[i];
281        int tlr = times_local_received[i];
282        int dt = tlr - trs;
283        if (tlr != 0 && trs != 0 && dt < maxE) {
284            maxE = dt;
285        }
286    }
287
288    clk->maxE = maxE;
289
290    LOGD("E is between %d and %d us\n", clk->minE, clk->maxE);
291}
292
293
294void improve_bounds(struct clock_connection *clk) {
295    improve_minE(clk);
296    improve_maxE(clk);
297}
298
299// get minE and maxE again after some time to check for clock drift
300void update_bounds(struct clock_connection *clk) {
301    // Reset the bounds to some unrealistically large numbers
302    int i;
303    clk->minE = -1e7;
304    clk->maxE =  1e7;
305    // Talk to remote to get bounds on minE and maxE
306    for (i=0; i < kSyncRepeats; i++) {
307        improve_bounds(clk);
308    }
309}
310
311void sync_clocks(struct clock_connection *clk) {
312    // Send CMD_SYNC_ZERO to remote for rough initial sync
313    zero_remote(clk);
314
315    int rep;
316    for (rep=0; rep < kSyncRepeats; rep++) {
317        improve_bounds(clk);
318    }
319
320    // Shift the base time to set minE = 0
321    clk->t_base += clk->minE;
322    clk->maxE -= clk->minE;
323    clk->minE = 0;
324    LOGD("Base time shifted for zero minE\n");
325}
326
327
328