/**
*
* Funf: Open Sensing Framework
* Copyright (C) 2010-2011 Nadav Aharony, Wei Pan, Alex Pentland.
* Acknowledgments: Alan Gardner
* Contact: nadav@media.mit.edu
*
* This file is part of Funf.
*
* Funf is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* Funf is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Funf. If not, see <http://www.gnu.org/licenses/>.
*
*/
package edu.mit.media.funf.probe.builtin;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.UnknownHostException;
import android.util.Log;
import com.google.gson.JsonObject;
import edu.mit.media.funf.config.Configurable;
import edu.mit.media.funf.probe.Probe.Base;
import edu.mit.media.funf.probe.builtin.ProbeKeys.TimeOffsetKeys;
import edu.mit.media.funf.time.NtpMessage;
import edu.mit.media.funf.time.TimeUtil;
import edu.mit.media.funf.util.LogUtil;
/**
* Broadcasts the current system time offset from time on major NTP servers in seconds,
* precise to the Microsecond (though not necessarily that accurate).
* @author alangardner
*
*/
public class TimeOffsetProbe extends Base implements TimeOffsetKeys {
private static final BigDecimal SECONDS_1900_TO_1970 = new BigDecimal(2208988800L);
@Configurable
private String host = "2.north-america.pool.ntp.org";
@Configurable
private int port = 123;
@Configurable
private BigDecimal timeout = BigDecimal.TEN;
@Override
protected void onStart() {
super.onStart();
try {
DatagramSocket socket = new DatagramSocket();
socket.setSoTimeout((int)TimeUtil.secondsToMillis(timeout == null ? BigDecimal.TEN : timeout));
InetAddress address = InetAddress.getByName(host);
byte[] buf = new NtpMessage().toByteArray();
DatagramPacket sendPacket = new DatagramPacket(buf, buf.length, address, port);
// Get timestamp right before sending
BigDecimal timestamp = TimeUtil.getTimestamp();
NtpMessage.encodeTimestamp(sendPacket.getData(), 40, SECONDS_1900_TO_1970.add(timestamp).doubleValue());
socket.send(sendPacket);
DatagramPacket receivePacket = new DatagramPacket(buf, buf.length);
socket.receive(receivePacket);
// Immediately record the incoming timestamp
double destinationTimestamp = SECONDS_1900_TO_1970.add(TimeUtil.getTimestamp()).doubleValue();
NtpMessage msg = new NtpMessage(receivePacket.getData());
// Corrected, according to RFC2030 errata
double roundTripDelay = (destinationTimestamp-msg.originateTimestamp) -
(msg.transmitTimestamp-msg.receiveTimestamp);
double localClockOffset =
((msg.receiveTimestamp - msg.originateTimestamp) +
(msg.transmitTimestamp - destinationTimestamp)) / 2;
socket.close();
JsonObject data = new JsonObject();
data.addProperty(TIMESTAMP, timestamp);
data.addProperty(ROUND_TRIP_DELAY, TimeUtil.roundToMilliPrecision(new BigDecimal(roundTripDelay)));
data.addProperty(LOCAL_TIME_OFFSET, TimeUtil.roundToMilliPrecision(new BigDecimal(localClockOffset)));
sendData(data);
} catch (UnknownHostException e) {
Log.e(LogUtil.TAG, "TimeOffsetProbe: Unknown host", e);
} catch (IOException e) {
Log.e(LogUtil.TAG, "TimeOffsetProbe: IOError", e);
}
stop();
}
}