• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
45 const int kSyncRepeats = 7;
46 const int kMillion = 1000000;
47 
48 
49 /**
50 uptimeMicros() - returns microseconds elapsed since boot.
51 Same time as Android's SystemClock.uptimeMillis() but in microseconds.
52 
53 Adapted from Android:
54 platform/system/core/libutils/Timers.cpp
55 platform/system/core/include/utils/Timers.h
56 
57 See:
58 http://developer.android.com/reference/android/os/SystemClock.html
59 https://android.googlesource.com/platform/system/core/+/master/libutils/Timers.cpp
60 */
uptimeMicros()61 int64_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
microsleep(int us)69 int 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 
send_char_async(int fd,int endpoint,char msg,char * label)80 static 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.
bulk_talk(int fd,int endpoint,char * buffer,int length)107 static 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
send_cmd(struct clock_connection * clk,char cmd)130 int 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.
send_async(struct clock_connection * clk,char cmd)135 int send_async(struct clock_connection *clk, char cmd) {
136     return send_char_async(clk->fd, clk->endpoint_out, cmd, NULL);
137 }
138 
139 
bulk_read(struct clock_connection * clk)140 int 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
micros(struct clock_connection * clk)147 int 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.
flush_incoming(struct clock_connection * clk)153 void 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.
read_remote_timestamps(struct clock_connection * clk,int * times_remote)164 void 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.
zero_remote(struct clock_connection * clk)186 void 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 
improve_minE(struct clock_connection * clk)199 void 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 
improve_maxE(struct clock_connection * clk)248 void 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 
improve_bounds(struct clock_connection * clk)294 void 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
update_bounds(struct clock_connection * clk)300 void 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 
sync_clocks(struct clock_connection * clk)311 void 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