Back to project page senhancelib.
The source code is released under:
GNU Lesser General Public License
If you think the Android project senhancelib listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package de.uos.nbp.senhance.datasource; /* ww w .ja v a2s. c o m*/ import java.util.Date; import java.util.UUID; import de.uos.nbp.senhance.bluetooth.PacketConnection.Packet; /** * This is the interface for receiving packets that * conform to the Senhance control protocol. * * This <em>should</em> be the only place one needs to * reference when implementing the Senhance control protocol. * * At the moment, this protocol is rather simple, and only the * heartFelt ExperimentComputer DataSource supports it. It is also heavily * skewed to the needs of the heartFelt application, it should perhaps * be in that project, but it could be expanded and made more general. * * The protocol allows a connected device to: * <ul> * <li>switch between real and dummy DataSource(s) * <li>write strings to the application's DataLogger * <li>retrieve the mean baseline of the primary DataSource * <li>set the baseline of the primary DataSource (this only has * meaning for dummy DataSources) * <li>initiate and end a transient response in the dummy DataSource * </ul> * 'Baseline' is, for the currently implemented DataSources, RR interval. * * NB: The event log strings are restricted to ASCII because the DataLogger * (SDLogger) uses a simplification of String.getBytes() which does not support * anything but ASCII characters. The simplified method is used for efficiency - * necessary because otherwise converting strings is a severe bottle-neck. * * @author rmuil@UoS.de */ public interface ControlSource extends DataSource { /** UUID generated by rmuil on 2011/11/25 on saturn.nbp.uos.de with uuidgen */ public static final UUID AndroidControlUUID = UUID.fromString("0d42124d-a18b-4269-a2cc-bf0e93a77bfd"); /** * Possible Control Commands. */ enum Command { /** Ping, used to measure latency */ Ping(0), /** Switch current DataSink(s) to real DataSource(s) and enable. */ OutputReal(1), /** Switch current DataSink(s) to dummy DataSource(s) and enable. */ OutputDummy(2), /** Write an ASCII string to the EventLogger */ EventLog(3), /** Retrieve current baseline value from primary data source */ GetBaseline(4), /** Set baseline value of secondary data source */ SetBaseline(5), /** Retrieve current value from primary data source */ GetCurrentValue(6), /** Disable current DataSink(s) */ OutputDisable(7), /** Enable current DataSink(s) */ OutputEnable(8), /** Start an artificial transient response in the dummy DataSource. */ StartTransient(9), /** End an artificial transient response in the dummy DataSource. */ EndTransient(10), /** Gracefully and deliberately end connection */ Disconnect(11), Unknown(-1); private final int id; Command(int id) { this.id = id; } public int getValue() { return id; } public static Command byValue(int id) { for (int idx = 0; idx < values().length; idx++) { if (values()[idx].getValue() == id) return values()[idx]; } return Unknown; } } /** * Possible responses from the Android back to * the ControlSource device. */ enum Response { /** Acknowledged. */ ACK(1), /** Not acknowledged. */ NACK(2), /** Integer value */ IntValue(3), Unknown(-1); private final int id; Response(int id) { this.id = id; } public int getValue() { return id; } public static Response byValue(int id) { for (int idx = 0; idx < values().length; idx++) { if (values()[idx].getValue() == id) return values()[idx]; } return Unknown; } } /** * This is the definition of the generic Control Packet. * * The packet format that will actually get sent over bluetooth is: * <ul> * <li>1 byte, start byte (discarded on reception) * <li>2 bytes, short unsigned integer, command * <li>8 bytes, signed long integer, timestamp * <li>... payload * <li>1 byte, end byte (discarded on reception) * </ul> * The byte sizes given exclude escape characters that may be needed, and are thus * minimum. Maximum possible is twice the stated number of bytes, although this will * practically never happen. * * The payloads are: * <ol> * <li><b>Ping</b>: none * <li><b>OutputReal</b>: none * <li><b>OutputDummy</b>: none * <li><b>EventLog</b>: an ASCII string to be written to the event log. * <li><b>GetBaseline</b>: * <ul> * <li>4 bytes, signed integer, <em>(not yet implemented)</em> the * deviceID of the source * from which to retrieve the baseline <em>(currently the primary * source is always used)</em> * </ul> * <li><b>SetBaseline</b>: * <ul> * <li>4 bytes, signed integer, <em>(not yet implemented)</em> the * deviceID of the source whose baseline is to be set * <em>(currently the secondary source is always used)</em> * <li>4 bytes, signed integer, the baseline value. * </ul> * <li><b>GetCurrentValue</b>: * <ul> * <li>4 bytes, signed integer, <em>(not yet implemented)</em> the * deviceID of the source from which to retrieve the current value * <em>(currently the primary source is always used)</em> * <li>4 bytes, signed integer, the current value. * </ul> * <li><b>OutputDisable</b>: none * <li><b>OutputEnable</b>: none * <li><b>StartTransient</b>: * <ul> * <li>2 bytes, short signed integer, UAmp - the amplitude of the first * component of the transient response, in BPM (offset from baseline). * <li>2 bytes, short signed integer, VAmp - the amplitude of the second * component of the transient response, in BPM (offset from baseline). * </ul> * <li><b>EndTransient</b>: none * <li><b>Disconnect</b>: none * </ol> * * TODO: allow arbitrary configuration (perhaps through use of strings, like * Bundle implementation) for such things as DummySourceThread's * {@value transientULength} parameter. * * @author rmuil@UoS.de */ public class ControlPacket extends Packet { /** header is command and timestamp */ public static final int HdrSize = 10; public static final int MaxEventLogSize = 200; /** payload is variable */ public static final int MaxPayloadSize = MaxEventLogSize; /** * Maximum size of the packet data after stripping * of start and end bytes and after escaping. */ public static final int MaxPacketSize = HdrSize + MaxPayloadSize; /** * This is an index into the received data, after stripping * of start and end bytes and after escaping. */ public static final int PayloadStart = HdrSize; public static final int DevIDPos = PayloadStart; public static final int ValuePos = DevIDPos+4; public static final int UAmpPos = PayloadStart; public static final int VAmpPos = UAmpPos+2; public ControlPacket() { super(MaxPacketSize); } /** * This simply wraps the {@link Packet} in * a ControlPacket. * * @param pkt */ public ControlPacket(Packet pkt) { super(pkt); } /** * @hide * @return command */ public Command getCommand () { return Command.byValue(this.getUShort(0)); } /** * Returns the timestamp that was written into the packet by the * source. This is distinct from start and end times which are the times * at <em>reception</em> on the destination system. * @return signed long, milliseconds past Unix epoch */ public long getTimestamp() { return this.getLong(2); } public int getDevID() { return this.getInt(DevIDPos); } public int getIntValue() { return this.getInt(ValuePos); } public String toString() { StringBuilder sb = new StringBuilder(getCommand().toString()); Date dt = new Date(getTimestamp()); sb.append('@').append(dt.toString()); return sb.toString(); } } /** * This is the definition of the generic response Packet, sent * from Android back to control source. * * The packet format that will actually get sent over bluetooth is: * <ul> * <li>1 byte, start byte (discarded on reception) * <li>2 bytes, short unsigned integer, response * <li>... payload * <li>1 byte, end byte (discarded on reception) * </ul> * * The payloads are: * <ol> * <li><b>ACK</b>: none * <li><b>NACK</b>: none * <li><b>IntValue</b>: * <ul> * <li>4 bytes, signed integer, the deviceID of the source * <li>4 bytes, signed integer, the requested value (e.g. RR value) * </ul> * </ol> * * @author rmuil@UoS.de */ public class ResponsePacket extends Packet { public static final int HdrSize = 2; public static final int PayloadStart = HdrSize; public static final int IntValueDevIDPos = PayloadStart; public static final int IntValuePos = IntValueDevIDPos+4; public static final int PayloadSizeIntValue = 8; public static final int MaxPayloadSize = PayloadSizeIntValue; /** * Maximum size of data of the packet, without start * and end bytes or escaping. */ public static final int MaxPacketSize = HdrSize + MaxPayloadSize; public ResponsePacket() { super(MaxPacketSize); } public ResponsePacket (Response response) { this(); this.setResponse(response); } public void setResponse(Response response) { this.putUShort(response.getValue(), 0); } public void setIntValue(int value) { this.putInt(value, IntValuePos); } public void setIntValueDevID(int devID) { this.putInt(devID, IntValueDevIDPos); } /** The primary information in the packet, its response. */ public Response getResponse() { return Response.byValue(this.getUShort(0)); } public String toString() { StringBuilder sb = new StringBuilder(getResponse().toString()); sb.append('[').append(super.toString()).append(']'); return sb.toString(); } } void send(ResponsePacket pkt); }