How it works
T0 = current_time() Tell the remote to zero clock. Wait for confirmation from remote maxE = current_time() - T0 All further local time is measured from T0
After this step we are sure that the remote clock lags behind the local clock by some value E. And we know that E >= 0 because remote was zeroed after we zeroed the local time (recored T0). And also E<= maxE. So 0 = minE < E < maxE.
minE
Send some messages from local to remote, note the time right before sending the message (denote it as t_local
) and have the remote reply with his timestamps of when it received the messages according to his clock that lags by unknown positive value E
behind the local clock, denote it by t_remote
.
t_remote = t_local - E + travel_time E = t_local - t_remote + travel_time > t_local - t_remote since travel_time > 0 E > t_local - t_remote set minE to max(minE, t_local - t_remote) Repeat
We need to first send a bunch of messages with some random small delays, and only after that get the remote timestamps for all of them. This helps deal with unwanted buffering and delay added by the kernel of hardware in the outgoing direction.
maxE
Same idea, but in the opposite direction. Remote device sends us messages and then the timestamps according to his clock of when they were sent. We record the local timestamps when we receive them.
t_local = t_remote + E + travel_time E = t_local - t_remote - travel time < t_local - t_remote set maxE = min(maxE, t_local - t_remote) Repeat
NTP measures the mean travel_time (latency) and assumes it to be symmetric - the same in both directions. If the symmetry assumption is broken, there is no way to detect this. Both, systematic asymmetry in latency and clock difference would result in exactly the same observations - explanation here.
In our case the latency can be relatively small compared to network, but is likely to be asymmetric due to the asymmetric nature of USB. The algorithm described above guarantees that the clock difference is within the measured bounds minE < E < maxE
, though the resulting interval deltaE = maxE - minE
can be fairly large compared to synchronization accuracy of NTP on a network with good latency symmetry.
Observed values for deltaE
General
USB communication
// Async way ioctl(fd, USBDEVFS_SUBMITURB, urb); // followed by ioctl(fd, USBDEVFS_REAPURB, &urb); // Blocks until there is a URB to read. // Sync way struct usbdevfs_bulktransfer ctrl; ctrl.ep = endpoint; ctrl.len = length; ctrl.data = buffer; ctrl.timeout = timeout; // [milliseconds] Will timeout if there is nothing to read int ret = ioctl(fd, USBDEVFS_BULK, &ctrl);