Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.eveningoutpost.dexdrip.Models;

/**
* Created by Radu Iliescu on 25.02.2015.
*/
public class DexdripPacket {
public static final int PACKET_DATA = 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.activeandroid.annotation.Column;
import com.activeandroid.annotation.Table;
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.utils.PacketUtil;

import java.util.Date;
import java.util.UUID;
Expand Down Expand Up @@ -78,6 +79,48 @@ public static TransmitterData create(int raw_data ,int sensor_battery_level, lon
return transmitterData;
}

public static TransmitterData createFromBinary(byte data[]) {
/* this is the C structure packed in data
needs to be in sync with wixel-DexDrip/libraries/include/dexdrip_packet.h
structure has versioning used only when members are changed;

Version 1:
struct dexdrip_data_packet {
uint8 version;
uint8 dexcom_battery;
uint16 dexdrip_battery;
uint32 raw;
} dexdrip_data_packet_t;
*/

int version;
int wixel_battery;
TransmitterData transmitterData = new TransmitterData();

version = PacketUtil.uint8FromBuffer(data, 0);
if (version == 1) {
if (data.length != 8) {
/* incompatible ABI with wixel */
Log.e(TAG, "corrupted packet - data length " + data.length + " is different than expected " + 8);
return null;
}
transmitterData.sensor_battery_level = PacketUtil.uint8FromBuffer(data, 1);
wixel_battery = PacketUtil.uint16FromBuffer(data, 2);
transmitterData.raw_data = PacketUtil.uint32FromBuffer(data, 4);
} else {
Log.e(TAG, "unknown data packet version " + version);
return null;
}

transmitterData.timestamp = new Date().getTime();
transmitterData.uuid = UUID.randomUUID().toString();
Log.d(TAG, "binary transmitter data raw " + transmitterData.raw_data +
" sensor battery " + transmitterData.sensor_battery_level +
" wixel battery " + wixel_battery);
transmitterData.save();
return transmitterData;
}

public static TransmitterData last() {
return new Select()
.from(TransmitterData.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.activeandroid.query.Select;
import com.eveningoutpost.dexdrip.Models.ActiveBluetoothDevice;
import com.eveningoutpost.dexdrip.Models.BgReading;
import com.eveningoutpost.dexdrip.Models.DexdripPacket;
import com.eveningoutpost.dexdrip.Sensor;
import com.eveningoutpost.dexdrip.UtilityModels.CollectionServiceStarter;
import com.eveningoutpost.dexdrip.UtilityModels.ForegroundServiceStarter;
Expand Down Expand Up @@ -75,6 +76,17 @@ public class DexCollectionService extends Service {
private static final int STATE_CONNECTING = BluetoothProfile.STATE_CONNECTING;
private static final int STATE_CONNECTED = BluetoothProfile.STATE_CONNECTED;

private static final int PSTATE_NEW_PACKET = 0;
private static final int PSTATE_PRIOR_READ_LEN = 1;
private static final int PSTATE_INREAD = 2;

private int mPacketState = PSTATE_NEW_PACKET;
private byte mPacket[];
private byte mPacketType;
private byte mPacketLen;
private byte mPacketReadBytes;
private long mLastReadTimestamp;

public final static String ACTION_DATA_AVAILABLE = "com.example.bluetooth.le.ACTION_DATA_AVAILABLE";
public final static UUID DexDripDataService = UUID.fromString(HM10Attributes.HM_10_SERVICE);
public final static UUID DexDripDataCharacteristic = UUID.fromString(HM10Attributes.HM_RX_TX);
Expand Down Expand Up @@ -238,7 +250,7 @@ private void broadcastUpdate(final String action,
final byte[] data = characteristic.getValue();

if (data != null && data.length > 0) {
setSerialDataToTransmitterRawData(data, data.length);
setSerialBinaryDataToTransmitterRawData(data, data.length);
}
}

Expand Down Expand Up @@ -350,19 +362,104 @@ public void setCharacteristicNotification(BluetoothGattCharacteristic characteri
}

public void setSerialDataToTransmitterRawData(byte[] buffer, int len) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First off, this PR is super cool, my biggest issue is that I dont want an app update to make someones currently functional wixel stop being able to communicate with xDrip, can we split this setSerialDataToTransmitterRawData and have it go down two logical paths, one if its the old style, one if its the new style,
Also I would love it if the start of each of these new packets was a version number (this being version 1, that way if we down the road add in some more params we can easily check which version of the a transmitter data parser to use)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have added a fallback mechanism see line 397


Log.w(TAG, "received some data!");
TransmitterData transmitterData = TransmitterData.create(buffer, len);
Long timestamp = new Date().getTime();
TransmitterData transmitterData = TransmitterData.create(buffer, len, timestamp);
if (transmitterData != null) {
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
sensor.latest_battery_level = transmitterData.sensor_battery_level;
sensor.save();

BgReading bgReading = BgReading.create(transmitterData.raw_data, this);
BgReading bgReading = BgReading.create(transmitterData.raw_data, this, timestamp);
} else {
Log.w(TAG, "No Active Sensor, Data only stored in Transmitter Data");
}
}
}

public void setSerialBinaryDataToTransmitterRawData(byte[] buffer, int len) {
int bufferReadPos = 0;
int i = 0;
Log.w(TAG, "received some data! " + len);
Long timestamp = new Date().getTime();
if (timestamp - mLastReadTimestamp > 2000) {
//if there was no read notification for over 2s means we had a malformed short packet;
//save the new timestamp and reset state machine
mPacketState = PSTATE_NEW_PACKET;
mLastReadTimestamp = timestamp;
}

if (mPacketState == PSTATE_NEW_PACKET) {
//beginning of a new packet - get type len and as much as available from packet
if (len > bufferReadPos) {
mPacketType = buffer[bufferReadPos];
Log.d(TAG, "read packet type " + mPacketType);
if (mPacketType != DexdripPacket.PACKET_DATA) {
Log.e(TAG, "this is not a binary packet switch to old method");
setSerialDataToTransmitterRawData(buffer, len);
return;
}

//goto to next state
mPacketState = PSTATE_PRIOR_READ_LEN;
bufferReadPos++;
}
}

if (mPacketState == PSTATE_PRIOR_READ_LEN) {
//read the packet length
if (len > bufferReadPos) {
mPacketLen = buffer[bufferReadPos];
Log.d(TAG, "packet len " + mPacketLen);
if (mPacketLen > 20) {
mPacketState = PSTATE_NEW_PACKET;
Log.e(TAG, "malformed packet received");
return;
}
mPacketState = PSTATE_INREAD;
mPacket = new byte[mPacketLen];
mPacketReadBytes = 0;
bufferReadPos++;
}
}

if (mPacketState == PSTATE_INREAD) {
//read the packet
for (i = bufferReadPos; (mPacketReadBytes < mPacketLen) && (i<len); i++, mPacketReadBytes++)
mPacket[mPacketReadBytes] = buffer[i];
Log.d(TAG, "read " + mPacket);
}

if (mPacketState != PSTATE_INREAD)
//haven't make it to read state - need at least one more notification in order to have the full packet
return;

if (mPacketReadBytes != mPacketLen)
//read just part of the packet - return and read the next part in following notification
return;

if (i < len) {
//had a longer packet than what was expected
mPacketState = PSTATE_NEW_PACKET;
Log.e(TAG, "received malformed packet");
return;
}

//we have the full packet create transmitter data and reset state machine
mPacketState = PSTATE_NEW_PACKET;
if (mPacketType == DexdripPacket.PACKET_DATA) {
TransmitterData transmitterData = TransmitterData.createFromBinary(mPacket);
if (transmitterData != null) {
Sensor sensor = Sensor.currentSensor();
if (sensor != null) {
sensor.latest_battery_level = transmitterData.sensor_battery_level;
sensor.save();

BgReading bgReading = BgReading.create(transmitterData.raw_data, this, timestamp);
} else {
Log.w(TAG, "No Active Sensor, Data only stored in Transmitter Data");
}
}
}
}
}
52 changes: 52 additions & 0 deletions app/src/main/java/com/eveningoutpost/dexdrip/utils/PacketUtil.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.eveningoutpost.dexdrip.utils;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.ShortBuffer;

/**
* Created by Radu Iliescu on 26.02.2015.
*/
public class PacketUtil {
public static int int32FromBuffer(byte data[], int offset) {
ByteBuffer bb = ByteBuffer.wrap(data, offset, 4);
IntBuffer sb = bb.asIntBuffer();
return sb.get();
}

public static int uint32FromBuffer(byte data[], int offset) {
int ret = int32FromBuffer(data, offset);

if (ret < 0) {
ret += 1 << 32;
}

return ret;
}

public static int int16FromBuffer(byte data[], int offset) {
ByteBuffer bb = ByteBuffer.wrap(data, offset, 2);
ShortBuffer sb = bb.asShortBuffer();
return sb.get();
}

public static int uint16FromBuffer(byte data[], int offset) {
int ret = int16FromBuffer(data, offset);

if (ret < 0) {
ret += 1 << 16;
}

return ret;
}

public static int uint8FromBuffer(byte data[], int offset) {
int ret = data[offset];

if (ret < 0) {
ret += 1 << 8;
}
return ret;
}
}