Home | History | Annotate | Download | only in jni
      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 */
     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
     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 
     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.
    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
    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.
    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 
    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
    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.
    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.
    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.
    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 
    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 
    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 
    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
    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 
    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