Initial project commit

This commit is contained in:
2020-07-18 21:44:27 -04:00
parent 8a1141b373
commit fea891a268
127 changed files with 20838 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CRC16 {
public static byte[] calculate(byte[] buff, int start, int end) {
int crcShort = 0;
for (int i = start; i < end; i++) {
crcShort = ((crcShort >>> 8) | (crcShort << 8) )& 0xffff;
crcShort ^= (buff[i] & 0xff);
crcShort ^= ((crcShort & 0xff) >> 4);
crcShort ^= (crcShort << 12) & 0xffff;
crcShort ^= ((crcShort & 0xFF) << 5) & 0xffff;
}
crcShort &= 0xffff;
return new byte[] {(byte) (crcShort & 0xff), (byte) ((crcShort >> 8) & 0xff)};
}
}

View File

@@ -0,0 +1,11 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CRCFailRuntimeException extends RuntimeException {
public CRCFailRuntimeException(String message){
super(message);
}
}

View File

@@ -0,0 +1,210 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class Dex_Constants {
public final static int NULL = 0;
public final static int ACK = 1;
public final static int NAK = 2;
public final static int INVALID_COMMAND = 3;
public final static int INVALID_PARAM = 4;
public final static int INCOMPLETE_PACKET_RECEIVED = 5;
public final static int RECEIVER_ERROR = 6;
public final static int INVALID_MODE = 7;
public final static int PING = 10;
public final static int READ_FIRMWARE_HEADER = 11;
public final static int READ_DATABASE_PARTITION_INFO = 15;
public final static int READ_DATABASE_PAGE_RANGE = 16;
public final static int READ_DATABASE_PAGES = 17;
public final static int READ_DATABASE_PAGE_HEADER = 18;
public final static int READ_TRANSMITTER_ID = 25;
public final static int WRITE_TRANSMITTER_ID = 26;
public final static int READ_LANGUAGE = 27;
public final static int WRITE_LANGUAGE = 28;
public final static int READ_DISPLAY_TIME_OFFSET = 29;
public final static int WRITE_DISPLAY_TIME_OFFSET = 30;
public final static int READ_RTC = 31;
public final static int RESET_RECEIVER = 32;
public final static int READ_BATTERY_LEVEL = 33;
public final static int READ_SYSTEM_TIME = 34;
public final static int READ_SYSTEM_TIME_OFFSET = 35;
public final static int WRITE_SYSTEM_TIME = 36;
public final static int READ_GLUCOSE_UNIT = 37;
public final static int WRITE_GLUCOSE_UNIT = 38;
public final static int READ_BLINDED_MODE = 39;
public final static int WRITE_BLINDED_MODE = 40;
public final static int READ_CLOCK_MODE = 41;
public final static int WRITE_CLOCK_MODE = 42;
public final static int READ_DEVICE_MODE = 43;
public final static int ERASE_DATABASE = 45;
public final static int SHUTDOWN_RECEIVER = 46;
public final static int WRITE_PC_PARAMETERS = 47;
public final static int READ_BATTERY_STATE = 48;
public final static int READ_HARDWARE_BOARD_ID = 49;
public final static int READ_FIRMWARE_SETTINGS = 54;
public final static int READ_ENABLE_SETUP_WIZARD_FLAG = 55;
public final static int READ_SETUP_WIZARD_STATE = 57;
public final static int MAX_COMMAND = 59;
public final static int MAX_POSSIBLE_COMMAND = 255;
public final static int EGV_VALUE_MASK = 1023;
public final static int EGV_DISPLAY_ONLY_MASK = 32768;
public final static int EGV_TREND_ARROW_MASK = 15;
public final static int EGV_NOISE_MASK = 112;
public final static float MG_DL_TO_MMOL_L = 0.05556f;
public final static int CRC_LEN = 2;
public static final int TRANSMITTER_BATTERY_LOW = 210;
public static final int TRANSMITTER_BATTERY_EMPTY = 207;
public enum BATTERY_STATES {
NONE,
CHARGING,
NOT_CHARGING,
NTC_FAULT,
BAD_BATTERY
}
public enum RECORD_TYPES {
MANUFACTURING_DATA,
FIRMWARE_PARAMETER_DATA,
PC_SOFTWARE_PARAMETER,
SENSOR_DATA,
EGV_DATA,
CAL_SET,
DEVIATION,
INSERTION_TIME,
RECEIVER_LOG_DATA,
RECEIVER_ERROR_DATA,
METER_DATA,
USER_EVENT_DATA,
USER_SETTING_DATA,
MAX_VALUE
}
public enum TREND_ARROW_VALUES {
NONE(0),
DOUBLE_UP(1,"\u21C8", "DoubleUp"),
SINGLE_UP(2,"\u2191", "SingleUp"),
UP_45(3,"\u2197", "FortyFiveUp"),
FLAT(4,"\u2192", "Flat"),
DOWN_45(5,"\u2198", "FortyFiveDown"),
SINGLE_DOWN(6,"\u2193", "SingleDown"),
DOUBLE_DOWN(7,"\u21CA", "DoubleDown"),
NOT_COMPUTABLE(8, "", "NOT_COMPUTABLE"),
OUT_OF_RANGE(9, "", "OUT_OF_RANGE");
private String arrowSymbol;
private String trendName;
private int myID;
TREND_ARROW_VALUES(int id, String a, String t) {
myID=id;
arrowSymbol = a;
trendName = t;
}
TREND_ARROW_VALUES(int id) {
this(id,null, null);
}
public String Symbol() {
if (arrowSymbol == null) {
return "\u2194";
} else {
return arrowSymbol;
}
}
public String friendlyTrendName() {
if (trendName == null) {
return this.name().replace("_", " ");
} else {
return this.trendName;
}
}
public int getID(){
return myID;
}
}
public enum SPECIALBGVALUES_MGDL {
NONE("??0", 0),
SENSORNOTACTIVE("?SN", 1),
MINIMALLYEGVAB("??2", 2),
NOANTENNA("?NA", 3),
SENSOROUTOFCAL("?NC", 5),
COUNTSAB("?CD", 6),
ABSOLUTEAB("?AD", 9),
POWERAB("???", 10),
RFBADSTATUS("?RF", 12);
private String name;
private int val;
private SPECIALBGVALUES_MGDL(String s, int i){
name=s;
val=i;
}
public int getValue(){
return val;
}
public String toString(){
return name;
}
public static SPECIALBGVALUES_MGDL getEGVSpecialValue(int val){
for (SPECIALBGVALUES_MGDL e: values()){
if (e.getValue()==val)
return e;
}
return null;
}
public static boolean isSpecialValue(int val){
for (SPECIALBGVALUES_MGDL e: values()){
if (e.getValue()==val)
return true;
}
return false;
}
}
public enum InsertionState {
NONE,
REMOVED,
EXPIRED,
RESIDUAL_DEVIATION,
COUNTS_DEVIATION,
SECOND_SESSION,
OFF_TIME_LOSS,
STARTED,
BAD_TRANSMITTER,
MANUFACTURING_MODE,
MAX_VALUE
}
public enum NOISE {
NOISE_NONE(0),
CLEAN(1),
LIGHT(2),
MEDIUM(3),
HEAVY(4),
NOT_COMPUTED(5),
MAX(6);
private final int value;
private NOISE(int value) {
this.value = value;
}
}
}

View File

@@ -0,0 +1,108 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import java.util.ArrayList;
import java.util.List;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class PacketBuilder {
public static final int MAX_PAYLOAD = 1584;
public static final int MIN_LEN = 6;
public static final int MAX_LEN = MAX_PAYLOAD + MIN_LEN;
public static final byte SOF = 0x01;
public static final int OFFSET_SOF = 0;
public static final int OFFSET_LENGTH = 1;
public static final int OFFSET_NULL = 2;
public static final byte NULL = 0x00;
public static final int OFFSET_CMD = 3;
public static final int OFFSET_PAYLOAD = 4;
public static final int CRC_LEN = 2;
public static final int HEADER_LEN = 4;
public ArrayList<Byte> packet;
public int command;
public ArrayList<Byte> payload;
public PacketBuilder(int command) {
this.command = command;
}
public PacketBuilder(int command, ArrayList<Byte> payload) {
this.command = command;
this.payload = payload;
}
public byte[] compose() {
packet = new ArrayList<Byte>();
packet.add(OFFSET_SOF, SOF);
packet.add(OFFSET_LENGTH, getLength());
packet.add(OFFSET_NULL, NULL);
packet.add(OFFSET_CMD, (byte) command);
if (this.payload != null) { this.packet.addAll(OFFSET_PAYLOAD, this.payload); }
byte[] crc16 = CRC16.calculate(toBytes(), 0, this.packet.size());
this.packet.add(crc16[0]);
this.packet.add(crc16[1]);
Log.d("ShareTest", "About to start adding to Byte, size: " + this.packet.size());
return this.toBytes();
}
public List<byte[]> composeList() {
packet = new ArrayList<Byte>();
packet.add(OFFSET_SOF, SOF);
packet.add(OFFSET_LENGTH, getLength());
packet.add(OFFSET_NULL, NULL);
packet.add(OFFSET_CMD, (byte) command);
if (this.payload != null) { this.packet.addAll(OFFSET_PAYLOAD, this.payload); }
byte[] crc16 = CRC16.calculate(toBytes(), 0, this.packet.size());
this.packet.add(crc16[0]);
this.packet.add(crc16[1]);
Log.d("ShareTest", "About to start adding to ByteList, size: " + this.packet.size());
return this.toBytesList();
}
private byte getLength() {
int packetSize = payload == null ? MIN_LEN : payload.size() + CRC_LEN + HEADER_LEN;
if (packetSize > MAX_LEN) {
throw new IndexOutOfBoundsException(packetSize + " bytes, but packet must between "
+ MIN_LEN + " and " + MAX_LEN + " bytes.");
}
return (byte) packetSize;
}
public byte[] toBytes() {
byte[] b = new byte[this.packet.size()];
for (int i = 0; i < this.packet.size(); i++) {
b[i] = this.packet.get(i).byteValue();
}
return b;
}
public List<byte[]> toBytesList() {
List<byte[]> byteMessages = new ArrayList<byte[]>();
double totalPacketSize = packet.size();
int messages =(int) Math.ceil(totalPacketSize/18);
for(int m = 0; m < messages; m++) {
int thisPacketSize;
if (m == messages - 1) {
thisPacketSize = ((this.packet.size()+2) % 18);
} else {
thisPacketSize = (20);
}
int offset = m * 18;
Log.d("ShareTest", "This packet size: " + thisPacketSize);
byte[] b = new byte[thisPacketSize];
b[0] = (byte) (m + 1);
b[1] = (byte) (messages);
for (int i = 2; i < thisPacketSize; i++) {
b[i] = packet.get(offset + i - 2).byteValue();
}
byteMessages.add(b);
}
return byteMessages;
}
}

View File

@@ -0,0 +1,348 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GenericXMLRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.PageHeader;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import org.w3c.dom.Element;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
public class ReadData {
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
private static final String TAG = ReadData.class.getSimpleName();
private static final int IO_TIMEOUT = 3000;
private static final int MIN_LEN = 256;
private UsbSerialDriver mSerialDevice;
protected final Object mReadBufferLock = new Object();
private UsbDeviceConnection mConnection;
private UsbDevice mDevice;
public ReadData(){}
public ReadData(UsbSerialDriver device) {
mSerialDevice = device;
}
public ReadData(UsbSerialDriver device, UsbDeviceConnection connection, UsbDevice usbDevice) {
mSerialDevice = device;
mConnection = connection;
mDevice = usbDevice;
try {
mSerialDevice.getPorts().get(0).open(connection);
} catch(IOException e) {
Log.d("FAILED WHILE", "trying to open");
}
// }
}
public EGVRecord[] getRecentEGVs() {
int recordType = Dex_Constants.RECORD_TYPES.EGV_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
return readDataBasePage(recordType, endPage);
}
public EGVRecord[] getRecentEGVsPages(int numOfRecentPages) {
if (numOfRecentPages < 1) {
throw new IllegalArgumentException("Number of pages must be greater than 1.");
}
Log.d(TAG, "Reading EGV page range...");
int recordType = Dex_Constants.RECORD_TYPES.EGV_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading " + numOfRecentPages + " EGV page(s)...");
numOfRecentPages = numOfRecentPages - 1;
EGVRecord[] allPages = new EGVRecord[0];
for (int i = Math.min(numOfRecentPages,endPage); i >= 0; i--) {
int nextPage = endPage - i;
Log.d(TAG, "Reading #" + i + " EGV pages (page number " + nextPage + ")");
EGVRecord[] ithEGVRecordPage = readDataBasePage(recordType, nextPage);
EGVRecord[] result = Arrays.copyOf(allPages, allPages.length + ithEGVRecordPage.length);
System.arraycopy(ithEGVRecordPage, 0, result, allPages.length, ithEGVRecordPage.length);
allPages = result;
}
Log.d(TAG, "Read complete of EGV pages.");
return allPages;
}
public long getTimeSinceEGVRecord(EGVRecord egvRecord) {
return readSystemTime() - egvRecord.getSystemTimeSeconds();
}
public MeterRecord[] getRecentMeterRecords() {
Log.d(TAG, "Reading Meter page...");
int recordType = Dex_Constants.RECORD_TYPES.METER_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
return readDataBasePage(recordType, endPage);
}
public SensorRecord[] getRecentSensorRecords(int numOfRecentPages) {
if (numOfRecentPages < 1) {
throw new IllegalArgumentException("Number of pages must be greater than 1.");
}
Log.d(TAG, "Reading Sensor page range...");
int recordType = Dex_Constants.RECORD_TYPES.SENSOR_DATA.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading " + numOfRecentPages + " Sensor page(s)...");
numOfRecentPages = numOfRecentPages - 1;
SensorRecord[] allPages = new SensorRecord[0];
for (int i = Math.min(numOfRecentPages,endPage); i >= 0; i--) {
int nextPage = endPage - i;
Log.d(TAG, "Reading #" + i + " Sensor pages (page number " + nextPage + ")");
SensorRecord[] ithSensorRecordPage = readDataBasePage(recordType, nextPage);
SensorRecord[] result = Arrays.copyOf(allPages, allPages.length + ithSensorRecordPage.length);
System.arraycopy(ithSensorRecordPage, 0, result, allPages.length, ithSensorRecordPage.length);
allPages = result;
}
Log.d(TAG, "Read complete of Sensor pages.");
return allPages;
}
public CalRecord[] getRecentCalRecords() {
Log.d(TAG, "Reading Cal Records page range...");
int recordType = Dex_Constants.RECORD_TYPES.CAL_SET.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading Cal Records page...");
return readDataBasePage(recordType, endPage);
}
public byte[] getRecentCalRecordsTest() {
Log.d(TAG, "Reading Cal Records page range...");
int recordType = Dex_Constants.RECORD_TYPES.CAL_SET.ordinal();
int endPage = readDataBasePageRange(recordType);
Log.d(TAG, "Reading Cal Records page...");
return readDataBasePageTest(recordType, endPage);
}
public boolean ping() {
writeCommand(Dex_Constants.PING);
return read(MIN_LEN).getCommand() == Dex_Constants.ACK;
}
public int readBatteryLevel() {
Log.d(TAG, "Reading battery level...");
writeCommand(Dex_Constants.READ_BATTERY_LEVEL);
byte[] readData = read(MIN_LEN).getData();
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt();
}
public String readSerialNumber() {
int PAGE_OFFSET = 0;
byte[] readData = readDataBasePage(Dex_Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), PAGE_OFFSET);
Element md = ParsePage(readData, Dex_Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal());
return md.getAttribute("SerialNumber");
}
public Date readDisplayTime() {
return Utils.receiverTimeToDate(readSystemTime() + readDisplayTimeOffset());
}
public long readSystemTime() {
Log.d(TAG, "Reading system time...");
writeCommand(Dex_Constants.READ_SYSTEM_TIME);
byte[] readData = read(MIN_LEN).getData();
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffff;
}
public int readDisplayTimeOffset() {
Log.d(TAG, "Reading display time offset...");
writeCommand(Dex_Constants.READ_DISPLAY_TIME_OFFSET);
byte[] readData = read(MIN_LEN).getData();
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffff;
}
private int readDataBasePageRange(int recordType) {
ArrayList<Byte> payload = new ArrayList<Byte>();
Log.d(TAG, "adding Payload");
payload.add((byte) recordType);
Log.d(TAG, "Sending write command");
writeCommand(Dex_Constants.READ_DATABASE_PAGE_RANGE, payload);
Log.d(TAG, "About to call getdata");
byte[] readData = read(MIN_LEN).getData();
Log.d(TAG, "Going to return");
return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt(4);
}
private <T> T readDataBasePage(int recordType, int page) {
byte numOfPages = 1;
if (page < 0){
throw new IllegalArgumentException("Invalid page requested:" + page);
}
ArrayList<Byte> payload = new ArrayList<Byte>();
payload.add((byte) recordType);
byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();
payload.add(pageInt[3]);
payload.add(pageInt[2]);
payload.add(pageInt[1]);
payload.add(pageInt[0]);
payload.add(numOfPages);
writeCommand(Dex_Constants.READ_DATABASE_PAGES, payload);
byte[] readData = read(2122).getData();
return ParsePage(readData, recordType);
}
private byte[] readDataBasePageTest(int recordType, int page) {
byte numOfPages = 1;
if (page < 0){
throw new IllegalArgumentException("Invalid page requested:" + page);
}
ArrayList<Byte> payload = new ArrayList<Byte>();
payload.add((byte) recordType);
byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();
payload.add(pageInt[3]);
payload.add(pageInt[2]);
payload.add(pageInt[1]);
payload.add(pageInt[0]);
payload.add(numOfPages);
return writeCommandTest(Dex_Constants.READ_DATABASE_PAGES, payload);
}
private void writeCommand(int command, ArrayList<Byte> payload) {
byte[] packet = new PacketBuilder(command, payload).compose();
if (mSerialDevice != null) {
try {
// UsbInterface mDataInterface = mDevice.getInterface(1);
// UsbEndpoint mWriteEndpoint = mDataInterface.getEndpoint(0);
// mConnection.bulkTransfer(mWriteEndpoint, packet, packet.length, IO_TIMEOUT);
mSerialDevice.getPorts().get(0).write(packet, IO_TIMEOUT);
} catch (Exception e) {
Log.e(TAG, "Unable to write to serial device.", e);
}
}
}
private byte[] writeCommandTest(int command, ArrayList<Byte> payload) {
byte[] packet = new PacketBuilder(command, payload).compose();
return packet;
}
private void writeCommand(int command) {
byte[] packet = new PacketBuilder(command).compose();
if (mSerialDevice != null) {
try {
// UsbInterface mDataInterface = mDevice.getInterface(1);
// UsbEndpoint mWriteEndpoint = mDataInterface.getEndpoint(0);
// mConnection.bulkTransfer(mWriteEndpoint, packet, packet.length, IO_TIMEOUT);
mSerialDevice.getPorts().get(0).write(packet, IO_TIMEOUT);
} catch (Exception e) {
Log.e(TAG, "Unable to write to serial device.", e);
}
}
}
private ReadPacket read(int numOfBytes) {
byte[] readData = new byte[numOfBytes];
int len = 0;
try {
// UsbInterface mDataInterface = mDevice.getInterface(1);
// UsbEndpoint mReadEndpoint = mDataInterface.getEndpoint(1);
// byte[] mReadBuffer;
// mReadBuffer = new byte[16 * 1024];
//
// int readAmt = Math.min(readData.length, mReadBuffer.length);
// synchronized (mReadBufferLock) {
//
//
// Log.d(TAG, "Read about to call bulk transfer.");
// if (len < 0) {
// // This sucks: we get -1 on timeout, not 0 as preferred.
// // We *should* use UsbRequest, except it has a bug/api oversight
// // where there is no way to determine the number of bytes read
// // in response :\ -- http://b.android.com/28023
// if (IO_TIMEOUT == Integer.MAX_VALUE) {
// // Hack: Special case "~infinite timeout" as an error.
// len = -1;
// }
// len = 0;
// }
//
//// System.arraycopy(mReadBuffer, 0, readData, 0, readAmt);
// }
// len = mConnection.bulkTransfer(mReadEndpoint, readData, readAmt, IO_TIMEOUT);
len = mSerialDevice.getPorts().get(0).read(readData, IO_TIMEOUT);
Log.d(TAG, "Read " + len + " byte(s) complete.");
// Add a 100ms delay for when multiple write/reads are occurring in series
Thread.sleep(100);
// TODO: this debug code to print data of the read, should be removed after
// finding the source of the reading issue
String bytes = "";
int readAmount = len;
for (int i = 0; i < readAmount; i++) bytes += String.format("%02x", readData[i]) + " ";
Log.d(TAG, "Read data: " + bytes);
////////////////////////////////////////////////////////////////////////////////////////
} catch (Exception e) {
Log.e(TAG, "Unable to read from serial device.", e);
}
byte[] data = Arrays.copyOfRange(readData, 0, len);
return new ReadPacket(data);
}
private <T> T ParsePage(byte[] data, int recordType) {
int HEADER_LEN = 28;
PageHeader pageHeader=new PageHeader(data);
int NUM_REC_OFFSET = 4;
int numRec = data[NUM_REC_OFFSET];
int rec_len;
switch (Dex_Constants.RECORD_TYPES.values()[recordType]) {
case MANUFACTURING_DATA:
GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1));
return (T) xmlRecord;
case SENSOR_DATA:
rec_len = 20;
SensorRecord[] sensorRecords = new SensorRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
sensorRecords[i] = new SensorRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) sensorRecords;
case EGV_DATA:
rec_len = 13;
EGVRecord[] egvRecords = new EGVRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
egvRecords[i] = new EGVRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) egvRecords;
case METER_DATA:
rec_len = 16;
MeterRecord[] meterRecords = new MeterRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) meterRecords;
case CAL_SET:
rec_len = 249;
if (pageHeader.getRevision()<=2) {
rec_len = 148;
}
CalRecord[] calRecords = new CalRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
calRecords[i] = new CalRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
return (T) calRecords;
default:
// Throw error "Database record not supported"
break;
}
return (T) null;
}
}

View File

@@ -0,0 +1,305 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GenericXMLRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.PageHeader;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.Services.DexShareCollectionService;
import com.eveningoutpost.dexdrip.ShareTest;
import org.w3c.dom.Element;
import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import rx.Observable;
import rx.functions.Action1;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class ReadDataShare {
byte[] accumulatedResponse;
private ShareTest mShareTest;
private DexShareCollectionService mCollectionService;
public ReadDataShare(ShareTest aShareTest){
mShareTest = aShareTest;
}
public ReadDataShare(DexShareCollectionService collectionService){
mCollectionService = collectionService;
}
public void getRecentEGVs(final Action1<EGVRecord[]> recordListener) {
final int recordType = Dex_Constants.RECORD_TYPES.EGV_DATA.ordinal();
final Action1<byte[]> fullPageListener = new Action1<byte[]>() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getRecentMeterRecords(final Action1<MeterRecord[]> recordListener) {
final int recordType = Dex_Constants.RECORD_TYPES.METER_DATA.ordinal();
final Action1<byte[]> fullPageListener = new Action1<byte[]>() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getRecentCalRecords(final Action1<CalRecord[]> recordListener) {
final int recordType = Dex_Constants.RECORD_TYPES.CAL_SET.ordinal();
final Action1<byte[]> fullPageListener = new Action1<byte[]>() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getRecentSensorRecords(final Action1<SensorRecord[]> recordListener) {
final int recordType = Dex_Constants.RECORD_TYPES.SENSOR_DATA.ordinal();
final Action1<byte[]> fullPageListener = new Action1<byte[]>() {
@Override
public void call(byte[] s) { ParsePage(read(0,s).getData(), recordType, recordListener); }
};
Action1<Integer> databasePageRangeCaller = new Action1<Integer>() {
@Override
public void call(Integer s) { readDataBasePage(recordType, s, fullPageListener); }
};
readDataBasePageRange(recordType, databasePageRangeCaller);
}
public void getTimeSinceEGVRecord(final EGVRecord egvRecord, final Action1<Long> timeSinceEgvRecord) {
Action1<Long> tempSystemTimeListener = new Action1<Long>() {
@Override
public void call(Long s) { Observable.just(s - egvRecord.getSystemTimeSeconds()).subscribe(timeSinceEgvRecord); }
};
readSystemTime(tempSystemTimeListener);
}
public void ping(final Action1<Boolean> pingListener) {
Action1<byte[]> pingReader = new Action1<byte[]>() {
@Override
public void call(byte[] s) { Observable.just(read(0, s).getCommand() == Dex_Constants.ACK).subscribe(pingListener); }
};
writeCommand(Dex_Constants.PING, pingReader);
}
public void readBatteryLevel(final Action1<Integer> batteryLevelListener) {
Action1<byte[]> batteryLevelReader = new Action1<byte[]>() {
@Override //TODO: find out if this should be wrapped in read(s).getData();
public void call(byte[] s) { Observable.just(ByteBuffer.wrap(s).order(ByteOrder.LITTLE_ENDIAN).getInt()).subscribe(batteryLevelListener); }
};
writeCommand(Dex_Constants.READ_BATTERY_LEVEL, batteryLevelReader);
}
public void readSerialNumber(final Action1<String> serialNumberListener) {
final Action1<byte[]> manufacturingDataListener = new Action1<byte[]>() {
@Override
public void call(byte[] s) {
Element el = ParsePage(s, Dex_Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal());
Observable.just(el.getAttribute("SerialNumber")).subscribe(serialNumberListener);
}
};
readDataBasePage(Dex_Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), 0, manufacturingDataListener);
}
public void readDisplayTime(final Action1<Date> displayTimeListener) {
Action1<Long> tempSystemTimeListener = new Action1<Long>() {
@Override
public void call(Long s) {
final long systemTime = s;
Action1<Long> tempSystemTimeListener = new Action1<Long>() {
@Override
public void call(Long s) {
Date dateDisplayTime = Utils.receiverTimeToDate(systemTime + s);
Observable.just(dateDisplayTime).subscribe(displayTimeListener); }
};
readDisplayTimeOffset(tempSystemTimeListener);
}
};
readSystemTime(tempSystemTimeListener);
}
public void readSystemTime(final Action1<Long> systemTimeListener) {
Action1<byte[]> systemTimeReader = new Action1<byte[]>() {
@Override
public void call(byte[] s) {
Observable.just(Utils.receiverTimeToDate(ByteBuffer.wrap(read(0,s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt()).getTime()).subscribe(systemTimeListener);
}
};
writeCommand(Dex_Constants.READ_SYSTEM_TIME, systemTimeReader);
}
public void readDisplayTimeOffset(final Action1<Long> displayTimeOffsetListener) {
Action1<byte[]> displayTimeOffsetReader = new Action1<byte[]>() {
@Override
public void call(byte[] s) { Observable.just((long) ByteBuffer.wrap(read(0,s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt()).subscribe(displayTimeOffsetListener); }
};
writeCommand(Dex_Constants.READ_DISPLAY_TIME_OFFSET, displayTimeOffsetReader);
}
private void readDataBasePageRange(int recordType, final Action1<Integer> databasePageRangeCaller) {
ArrayList<Byte> payload = new ArrayList<Byte>();
payload.add((byte) recordType);
final Action1<byte[]> databasePageRangeListener = new Action1<byte[]>() {
@Override
public void call(byte[] s) {
Observable.just(ByteBuffer.wrap(new ReadPacket(s).getData()).order(ByteOrder.LITTLE_ENDIAN).getInt(4)).subscribe(databasePageRangeCaller);
}
};
writeCommand(Dex_Constants.READ_DATABASE_PAGE_RANGE, payload, databasePageRangeListener);
}
private <T> T readDataBasePage(final int recordType, int page, final Action1<byte[]> fullPageListener) {
byte numOfPages = 1;
if (page < 0){ throw new IllegalArgumentException("Invalid page requested:" + page); }
ArrayList<Byte> payload = new ArrayList<Byte>();
payload.add((byte) recordType);
byte[] pageInt = ByteBuffer.allocate(4).putInt(page).array();
payload.add(pageInt[3]);
payload.add(pageInt[2]);
payload.add(pageInt[1]);
payload.add(pageInt[0]);
payload.add(numOfPages);
accumulatedResponse = null;
final Action1<byte[]> databasePageReader = new Action1<byte[]>() {
@Override
public void call(byte[] s) {
Log.d("ShareTest", "Database Page Reader received SIZE: " + s.length);
byte[] temp = s;
if (accumulatedResponse == null) {
accumulatedResponse = s;
} else {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
outputStream.write(accumulatedResponse);
outputStream.write(temp);
accumulatedResponse = outputStream.toByteArray();
Log.d("ShareTest", "Combined Response length: " + accumulatedResponse.length);
} catch (Exception e) { e.printStackTrace(); }
}
if (temp.length < 20) { Observable.just(accumulatedResponse).subscribe(fullPageListener).unsubscribe(); }
}
};
writeCommand(Dex_Constants.READ_DATABASE_PAGES, payload, databasePageReader);
return null;
}
private void writeCommand(int command, ArrayList<Byte> payload, Action1<byte[]> responseListener) {
List<byte[]> packets = new PacketBuilder(command, payload).composeList();
if(mShareTest != null) { mShareTest.writeCommand(packets, 0, responseListener); }
else if (mCollectionService != null) { mCollectionService.writeCommand(packets, 0, responseListener); }
}
private void writeCommand(int command, Action1<byte[]> responseListener) {
List<byte[]> packets = new PacketBuilder(command).composeList();
if(mShareTest != null) { mShareTest.writeCommand(packets, 0, responseListener); }
else if (mCollectionService != null) { mCollectionService.writeCommand(packets, 0, responseListener); }
}
private ReadPacket read(int numOfBytes, byte[] readPacket) {
return new ReadPacket(Arrays.copyOfRange(readPacket, 0, readPacket.length));
}
private <T> T ParsePage(byte[] data, int recordType) { return ParsePage(data, recordType, null); }
private <T> T ParsePage(byte[] data, int recordType, Action1<T> parsedPageReceiver) {
int HEADER_LEN = 28;
PageHeader pageHeader=new PageHeader(data);
int NUM_REC_OFFSET = 4;
int numRec = data[NUM_REC_OFFSET];
int rec_len;
switch (Dex_Constants.RECORD_TYPES.values()[recordType]) {
case MANUFACTURING_DATA:
GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1));
if(parsedPageReceiver != null) {
Observable.just((T) xmlRecord).subscribe(parsedPageReceiver);
} else {
return (T) xmlRecord;
}
break;
case SENSOR_DATA:
rec_len = 20;
SensorRecord[] sensorRecords = new SensorRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
sensorRecords[i] = new SensorRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) sensorRecords).subscribe(parsedPageReceiver);
} else {
return (T) sensorRecords;
}
break;
case EGV_DATA:
rec_len = 13;
EGVRecord[] egvRecords = new EGVRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
egvRecords[i] = new EGVRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) egvRecords).subscribe(parsedPageReceiver);
} else {
return (T) egvRecords;
}
break;
case METER_DATA:
rec_len = 16;
MeterRecord[] meterRecords = new MeterRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) meterRecords).subscribe(parsedPageReceiver);
} else {
return (T) meterRecords;
}
break;
case CAL_SET:
rec_len = 249;
if (pageHeader.getRevision()<=2) { rec_len = 148; }
CalRecord[] calRecords = new CalRecord[numRec];
for (int i = 0; i < numRec; i++) {
int startIdx = HEADER_LEN + rec_len * i;
calRecords[i] = new CalRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1));
}
if(parsedPageReceiver != null) {
Observable.just((T) calRecords).subscribe(parsedPageReceiver);
} else {
return (T) calRecords;
}
break;
default:
break;
}
Observable.just((T) null).subscribe(parsedPageReceiver);
return (T) null;
}
}

View File

@@ -0,0 +1,36 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import java.util.Arrays;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class ReadPacket {
private int command;
private byte[] data;
private byte[] crc_calc;
private byte[] crc;
private int OFFSET_CMD = 3;
private int OFFSET_DATA = 4;
private int CRC_LEN = 2;
public ReadPacket(byte[] readPacket) {
this.command = readPacket[OFFSET_CMD];
this.data = Arrays.copyOfRange(readPacket, OFFSET_DATA, readPacket.length - CRC_LEN);
this.crc = Arrays.copyOfRange(readPacket, readPacket.length - CRC_LEN, readPacket.length);
this.crc_calc=CRC16.calculate(readPacket, 0, readPacket.length - 2);
if (!Arrays.equals(this.crc, this.crc_calc)) {
throw new CRCFailRuntimeException("CRC check failed: " + Utils.bytesToHex(this.crc) + " vs " + Utils.bytesToHex(this.crc_calc));
}
}
public int getCommand() {
return command;
}
public byte[] getData() {
return data;
}
}

View File

@@ -0,0 +1,346 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbManager;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import com.eveningoutpost.dexdrip.Models.JoH;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.CalRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GlucoseDataSet;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.MeterRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.CdcAcmSerialDriver;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.ProbeTable;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialDriver;
import com.eveningoutpost.dexdrip.ImportedLibraries.usbserial.driver.UsbSerialProber;
import com.eveningoutpost.dexdrip.Models.Calibration;
import org.json.JSONArray;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
/**
* An {@link IntentService} subclass for handling asynchronous CGM Receiver downloads and cloud uploads
* requests in a service on a separate handler thread.
*/
public class SyncingService extends IntentService {
// Action for intent
private static final String ACTION_SYNC = "com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.action.SYNC";
private static final String ACTION_CALIBRATION_CHECKIN = "com.eveningoutpost.dexdrip.CalibrationCheckInActivity";
// Parameters for intent
private static final String SYNC_PERIOD = "com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.extra.SYNC_PERIOD";
// Response to broadcast to activity
public static final String RESPONSE_SGV = "mySGV";
public static final String RESPONSE_TREND = "myTrend";
public static final String RESPONSE_TIMESTAMP = "myTimestamp";
public static final String RESPONSE_NEXT_UPLOAD_TIME = "myUploadTime";
public static final String RESPONSE_UPLOAD_STATUS = "myUploadStatus";
public static final String RESPONSE_DISPLAY_TIME = "myDisplayTime";
public static final String RESPONSE_JSON = "myJSON";
public static final String RESPONSE_BAT = "myBatLvl";
private final String TAG = SyncingService.class.getSimpleName();
private Context mContext;
private UsbManager mUsbManager;
private UsbSerialDriver mSerialDevice;
private UsbDevice dexcom;
private UsbDeviceConnection mConnection;
// Constants
private final int TIME_SYNC_OFFSET = 10000;
public static final int MIN_SYNC_PAGES = 2;
public static final int GAP_SYNC_PAGES = 20;
/**
* Starts this service to perform action Single Sync with the given parameters. If
* the service is already performing a task this action will be queued.
*
* @see IntentService
*/
public static void startActionSingleSync(Context context, int numOfPages) {
Intent intent = new Intent(context, SyncingService.class);
intent.setAction(ACTION_SYNC);
intent.putExtra(SYNC_PERIOD, numOfPages);
context.startService(intent);
}
public static void startActionCalibrationCheckin(Context context) {
Intent intent = new Intent(context, SyncingService.class);
intent.setAction(ACTION_CALIBRATION_CHECKIN);
context.startService(intent);
}
public SyncingService() {
super("SyncingService");
}
@Override
protected void onHandleIntent(Intent intent) {
mContext = getApplicationContext();
if (intent != null) {
final String action = intent.getAction();
if (ACTION_SYNC.equals(action)) {
final int param1 = intent.getIntExtra(SYNC_PERIOD, 1);
handleActionSync(param1);
} else if (ACTION_CALIBRATION_CHECKIN.equals(action)) {
Log.i("CALIBRATION-CHECK-IN: ", "Beginning check in process");
performCalibrationCheckin();
}
}
}
/**
* Handle action Sync in the provided background thread with the provided
* parameters.
*/
private void performCalibrationCheckin(){
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NSDownload");
wl.acquire();
try {
Log.i("CALIBRATION-CHECK-IN: ", "Wake Lock Acquired");
if (acquireSerialDevice()) {
try {
ReadData readData = new ReadData(mSerialDevice, mConnection, dexcom);
// ReadData readData = new ReadData(mSerialDevice);
CalRecord[] calRecords = readData.getRecentCalRecords();
Log.i("CALIBRATION-CHECK-IN: ", "Found " + calRecords.length + " Records!");
save_most_recent_cal_record(calRecords);
} catch (Exception e) {
Log.wtf("Unhandled exception caught", e);
} finally {
// Close serial
try {
mSerialDevice.getPorts().get(0).close();
} catch (IOException e) {
Log.e(TAG, "Unable to close", e);
}
}
} else {
Log.w("CALIBRATION-CHECK-IN: ", "Failed to acquire serial device");
}
} finally {
JoH.releaseWakeLock(wl);
}
}
private void handleActionSync(int numOfPages) {
boolean broadcastSent = false;
PowerManager pm = (PowerManager) getApplicationContext().getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "NSDownload");
wl.acquire();
try {
sync(numOfPages);
} finally {
wl.release();
}
}
private void sync(int numOfPages) {
boolean broadcastSent;
if (acquireSerialDevice()) {
try {
ReadData readData = new ReadData(mSerialDevice);
// TODO: need to check if numOfPages if valid on ReadData side
EGVRecord[] recentRecords = readData.getRecentEGVsPages(numOfPages);
MeterRecord[] meterRecords = readData.getRecentMeterRecords();
// TODO: need to check if numOfPages if valid on ReadData side
SensorRecord[] sensorRecords = readData.getRecentSensorRecords(numOfPages);
GlucoseDataSet[] glucoseDataSets = Utils.mergeGlucoseDataRecords(recentRecords, sensorRecords);
// FIXME: This is a workaround for the new Dexcom AP which seems to have a new format
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
CalRecord[] calRecords = new CalRecord[1];
if (prefs.getBoolean("cloud_cal_data", false)) {
calRecords = readData.getRecentCalRecords();
}
long timeSinceLastRecord = readData.getTimeSinceEGVRecord(recentRecords[recentRecords.length - 1]);
// TODO: determine if the logic here is correct. I suspect it assumes the last record was less than 5
// minutes ago. If a reading is skipped and the device is plugged in then nextUploadTime will be
// set to a negative number. This situation will eventually correct itself.
long nextUploadTime = (1000 * 60 * 5) - (timeSinceLastRecord * (1000));
long displayTime = readData.readDisplayTime().getTime();
// FIXME: Device seems to flake out on battery level reads. Removing for now.
// int batLevel = readData.readBatteryLevel();
int batLevel = 100;
// convert into json for d3 plot
JSONArray array = new JSONArray();
for (int i = 0; i < recentRecords.length; i++) array.put(recentRecords[i].toJSON());
EGVRecord recentEGV = recentRecords[recentRecords.length - 1];
// broadcastSGVToUI(recentEGV, uploadStatus, nextUploadTime + TIME_SYNC_OFFSET,
// displayTime, array ,batLevel);
broadcastSent=true;
} catch (ArrayIndexOutOfBoundsException e) {
Log.wtf("Unable to read from the dexcom, maybe it will work next time", e);
} catch (NegativeArraySizeException e) {
Log.wtf("Negative array exception from receiver", e);
} catch (IndexOutOfBoundsException e) {
Log.wtf("IndexOutOfBounds exception from receiver", e);
} catch (CRCFailRuntimeException e){
// FIXME: may consider localizing this catch at a lower level (like ReadData) so that
// if the CRC check fails on one type of record we can capture the values if it
// doesn't fail on other types of records. This means we'd need to broadcast back
// partial results to the UI. Adding it to a lower level could make the ReadData class
// more difficult to maintain - needs discussion.
Log.wtf("CRC failed", e);
} catch (Exception e) {
Log.wtf("Unhandled exception caught", e);
} finally {
// Close serial
try {
mSerialDevice.getPorts().get(0).close();
} catch (IOException e) {
Log.e(TAG, "Unable to close", e);
}
}
}
// if (!broadcastSent) broadcastSGVToUI();
}
private void save_most_recent_cal_record(CalRecord[] calRecords) {
int size = calRecords.length;
Calibration.create(calRecords,getApplicationContext(), false, 0);
}
private boolean acquireSerialDevice() {
UsbDevice found_device = findDexcom();
if (mUsbManager == null) {
Log.w("CALIBRATION-CHECK-IN: ", "USB manager is null");
return false;
}
if (dexcom == null) {
Log.e(TAG, "dex device == null");
return false;
}
if( mUsbManager.hasPermission(dexcom)) { // the system is allowing us to poke around this device
ProbeTable customTable = new ProbeTable(); // From the USB library...
customTable.addProduct(0x22A3, 0x0047, CdcAcmSerialDriver.class); // ...Specify the Vendor ID and Product ID
UsbSerialProber prober = new UsbSerialProber(customTable); // Probe the device with the custom values
List<UsbSerialDriver> drivers = prober.findAllDrivers(mUsbManager); // let's go through the list
Iterator<UsbSerialDriver> foo = drivers.iterator(); // Invalid Return code
while (foo.hasNext()) { // let's loop through
UsbSerialDriver driver = foo.next(); // set fooDriver to the next available driver
if (driver != null) {
UsbDeviceConnection connection = mUsbManager.openDevice(driver.getDevice());
if (connection != null) {
mSerialDevice = driver;
mConnection = connection;
Log.i("CALIBRATION-CHECK-IN: ", "CONNECTEDDDD!!");
return true;
}
} else {
Log.w("CALIBRATION-CHECK-IN: ", "Driver was no good");
}
}
Log.w("CALIBRATION-CHECK-IN: ", "No usable drivers found");
} else {
Log.w("CALIBRATION-CHECK-IN: ", "You dont have permissions for that dexcom!!");
}
return false;
}
static public boolean isG4Connected(Context c){
UsbManager manager = (UsbManager) c.getSystemService(Context.USB_SERVICE);
HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
Log.i("USB DEVICES = ", deviceList.toString());
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
Log.i("USB DEVICES = ", String.valueOf(deviceList.size()));
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getVendorId() == 8867 && device.getProductId() == 71
&& device.getDeviceClass() == 2 && device.getDeviceSubclass() ==0
&& device.getDeviceProtocol() == 0){
Log.i("CALIBRATION-CHECK-IN: ", "Dexcom Found!");
return true;
}
}
return false;
}
public UsbDevice findDexcom() {
Log.i("CALIBRATION-CHECK-IN: ", "Searching for dexcom");
mUsbManager = (UsbManager) getApplicationContext().getSystemService(Context.USB_SERVICE);
Log.i("USB MANAGER = ", mUsbManager.toString());
HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
Log.i("USB DEVICES = ", deviceList.toString());
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
Log.i("USB DEVICES = ", String.valueOf(deviceList.size()));
while(deviceIterator.hasNext()){
UsbDevice device = deviceIterator.next();
if (device.getVendorId() == 8867 && device.getProductId() == 71
&& device.getDeviceClass() == 2 && device.getDeviceSubclass() ==0
&& device.getDeviceProtocol() == 0){
dexcom = device;
Log.i("CALIBRATION-CHECK-IN: ", "Dexcom Found!");
return device;
} else {
Log.w("CALIBRATION-CHECK-IN: ", "that was not a dexcom (I dont think)");
}
}
return null;
}
private void broadcastSGVToUI(EGVRecord egvRecord, boolean uploadStatus,
long nextUploadTime, long displayTime,
JSONArray json, int batLvl) {
Log.d(TAG, "Current EGV: " + egvRecord.getBGValue());
Intent broadcastIntent = new Intent();
// broadcastIntent.setAction(MainActivity.CGMStatusReceiver.PROCESS_RESPONSE);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
broadcastIntent.putExtra(RESPONSE_SGV, egvRecord.getBGValue());
broadcastIntent.putExtra(RESPONSE_TREND, egvRecord.getTrend().getID());
broadcastIntent.putExtra(RESPONSE_TIMESTAMP, egvRecord.getDisplayTime().getTime());
broadcastIntent.putExtra(RESPONSE_NEXT_UPLOAD_TIME, nextUploadTime);
broadcastIntent.putExtra(RESPONSE_UPLOAD_STATUS, uploadStatus);
broadcastIntent.putExtra(RESPONSE_DISPLAY_TIME, displayTime);
if (json!=null)
broadcastIntent.putExtra(RESPONSE_JSON, json.toString());
broadcastIntent.putExtra(RESPONSE_BAT, batLvl);
sendBroadcast(broadcastIntent);
}
private void broadcastSGVToUI() {
EGVRecord record=new EGVRecord(-1, Dex_Constants.TREND_ARROW_VALUES.NONE,new Date(),new Date());
broadcastSGVToUI(record,false, (long) (1000 * 60 * 5) + TIME_SYNC_OFFSET, new Date().getTime(), null, 0);
}
}

View File

@@ -0,0 +1,75 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.EGVRecord;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.GlucoseDataSet;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records.SensorRecord;
import java.util.Date;
import java.util.TimeZone;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class Utils {
public static Date receiverTimeToDate(long delta) {
int currentTZOffset = TimeZone.getDefault().getRawOffset();
long epochMS = 1230768000000L; // Jan 01, 2009 00:00 in UTC
long milliseconds = epochMS - currentTZOffset;
long timeAdd = milliseconds + (1000L * delta);
TimeZone tz = TimeZone.getDefault();
if (tz.inDaylightTime(new Date())) timeAdd = timeAdd - (1000 * 60 * 60);
return new Date(timeAdd);
}
public static String getTimeString(long timeDeltaMS) {
long minutes = (timeDeltaMS / 1000) / 60;
long hours = minutes / 60;
long days = hours / 24;
long weeks = days / 7;
minutes= minutes - hours * 60;
hours = hours - days * 24;
days= days - weeks * 7;
String timeAgoString = "";
if (weeks > 0) {
timeAgoString += weeks + " weeks ";
}
if (days > 0) {
timeAgoString += days + " days ";
}
if (hours > 0) {
timeAgoString += hours + " hours ";
}
if (minutes >= 0) {
timeAgoString += minutes + " min ";
}
return (timeAgoString.equals("") ? "--" : timeAgoString + "ago");
}
public static GlucoseDataSet[] mergeGlucoseDataRecords(EGVRecord[] egvRecords,
SensorRecord[] sensorRecords) {
int egvLength = egvRecords.length;
int sensorLength = sensorRecords.length;
int smallerLength = egvLength < sensorLength ? egvLength : sensorLength;
GlucoseDataSet[] glucoseDataSets = new GlucoseDataSet[smallerLength];
for (int i = 1; i <= smallerLength; i++) {
glucoseDataSets[smallerLength - i] = new GlucoseDataSet(egvRecords[egvLength - i], sensorRecords[sensorLength - i]);
}
return glucoseDataSets;
}
public static String bytesToHex(byte[] bytes) {
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[bytes.length * 3];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 3] = hexArray[v >>> 4];
hexChars[j * 3 + 1] = hexArray[v & 0x0F];
hexChars[j * 3 + 2] = " ".toCharArray()[0];
}
return new String(hexChars);
}
}

View File

@@ -0,0 +1,72 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CalRecord extends GenericTimestampRecord {
private static final String TAG = CalRecord.class.getSimpleName();
private double slope;
private double intercept;
private double scale;
private int[] unk = new int[3];
private double decay;
private int numRecords;
private CalSubrecord[] calSubrecords = new CalSubrecord[12];
private int SUB_LEN = 17;
public CalRecord(byte[] packet) {
super(packet);
slope = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(8);
intercept = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(16);
scale = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(24);
unk[0] = packet[32];
unk[1] = packet[33];
unk[2] = packet[34];
decay = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getDouble(35);
numRecords = packet[43];
long displayTimeOffset = (getDisplayTime().getTime() - getSystemTime().getTime()) / (1000);
int start = 44;
for (int i = 0; i < numRecords; i++) {
Log.d("CalDebug","Loop #"+i);
byte[] temp = new byte[SUB_LEN];
System.arraycopy(packet, start, temp, 0, temp.length);
calSubrecords[i] = new CalSubrecord(temp, displayTimeOffset);
start += SUB_LEN;
}
Log.d("ShareTest", "slope: " + slope + " intercept: " + intercept);
}
public double getSlope() {
return slope;
}
public double getIntercept() {
return intercept;
}
public double getScale() {
return scale;
}
public int[] getUnk() {
return unk;
}
public double getDecay() {
return decay;
}
public int getNumRecords() {
return numRecords;
}
public CalSubrecord[] getCalSubrecords() {
return calSubrecords;
}
}

View File

@@ -0,0 +1,52 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class CalSubrecord {
private static final String TAG = CalSubrecord.class.getSimpleName();
private Date dateEntered;
private int calBGL;
private int calRaw;
private Date dateApplied;
private byte unk;
public CalSubrecord(byte[] packet, long displayTimeOffset) {
int delta = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt();
dateEntered = Utils.receiverTimeToDate(delta + displayTimeOffset);
calBGL = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4);
calRaw = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(8);
delta = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(12);
dateApplied = Utils.receiverTimeToDate(delta + displayTimeOffset);
unk = packet[16];
}
public Date getDateEntered() {
return dateEntered;
}
public int getCalBGL() {
return calBGL;
}
public int getCalRaw() {
return calRaw;
}
public Date getDateApplied() {
return dateApplied;
}
public byte getUnk() {
return unk;
}
}

View File

@@ -0,0 +1,58 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Dex_Constants;
import org.json.JSONException;
import org.json.JSONObject;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class EGVRecord extends GenericTimestampRecord {
private int bGValue;
private int noise;
private Dex_Constants.TREND_ARROW_VALUES trend;
public EGVRecord(byte[] packet) {
// system_time (UInt), display_time (UInt), glucose (UShort), trend_arrow (Byte), crc (UShort))
super(packet);
bGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8) & Dex_Constants.EGV_VALUE_MASK;
byte trendAndNoise = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).get(10);
int trendValue = trendAndNoise & Dex_Constants.EGV_TREND_ARROW_MASK;
byte noiseValue = (byte) ((trendAndNoise & Dex_Constants.EGV_NOISE_MASK) >> 4);
trend = Dex_Constants.TREND_ARROW_VALUES.values()[trendValue];
noise = noiseValue;
}
public EGVRecord(int bGValue, Dex_Constants.TREND_ARROW_VALUES trend, Date displayTime, Date systemTime){
super(displayTime, systemTime);
this.bGValue=bGValue;
this.trend=trend;
}
public String noiseValue() { return String.valueOf(noise); }
public int getBGValue() {
return bGValue;
}
public Dex_Constants.TREND_ARROW_VALUES getTrend() {
return trend;
}
public JSONObject toJSON() {
JSONObject obj = new JSONObject();
try {
obj.put("sgv", getBGValue());
obj.put("date", getDisplayTimeSeconds());
} catch (JSONException e) {
e.printStackTrace();
}
return obj;
}
}

View File

@@ -0,0 +1,48 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class GenericTimestampRecord {
protected final int OFFSET_SYS_TIME = 0;
protected final int OFFSET_DISPLAY_TIME = 4;
protected Date systemTime;
protected int systemTimeSeconds;
protected Date displayTime;
public GenericTimestampRecord(byte[] packet) {
systemTimeSeconds = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_SYS_TIME);
systemTime = Utils.receiverTimeToDate(systemTimeSeconds);
int dt = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_DISPLAY_TIME);
displayTime = Utils.receiverTimeToDate(dt);
}
public GenericTimestampRecord(Date displayTime, Date systemTime){
this.displayTime=displayTime;
this.systemTime=systemTime;
}
public Date getSystemTime() {
return systemTime;
}
public int getSystemTimeSeconds() {
return systemTimeSeconds;
}
public Date getDisplayTime() {
return displayTime;
}
public long getDisplayTimeSeconds() {
return displayTime.getTime();
}
}

View File

@@ -0,0 +1,48 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.Serializable;
import java.io.StringReader;
import java.util.Arrays;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class GenericXMLRecord extends GenericTimestampRecord {
int XML_START = 8;
int XML_END = 241;
private final String TAG = GenericXMLRecord.class.getSimpleName();
private Element xmlElement;
public GenericXMLRecord(byte[] packet) {
super(packet);
Document document;
// TODO: it would be best if we could just remove /x00 characters and read till end
String xml = new String(Arrays.copyOfRange(packet, XML_START, XML_END));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
document = builder.parse(new InputSource(new StringReader(xml)));
xmlElement = document.getDocumentElement();
} catch (Exception e) {
Log.e(TAG, "Unable to build xml element", e);
}
}
// example: String sn = getXmlElement().getAttribute("SerialNumber");
public Element getXmlElement() {
return xmlElement;
}
}

View File

@@ -0,0 +1,63 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Dex_Constants;
import java.util.Date;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class GlucoseDataSet {
private Date systemTime;
private Date displayTime;
private int bGValue;
private Dex_Constants.TREND_ARROW_VALUES trend;
private long unfiltered;
private long filtered;
private int rssi;
public GlucoseDataSet(EGVRecord egvRecord, SensorRecord sensorRecord) {
// TODO check times match between record
systemTime = egvRecord.getSystemTime();
displayTime = egvRecord.getDisplayTime();
bGValue = egvRecord.getBGValue();
trend = egvRecord.getTrend();
unfiltered = sensorRecord.getUnfiltered();
filtered = sensorRecord.getFiltered();
rssi = sensorRecord.getRSSI();
}
public Date getSystemTime() {
return systemTime;
}
public Date getDisplayTime() {
return displayTime;
}
public int getBGValue() {
return bGValue;
}
public Dex_Constants.TREND_ARROW_VALUES getTrend() {
return trend;
}
public String getTrendSymbol() {
return trend.Symbol();
}
public long getUnfiltered() {
return unfiltered;
}
public long getFiltered() {
return filtered;
}
public int getRssi() {
return rssi;
}
}

View File

@@ -0,0 +1,28 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class MeterRecord extends GenericTimestampRecord {
private int meterBG;
private int meterTime;
public MeterRecord(byte[] packet) {
super(packet);
meterBG = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8);
meterTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(10);
}
public int getMeterBG() {
return meterBG;
}
public int getMeterTime() {
return meterTime;
}
}

View File

@@ -0,0 +1,89 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.CRC16;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.CRCFailRuntimeException;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Dex_Constants;
import com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.Utils;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class PageHeader {
protected final int HEADER_SIZE=28;
protected final int FIRSTRECORDINDEX_OFFSET=0;
protected final int NUMRECS_OFFSET=4;
protected final int RECTYPE_OFFSET=8;
protected final int REV_OFFSET=9;
protected final int PAGENUMBER_OFFSET=10;
protected final int RESERVED2_OFFSET=14;
protected final int RESERVED3_OFFSET=18;
protected final int RESERVED4_OFFSET=22;
protected int firstRecordIndex;
protected int numOfRecords;
protected Dex_Constants.RECORD_TYPES recordType;
protected byte revision;
protected int pageNumber;
protected int reserved2;
protected int reserved3;
protected int reserved4;
protected byte[] crc=new byte[2];
public PageHeader(byte[] packet) {
Log.d("ShareTest", "Header Packet Data Length: " + packet.length);
firstRecordIndex = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(FIRSTRECORDINDEX_OFFSET);
numOfRecords = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(NUMRECS_OFFSET);
recordType = Dex_Constants.RECORD_TYPES.values()[packet[RECTYPE_OFFSET]];
revision = packet[REV_OFFSET];
pageNumber = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(PAGENUMBER_OFFSET);
reserved2 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED2_OFFSET);
reserved3 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED3_OFFSET);
reserved4 = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(RESERVED4_OFFSET);
System.arraycopy(packet,HEADER_SIZE- Dex_Constants.CRC_LEN,crc,0, Dex_Constants.CRC_LEN);
byte[] crc_calc = CRC16.calculate(packet,0,HEADER_SIZE - Dex_Constants.CRC_LEN);
if (!Arrays.equals(this.crc, crc_calc)) {
throw new CRCFailRuntimeException("CRC check failed: " + Utils.bytesToHex(this.crc) + " vs " + Utils.bytesToHex(crc_calc));
}
}
public byte getRevision() {
return revision;
}
public Dex_Constants.RECORD_TYPES getRecordType() {
return recordType;
}
public int getFirstRecordIndex() {
return firstRecordIndex;
}
public int getNumOfRecords() {
return numOfRecords;
}
public int getPageNumber() {
return pageNumber;
}
public int getReserved2() {
return reserved2;
}
public int getReserved3() {
return reserved3;
}
public int getReserved4() {
return reserved4;
}
}

View File

@@ -0,0 +1,42 @@
package com.eveningoutpost.dexdrip.ImportedLibraries.dexcom.records;
import com.eveningoutpost.dexdrip.Models.UserError.Log;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
// This code and this particular library are from the NightScout android uploader
// Check them out here: https://github.com/nightscout/android-uploader
// Some of this code may have been modified for use in this project
public class SensorRecord extends GenericTimestampRecord {
private int unfiltered;
private int filtered;
private int rssi;
private int OFFSET_UNFILTERED = 8;
private int OFFSET_FILTERED = 12;
private int OFFSET_RSSI = 16;
public SensorRecord(byte[] packet) {
super(packet);
unfiltered = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_UNFILTERED);
filtered = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_FILTERED);
byte [] usRSSI = new byte[]{packet[17],packet[16]};
rssi = usRSSI[0] << 8 | usRSSI[1];
//rssi = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(OFFSET_RSSI);
Log.d("ShareTest", "filtered: " + filtered + " unfiltered: " + unfiltered);
}
public long getUnfiltered() {
return unfiltered;
}
public long getFiltered() {
return filtered;
}
public int getRSSI() {
return rssi;
}
}