From 67ad94b593018ce30560a74693b52b71798b26f5 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Fri, 18 Jul 2014 00:16:12 -0700 Subject: [PATCH 001/212] Adding Constant class for Receiver. --- .../nightscout/android/dexcom/Constants.java | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/Constants.java diff --git a/src/com/nightscout/android/dexcom/Constants.java b/src/com/nightscout/android/dexcom/Constants.java new file mode 100644 index 00000000..07968da2 --- /dev/null +++ b/src/com/nightscout/android/dexcom/Constants.java @@ -0,0 +1,93 @@ +package com.nightscout.android.dexcom; + +public class Constants { + + public final static int DEXCOM_G4_USB_VENDOR = 0x22a3; + public final static int DEXCOM_G4_USB_PRODUCT = 0x0047; + + 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 String[] BATTERY_STATES = { + "NONE", + "CHARGING", + "NOT_CHARGING", + "NTC_FAULT", + "BAD_BATTERY" + }; + + public final static String[] 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 final static String[] TREND_ARROW_VALUES = { + "NONE", + "DOUBLE_UP", + "SINGLE_UP", + "45_UP", + "FLAT", + "45_DOWN", + "SINGLE_DOWN", + "DOUBLE_DOWN", + "NOT_COMPUTABLE", + "OUT_OF_RANGE" + }; +} From d0ea72cdd9e3b0bd549fafad1896fd2354b02f7c Mon Sep 17 00:00:00 2001 From: saercnap Date: Mon, 21 Jul 2014 22:51:57 -0700 Subject: [PATCH 002/212] Start refactoring DexcomReader Use Constants and a PacketWriter --- .../nightscout/android/dexcom/Constants.java | 105 +++++++----- .../android/dexcom/DexcomPacket.java | 86 ++++++++++ .../android/dexcom/DexcomReader.java | 162 +++--------------- 3 files changed, 179 insertions(+), 174 deletions(-) create mode 100644 src/com/nightscout/android/dexcom/DexcomPacket.java diff --git a/src/com/nightscout/android/dexcom/Constants.java b/src/com/nightscout/android/dexcom/Constants.java index 07968da2..ae93a614 100644 --- a/src/com/nightscout/android/dexcom/Constants.java +++ b/src/com/nightscout/android/dexcom/Constants.java @@ -2,9 +2,6 @@ public class Constants { - public final static int DEXCOM_G4_USB_VENDOR = 0x22a3; - public final static int DEXCOM_G4_USB_PRODUCT = 0x0047; - public final static int NULL = 0; public final static int ACK = 1; public final static int NAK = 2; @@ -48,46 +45,76 @@ public class Constants { 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 String EPOCH = "01-01-2009"; + + 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, + DOUBLE_UP("\u21C8", "DoubleUp"), + SINGLE_UP("\u2191", "SingleUp"), + UP_45("\u2197", "FortyFifeUp"), + FLAT("\u2192", "Flat"), + DOWN_45("\u2198", "FortyFiveDown"), + SINGLE_DOWN("\u2193", "SingleDown"), + DOUBLE_DOWN("\u21CA", "DoubleDown"), + NOT_COMPUTABLE, + OUT_OF_RANGE; + + private String arrowSymbol; + private String trendName; + + TREND_ARROW_VALUES(String a, String t) { + arrowSymbol = a; + trendName = t; + } + + TREND_ARROW_VALUES() { + this(null, null); + } + + public String Symbol() { + if (arrowSymbol == null) { + return "\u2194"; + } else { + return arrowSymbol; + } + } - public final static String[] BATTERY_STATES = { - "NONE", - "CHARGING", - "NOT_CHARGING", - "NTC_FAULT", - "BAD_BATTERY" - }; + public String friendlyTrendName() { + if (trendName == null) { + return this.name().replace("_", " "); + } else { + return this.trendName; + } + } - public final static String[] 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 final static String[] TREND_ARROW_VALUES = { - "NONE", - "DOUBLE_UP", - "SINGLE_UP", - "45_UP", - "FLAT", - "45_DOWN", - "SINGLE_DOWN", - "DOUBLE_DOWN", - "NOT_COMPUTABLE", - "OUT_OF_RANGE" - }; } diff --git a/src/com/nightscout/android/dexcom/DexcomPacket.java b/src/com/nightscout/android/dexcom/DexcomPacket.java new file mode 100644 index 00000000..9fa53f5b --- /dev/null +++ b/src/com/nightscout/android/dexcom/DexcomPacket.java @@ -0,0 +1,86 @@ +package com.nightscout.android.dexcom; + +import android.util.Log; + +import java.util.ArrayList; +import java.util.Arrays; + + +public class DexcomPacket { + 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_CMD = 3; + public static final int OFFSET_PAYLOAD = 4; + private static final String TAG = DexcomPacket.class.getSimpleName(); + private ArrayList packet; + private int command; + private ArrayList payload; + + public DexcomPacket(int command) { + this.packet = new ArrayList(); + this.command = command; + packet.add(SOF); + setLength(); + packet.add((byte) 0); + packet.add((byte) command); + } + + public static short calculateCRC16(byte[] buff, int start, int end) { + + int crc = 0; + for (int i = start; i < end; i++) { + + crc = ((crc >>> 8) | (crc << 8)) & 0xffff; + crc ^= (buff[i] & 0xff); + crc ^= ((crc & 0xff) >> 4); + crc ^= (crc << 12) & 0xffff; + crc ^= ((crc & 0xFF) << 5) & 0xffff; + + } + crc &= 0xffff; + return (short) crc; + + } + + private void setLength() { + byte packetSize = (byte) Math.max(this.packet.size() + 2, MIN_LEN); + if (this.packet.size() < 2) { + packet.add(packetSize); + } else { + packet.set(1, packetSize); + } + } + + private void setCRC16() { + short crc16 = calculateCRC16(bytes(), 0, this.packet.size()); + this.packet.add((byte) (crc16 & 0xff)); + this.packet.add((byte) ((crc16 >> 8) & 0xff)); + } + + private byte[] bytes() { + 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 byte[] Compose() { + setLength(); + setCRC16(); + if (this.payload != null) { + this.packet.addAll(this.payload); + } + return this.bytes(); + } + + public byte[] Compose(ArrayList payload) { + this.payload = payload; + return Compose(); + } + +} diff --git a/src/com/nightscout/android/dexcom/DexcomReader.java b/src/com/nightscout/android/dexcom/DexcomReader.java index f0259af2..030978d9 100644 --- a/src/com/nightscout/android/dexcom/DexcomReader.java +++ b/src/com/nightscout/android/dexcom/DexcomReader.java @@ -6,9 +6,14 @@ import android.util.Log; import com.nightscout.android.dexcom.USB.UsbSerialDriver; import com.nightscout.android.dexcom.USB.UsbSerialProber; +import com.nightscout.android.dexcom.Constants; +import com.nightscout.android.dexcom.DexcomPacket; import java.io.*; import java.nio.ByteBuffer; +import java.sql.Array; +import java.sql.ResultSet; +import java.sql.SQLException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; @@ -44,10 +49,6 @@ public void readFromReceiver(Context context, int pageOffset) { // make first read public mRD = mostRecentData; - - //save them to the android file system for later access - //TODO: should be removed? - writeLocalCSV(mostRecentData, context); } //Not being used, but this is a nice to have if we want to kill the receiver, etc from @@ -59,15 +60,9 @@ public void shutDownReceiver(Context context){ if (mSerialDevice != null) { try { mSerialDevice.open(); - // EGVData page range read command - byte[] resetPacket = new byte[6]; - resetPacket[0] = 0x01; - resetPacket[1] = 0x06; - resetPacket[3] = 0x2e; - resetPacket[4] = (byte) 0xb8; - resetPacket[5] = (byte) 0x01; + DexcomPacket p = new DexcomPacket(Constants.SHUTDOWN_RECEIVER); try { - mSerialDevice.write(resetPacket, 200); + mSerialDevice.write(p.Compose(), 200); } catch (IOException e) { Log.e(TAG, "unable to write to serial device", e); } @@ -103,17 +98,11 @@ public Date getDisplayTime() { } private int getSystemTime() { - - byte[] readSystemTime = new byte[6]; - readSystemTime[0] = 0x01; - readSystemTime[1] = 0x06; - readSystemTime[2] = 0x00; - readSystemTime[3] = 0x22; - readSystemTime[4] = 0x34; - readSystemTime[5] = (byte)0xc0; + DexcomPacket p = new DexcomPacket(Constants.READ_SYSTEM_TIME); try { - mSerialDevice.write(readSystemTime, 200); + mSerialDevice.write(p.Compose(), 200); + } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } @@ -136,17 +125,10 @@ private int getSystemTime() { } private int getDisplayTimeOffset() { - - byte[] readDisplayTimeOffset = new byte[6]; - readDisplayTimeOffset[0] = 0x01; - readDisplayTimeOffset[1] = 0x06; - readDisplayTimeOffset[2] = 0x00; - readDisplayTimeOffset[3] = 0x1d; - readDisplayTimeOffset[4] = (byte)0x88; - readDisplayTimeOffset[5] = 0x07; + DexcomPacket p = new DexcomPacket(Constants.READ_DISPLAY_TIME_OFFSET); try { - mSerialDevice.write(readDisplayTimeOffset, 200); + mSerialDevice.write(p.Compose(), 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } @@ -180,9 +162,17 @@ private byte[] getEGVDataPageRange(){ readEGVDataPageRange[4] = 0x04; readEGVDataPageRange[5] = (byte)0x8b; readEGVDataPageRange[6] = (byte)0xb8; + DexcomPacket p = new DexcomPacket(Constants.READ_DATABASE_PAGE_RANGE); + ArrayList dat = new ArrayList(); + + dat.add((byte)Constants.RECORD_TYPES.EGV_DATA.ordinal()); + + byte[] z = p.Compose(dat); + + Log.i(TAG, (z == readEGVDataPageRange) + "ok?"); try { - rets[c++] = mSerialDevice.write(readEGVDataPageRange, 200); + rets[c++] = mSerialDevice.write(z, 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } @@ -310,62 +300,19 @@ private EGVRecord[] parseDatabasePages(byte[] databasePages) { Date display = new Date(timeAdd); byte trendArrow = (byte) (tempRecord[10] & (byte)15); - String trend = "Not Calculated"; - String trendA = "--X"; - - switch (trendArrow) { - - case (0): - trendA = "\u2194"; - trend = "NONE"; - break; - case (1): - trendA = "\u21C8"; - trend = "DoubleUp"; - break; - case (2): - trendA = "\u2191"; - trend = "SingleUp"; - break; - case (3): - trendA = "\u2197"; - trend = "FortyFiveUp"; - break; - case (4): - trendA = "\u2192"; - trend = "Flat"; - break; - case (5): - trendA = "\u2198"; - trend = "FortyFiveDown"; - break; - case (6): - trendA = "\u2193"; - trend = "SingleDown"; - break; - case (7): - trendA = "\u21CA"; - trend = "DoubleDown"; - break; - case (8): - trendA = "\u2194"; - trend = "NOT COMPUTABLE"; - break; - case (9): - trendA = "\u2194"; - trend = "RATE OUT OF RANGE"; - break; - } + + Constants.TREND_ARROW_VALUES arrow = Constants.TREND_ARROW_VALUES.values()[trendArrow]; + - this.trend = trend; + this.trend = arrow.friendlyTrendName(); this.displayTime = new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(display); this.bGValue = String.valueOf(bGValue); EGVRecord record = new EGVRecord(); record.setBGValue(this.bGValue); record.setDisplayTime(this.displayTime); - record.setTrend(this.trend); - record.setTrendArrow(trendA); + record.setTrend(arrow.friendlyTrendName()); + record.setTrendArrow(arrow.Symbol()); recordsToReturn[k++] = record; } @@ -374,40 +321,6 @@ private EGVRecord[] parseDatabasePages(byte[] databasePages) { } - //TODO: why are we writing CSV? - private void writeLocalCSV(EGVRecord[] mostRecentData, Context context) { - - //Write EGV Binary of last (most recent) data - try { - ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(context.getFilesDir(), "save.bin"))); //Select where you wish to save the file... - oos.writeObject(mostRecentData[mostRecentData.length - 1]); // write the class as an 'object' - oos.flush(); // flush the stream to insure all of the information was written to 'save.bin' - oos.close();// close the stream - } catch(Exception e) { - Log.e(TAG, "write to OutputStream failed", e); - } - - //Write CSV of EGV from last 4 pages - CSVWriter writer; - try { - - writer = new CSVWriter(new FileWriter(new File(context.getFilesDir(), "hayden.csv")),',', CSVWriter.NO_QUOTE_CHARACTER); - List data = new ArrayList(); - data.add(new String[] {"GlucoseValue","DisplayTime"}); - - for (int i = 0; i < mostRecentData.length; i++) - { - data.add(new String[] {mostRecentData[i].bGValue, mostRecentData[i].displayTime}); - } - - writer.writeAll(data); - - writer.close(); - } catch (IOException e) { - Log.e(TAG, "write to CSV failed", e); - } - } - //CRC methods public static int calculateCRC16 (byte [] buff, int start, int end) { @@ -439,27 +352,6 @@ public static int toInt(byte[] b, int flag) { } } - public static byte[] getBytes(int i, int flag) { - byte[] b = new byte[4]; - switch (flag) { - case 0: - b[0] = (byte) ((i >> 24) & 0xff); - b[1] = (byte) ((i >> 16) & 0xff); - b[2] = (byte) ((i >> 8) & 0xff); - b[3] = (byte) (i & 0xff); - break; - case 1: - b[3] = (byte) ((i >> 24) & 0xff); - b[2] = (byte) ((i >> 16) & 0xff); - b[1] = (byte) ((i >> 8) & 0xff); - b[0] = (byte) (i & 0xff); - break; - default: - break; - } - return b; - } - @Override protected Object doInBackground(UsbSerialDriver... params) { From 6789d2632f62d9101241dab421cc631077460398 Mon Sep 17 00:00:00 2001 From: saercnap Date: Tue, 22 Jul 2014 08:52:11 -0700 Subject: [PATCH 003/212] Start work on Generic reads --- .../android/dexcom/DexcomCommandPacket.java | 86 ++++++++++++++ .../android/dexcom/DexcomReader.java | 107 ++++++++++++++---- .../nightscout/android/dexcom/DexcomUtil.java | 11 ++ 3 files changed, 181 insertions(+), 23 deletions(-) create mode 100644 src/com/nightscout/android/dexcom/DexcomCommandPacket.java create mode 100644 src/com/nightscout/android/dexcom/DexcomUtil.java diff --git a/src/com/nightscout/android/dexcom/DexcomCommandPacket.java b/src/com/nightscout/android/dexcom/DexcomCommandPacket.java new file mode 100644 index 00000000..6a34896f --- /dev/null +++ b/src/com/nightscout/android/dexcom/DexcomCommandPacket.java @@ -0,0 +1,86 @@ +package com.nightscout.android.dexcom; + +import java.util.ArrayList; + + +public class DexcomCommandPacket { + 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_CMD = 3; + public static final int OFFSET_PAYLOAD = 4; + private static final String TAG = DexcomCommandPacket.class.getSimpleName(); + private ArrayList packet; + private int command; + private ArrayList payload; + + public DexcomCommandPacket(int command) { + this.command = command; + } + + private void resetPacket() { + packet = new ArrayList(); + packet.add(SOF); + setLength(); + packet.add((byte) 0); + packet.add((byte) command); + } + + public static short calculateCRC16(byte[] buff, int start, int end) { + + int crc = 0; + for (int i = start; i < end; i++) { + + crc = ((crc >>> 8) | (crc << 8)) & 0xffff; + crc ^= (buff[i] & 0xff); + crc ^= ((crc & 0xff) >> 4); + crc ^= (crc << 12) & 0xffff; + crc ^= ((crc & 0xFF) << 5) & 0xffff; + + } + crc &= 0xffff; + return (short) crc; + + } + + private void setLength() { + byte packetSize = (byte) Math.max(this.packet.size() + 2, MIN_LEN); + if (this.packet.size() < 2) { + packet.add(packetSize); + } else { + packet.set(1, packetSize); + } + } + + private void setCRC16() { + short crc16 = calculateCRC16(bytes(), 0, this.packet.size()); + this.packet.add((byte) (crc16 & 0xff)); + this.packet.add((byte) ((crc16 >> 8) & 0xff)); + } + + private byte[] bytes() { + 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 void setPayload(ArrayList payload) { + this.payload = payload; + } + + public byte[] Compose() { + resetPacket(); + if (this.payload != null) { + this.packet.addAll(this.payload); + } + setLength(); + setCRC16(); + return this.bytes(); + } + +} diff --git a/src/com/nightscout/android/dexcom/DexcomReader.java b/src/com/nightscout/android/dexcom/DexcomReader.java index 030978d9..099ac7be 100644 --- a/src/com/nightscout/android/dexcom/DexcomReader.java +++ b/src/com/nightscout/android/dexcom/DexcomReader.java @@ -6,14 +6,10 @@ import android.util.Log; import com.nightscout.android.dexcom.USB.UsbSerialDriver; import com.nightscout.android.dexcom.USB.UsbSerialProber; -import com.nightscout.android.dexcom.Constants; -import com.nightscout.android.dexcom.DexcomPacket; import java.io.*; import java.nio.ByteBuffer; -import java.sql.Array; -import java.sql.ResultSet; -import java.sql.SQLException; +import java.nio.ByteOrder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; @@ -60,7 +56,8 @@ public void shutDownReceiver(Context context){ if (mSerialDevice != null) { try { mSerialDevice.open(); - DexcomPacket p = new DexcomPacket(Constants.SHUTDOWN_RECEIVER); + mSerialDevice.setParameters(115200, 8, 0, 1); + DexcomCommandPacket p = new DexcomCommandPacket(Constants.SHUTDOWN_RECEIVER); try { mSerialDevice.write(p.Compose(), 200); } catch (IOException e) { @@ -98,7 +95,7 @@ public Date getDisplayTime() { } private int getSystemTime() { - DexcomPacket p = new DexcomPacket(Constants.READ_SYSTEM_TIME); + DexcomCommandPacket p = new DexcomCommandPacket(Constants.READ_SYSTEM_TIME); try { mSerialDevice.write(p.Compose(), 200); @@ -125,14 +122,20 @@ private int getSystemTime() { } private int getDisplayTimeOffset() { - DexcomPacket p = new DexcomPacket(Constants.READ_DISPLAY_TIME_OFFSET); + DexcomCommandPacket p = new DexcomCommandPacket(Constants.READ_DISPLAY_TIME_OFFSET); try { mSerialDevice.write(p.Compose(), 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } - +readPacket(); + Log.i(TAG, "JLKSDJFLKDSJFKDLSJFSKDLFJKLSD"); + try { + mSerialDevice.write(p.Compose(), 200); + } catch (IOException e) { + Log.e(TAG, "Unable to write to serial device", e); + } byte[] readData = new byte[256]; try { mSerialDevice.read(readData, 200); @@ -140,6 +143,9 @@ private int getDisplayTimeOffset() { Log.e(TAG, "Unable to read from serial device", e); } + for (int j=0; j dat = new ArrayList(); + Log.i(TAG, "Looking up page range for " + Constants.RECORD_TYPES.EGV_DATA.ordinal()); dat.add((byte)Constants.RECORD_TYPES.EGV_DATA.ordinal()); + p.setPayload(dat); - byte[] z = p.Compose(dat); - Log.i(TAG, (z == readEGVDataPageRange) + "ok?"); - try { - rets[c++] = mSerialDevice.write(z, 200); + rets[c++] = mSerialDevice.write(p.Compose(), 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } @@ -339,6 +336,70 @@ public static int calculateCRC16 (byte [] buff, int start, int end) { return crc; } + + public void readPacket() { + byte[] initialData = new byte[4]; + try { + Log.i(TAG, "Read: " + mSerialDevice.read(initialData, 20000)); + } catch (IOException e) { + Log.i(TAG, "Failed to read initial packet data"); + } + if (initialData[0] == (byte)1) { + + } else { + Log.i(TAG, "Invalid initial packet header!"); + } + for (int y = 0; y 6) { + int remainingRead = Math.abs(dataNumber - 8); + remainingData = new byte[remainingRead]; + try { + Log.i(TAG, "remaining read of " + remainingRead); + Log.i(TAG, "read " + mSerialDevice.read(remainingData, 20000)); + } catch (IOException e) { + Log.i(TAG, "Failed to read remaining packet data"); + } + } else { + remainingData = new byte[0]; + } + byte[] suffixArray = new byte[2]; + + try { + mSerialDevice.read(suffixArray, 20000); + } catch (IOException e) { + Log.i(TAG, "Failed to read suffix packet data"); + } + for (int i=0; i Date: Wed, 6 Aug 2014 12:17:51 -0700 Subject: [PATCH 004/212] Revert to old reader and plan on creating new. --- .../android/dexcom/DexcomReader.java | 263 +++++++++++------- 1 file changed, 155 insertions(+), 108 deletions(-) diff --git a/src/com/nightscout/android/dexcom/DexcomReader.java b/src/com/nightscout/android/dexcom/DexcomReader.java index 099ac7be..311e0b56 100644 --- a/src/com/nightscout/android/dexcom/DexcomReader.java +++ b/src/com/nightscout/android/dexcom/DexcomReader.java @@ -9,7 +9,6 @@ import java.io.*; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; @@ -45,6 +44,10 @@ public void readFromReceiver(Context context, int pageOffset) { // make first read public mRD = mostRecentData; + + //save them to the android file system for later access + //TODO: should be removed? + writeLocalCSV(mostRecentData, context); } //Not being used, but this is a nice to have if we want to kill the receiver, etc from @@ -56,10 +59,15 @@ public void shutDownReceiver(Context context){ if (mSerialDevice != null) { try { mSerialDevice.open(); - mSerialDevice.setParameters(115200, 8, 0, 1); - DexcomCommandPacket p = new DexcomCommandPacket(Constants.SHUTDOWN_RECEIVER); + // EGVData page range read command + byte[] resetPacket = new byte[6]; + resetPacket[0] = 0x01; + resetPacket[1] = 0x06; + resetPacket[3] = 0x2e; + resetPacket[4] = (byte) 0xb8; + resetPacket[5] = (byte) 0x01; try { - mSerialDevice.write(p.Compose(), 200); + mSerialDevice.write(resetPacket, 200); } catch (IOException e) { Log.e(TAG, "unable to write to serial device", e); } @@ -95,11 +103,17 @@ public Date getDisplayTime() { } private int getSystemTime() { - DexcomCommandPacket p = new DexcomCommandPacket(Constants.READ_SYSTEM_TIME); - try { - mSerialDevice.write(p.Compose(), 200); + byte[] readSystemTime = new byte[6]; + readSystemTime[0] = 0x01; + readSystemTime[1] = 0x06; + readSystemTime[2] = 0x00; + readSystemTime[3] = 0x22; + readSystemTime[4] = 0x34; + readSystemTime[5] = (byte)0xc0; + try { + mSerialDevice.write(readSystemTime, 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } @@ -122,20 +136,21 @@ private int getSystemTime() { } private int getDisplayTimeOffset() { - DexcomCommandPacket p = new DexcomCommandPacket(Constants.READ_DISPLAY_TIME_OFFSET); + + byte[] readDisplayTimeOffset = new byte[6]; + readDisplayTimeOffset[0] = 0x01; + readDisplayTimeOffset[1] = 0x06; + readDisplayTimeOffset[2] = 0x00; + readDisplayTimeOffset[3] = 0x1d; + readDisplayTimeOffset[4] = (byte)0x88; + readDisplayTimeOffset[5] = 0x07; try { - mSerialDevice.write(p.Compose(), 200); - } catch (IOException e) { - Log.e(TAG, "Unable to write to serial device", e); - } -readPacket(); - Log.i(TAG, "JLKSDJFLKDSJFKDLSJFSKDLFJKLSD"); - try { - mSerialDevice.write(p.Compose(), 200); + mSerialDevice.write(readDisplayTimeOffset, 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } + byte[] readData = new byte[256]; try { mSerialDevice.read(readData, 200); @@ -143,9 +158,6 @@ private int getDisplayTimeOffset() { Log.e(TAG, "Unable to read from serial device", e); } - for (int j=0; j dat = new ArrayList(); - - Log.i(TAG, "Looking up page range for " + Constants.RECORD_TYPES.EGV_DATA.ordinal()); - dat.add((byte)Constants.RECORD_TYPES.EGV_DATA.ordinal()); - p.setPayload(dat); - + //EGVData page range read command + byte[] readEGVDataPageRange = new byte[7]; + readEGVDataPageRange[0] = 0x01; + readEGVDataPageRange[1] = 0x07; + readEGVDataPageRange[3] = 0x10; + readEGVDataPageRange[4] = 0x04; + readEGVDataPageRange[5] = (byte)0x8b; + readEGVDataPageRange[6] = (byte)0xb8; try { - rets[c++] = mSerialDevice.write(p.Compose(), 200); + rets[c++] = mSerialDevice.write(readEGVDataPageRange, 200); } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } @@ -179,7 +192,7 @@ private byte[] getEGVDataPageRange(){ } catch (IOException e) { Log.e(TAG, "Unable to read from serial device", e); } - + return dexcomPageRange; } @@ -199,7 +212,7 @@ private byte[] getLastFourPages(byte [] dexcomPageRange, int pageOffset) ByteBuffer b = ByteBuffer.allocate(4); b.putInt(lastFour); byte[] result = b.array(); - + //Build get page (EGV) command byte [] getLastEGVPage = new byte[636]; getLastEGVPage[0] = 0x01; @@ -212,7 +225,7 @@ private byte[] getLastFourPages(byte [] dexcomPageRange, int pageOffset) getLastEGVPage[7] = result[1]; getLastEGVPage[8] = result[0]; getLastEGVPage[9] = 0x04; - + //Get checksum int getLastEGVCRC = calculateCRC16(getLastEGVPage, 0, 10); byte crcByte1 = (byte) (getLastEGVCRC & 0xff); @@ -226,7 +239,7 @@ private byte[] getLastFourPages(byte [] dexcomPageRange, int pageOffset) } catch (IOException e) { Log.e(TAG, "Unable to write to serial device", e); } - + //Get pages byte[] dexcomDatabasePages = new byte[2122]; @@ -236,10 +249,10 @@ private byte[] getLastFourPages(byte [] dexcomPageRange, int pageOffset) Log.e(TAG, "Unable to read from serial device", e); } - //Parse pages + //Parse pages byte [] databasePages = new byte[2112]; System.arraycopy(dexcomDatabasePages, 4, databasePages, 0, 2112); - return databasePages; + return databasePages; } private EGVRecord[] parseDatabasePages(byte[] databasePages) { @@ -247,7 +260,7 @@ private EGVRecord[] parseDatabasePages(byte[] databasePages) { byte [][] fourPages = new byte[4][528]; int [] recordCounts = new int[4]; int totalRecordCount = 0; - + //we parse 4 pages at a time, calculate total record count while we do this for (int i = 0; i < 4; i++) { @@ -255,10 +268,10 @@ private EGVRecord[] parseDatabasePages(byte[] databasePages) { recordCounts[i] = fourPages[i][4]; totalRecordCount = totalRecordCount + recordCounts[i]; } - + EGVRecord[] recordsToReturn = new EGVRecord[totalRecordCount]; int k = 0; - + //parse each record, plenty of room for improvement byte [] tempRecord = new byte[13]; for (int i = 0; i < 4; i++) @@ -297,27 +310,104 @@ private EGVRecord[] parseDatabasePages(byte[] databasePages) { Date display = new Date(timeAdd); byte trendArrow = (byte) (tempRecord[10] & (byte)15); + String trend = "Not Calculated"; + String trendA = "--X"; + + switch (trendArrow) { + + case (0): + trendA = "\u2194"; + trend = "NONE"; + break; + case (1): + trendA = "\u21C8"; + trend = "DoubleUp"; + break; + case (2): + trendA = "\u2191"; + trend = "SingleUp"; + break; + case (3): + trendA = "\u2197"; + trend = "FortyFiveUp"; + break; + case (4): + trendA = "\u2192"; + trend = "Flat"; + break; + case (5): + trendA = "\u2198"; + trend = "FortyFiveDown"; + break; + case (6): + trendA = "\u2193"; + trend = "SingleDown"; + break; + case (7): + trendA = "\u21CA"; + trend = "DoubleDown"; + break; + case (8): + trendA = "\u2194"; + trend = "NOT COMPUTABLE"; + break; + case (9): + trendA = "\u2194"; + trend = "RATE OUT OF RANGE"; + break; + } - Constants.TREND_ARROW_VALUES arrow = Constants.TREND_ARROW_VALUES.values()[trendArrow]; - - - this.trend = arrow.friendlyTrendName(); + this.trend = trend; this.displayTime = new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(display); this.bGValue = String.valueOf(bGValue); EGVRecord record = new EGVRecord(); record.setBGValue(this.bGValue); record.setDisplayTime(this.displayTime); - record.setTrend(arrow.friendlyTrendName()); - record.setTrendArrow(arrow.Symbol()); + record.setTrend(this.trend); + record.setTrendArrow(trendA); recordsToReturn[k++] = record; } - } + } return recordsToReturn; } + //TODO: why are we writing CSV? + private void writeLocalCSV(EGVRecord[] mostRecentData, Context context) { + + //Write EGV Binary of last (most recent) data + try { + ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(context.getFilesDir(), "save.bin"))); //Select where you wish to save the file... + oos.writeObject(mostRecentData[mostRecentData.length - 1]); // write the class as an 'object' + oos.flush(); // flush the stream to insure all of the information was written to 'save.bin' + oos.close();// close the stream + } catch(Exception e) { + Log.e(TAG, "write to OutputStream failed", e); + } + + //Write CSV of EGV from last 4 pages + CSVWriter writer; + try { + + writer = new CSVWriter(new FileWriter(new File(context.getFilesDir(), "hayden.csv")),',', CSVWriter.NO_QUOTE_CHARACTER); + List data = new ArrayList(); + data.add(new String[] {"GlucoseValue","DisplayTime"}); + + for (int i = 0; i < mostRecentData.length; i++) + { + data.add(new String[] {mostRecentData[i].bGValue, mostRecentData[i].displayTime}); + } + + writer.writeAll(data); + + writer.close(); + } catch (IOException e) { + Log.e(TAG, "write to CSV failed", e); + } + } + //CRC methods public static int calculateCRC16 (byte [] buff, int start, int end) { @@ -337,70 +427,6 @@ public static int calculateCRC16 (byte [] buff, int start, int end) { } - public void readPacket() { - byte[] initialData = new byte[4]; - try { - Log.i(TAG, "Read: " + mSerialDevice.read(initialData, 20000)); - } catch (IOException e) { - Log.i(TAG, "Failed to read initial packet data"); - } - if (initialData[0] == (byte)1) { - - } else { - Log.i(TAG, "Invalid initial packet header!"); - } - for (int y = 0; y 6) { - int remainingRead = Math.abs(dataNumber - 8); - remainingData = new byte[remainingRead]; - try { - Log.i(TAG, "remaining read of " + remainingRead); - Log.i(TAG, "read " + mSerialDevice.read(remainingData, 20000)); - } catch (IOException e) { - Log.i(TAG, "Failed to read remaining packet data"); - } - } else { - remainingData = new byte[0]; - } - byte[] suffixArray = new byte[2]; - - try { - mSerialDevice.read(suffixArray, 20000); - } catch (IOException e) { - Log.i(TAG, "Failed to read suffix packet data"); - } - for (int i=0; i> 24) & 0xff); + b[1] = (byte) ((i >> 16) & 0xff); + b[2] = (byte) ((i >> 8) & 0xff); + b[3] = (byte) (i & 0xff); + break; + case 1: + b[3] = (byte) ((i >> 24) & 0xff); + b[2] = (byte) ((i >> 16) & 0xff); + b[1] = (byte) ((i >> 8) & 0xff); + b[0] = (byte) (i & 0xff); + break; + default: + break; + } + return b; + } + @Override protected Object doInBackground(UsbSerialDriver... params) { return new String[]{displayTime, bGValue, trend}; } -} +} \ No newline at end of file From f41e70ee9494dafc518ab3eae670c068779a80d1 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Wed, 6 Aug 2014 13:29:16 -0700 Subject: [PATCH 005/212] Delete unused class. --- .../android/dexcom/DexcomPacket.java | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 src/com/nightscout/android/dexcom/DexcomPacket.java diff --git a/src/com/nightscout/android/dexcom/DexcomPacket.java b/src/com/nightscout/android/dexcom/DexcomPacket.java deleted file mode 100644 index 9fa53f5b..00000000 --- a/src/com/nightscout/android/dexcom/DexcomPacket.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.nightscout.android.dexcom; - -import android.util.Log; - -import java.util.ArrayList; -import java.util.Arrays; - - -public class DexcomPacket { - 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_CMD = 3; - public static final int OFFSET_PAYLOAD = 4; - private static final String TAG = DexcomPacket.class.getSimpleName(); - private ArrayList packet; - private int command; - private ArrayList payload; - - public DexcomPacket(int command) { - this.packet = new ArrayList(); - this.command = command; - packet.add(SOF); - setLength(); - packet.add((byte) 0); - packet.add((byte) command); - } - - public static short calculateCRC16(byte[] buff, int start, int end) { - - int crc = 0; - for (int i = start; i < end; i++) { - - crc = ((crc >>> 8) | (crc << 8)) & 0xffff; - crc ^= (buff[i] & 0xff); - crc ^= ((crc & 0xff) >> 4); - crc ^= (crc << 12) & 0xffff; - crc ^= ((crc & 0xFF) << 5) & 0xffff; - - } - crc &= 0xffff; - return (short) crc; - - } - - private void setLength() { - byte packetSize = (byte) Math.max(this.packet.size() + 2, MIN_LEN); - if (this.packet.size() < 2) { - packet.add(packetSize); - } else { - packet.set(1, packetSize); - } - } - - private void setCRC16() { - short crc16 = calculateCRC16(bytes(), 0, this.packet.size()); - this.packet.add((byte) (crc16 & 0xff)); - this.packet.add((byte) ((crc16 >> 8) & 0xff)); - } - - private byte[] bytes() { - 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 byte[] Compose() { - setLength(); - setCRC16(); - if (this.payload != null) { - this.packet.addAll(this.payload); - } - return this.bytes(); - } - - public byte[] Compose(ArrayList payload) { - this.payload = payload; - return Compose(); - } - -} From 675e02f2943f6e01bc716844be4c99d4dc9dea85 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Wed, 6 Aug 2014 23:07:49 -0700 Subject: [PATCH 006/212] Adding record director with MeterRecord. --- .../android/dexcom/records/MeterRecord.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/records/MeterRecord.java diff --git a/src/com/nightscout/android/dexcom/records/MeterRecord.java b/src/com/nightscout/android/dexcom/records/MeterRecord.java new file mode 100644 index 00000000..4fca8ec8 --- /dev/null +++ b/src/com/nightscout/android/dexcom/records/MeterRecord.java @@ -0,0 +1,24 @@ +package com.nightscout.android.dexcom.records; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class MeterRecord { + private int systemTime; + private int displayTime; + private int meterBG; + private int meterTime; + + public MeterRecord(byte[] 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; + } +} From b117a09b4e2eb589a9a9344459edb22bfe47977c Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Wed, 6 Aug 2014 23:11:08 -0700 Subject: [PATCH 007/212] Change class name and some adds and cleanup. --- .../android/dexcom/DexcomCommandPacket.java | 86 ------------------- .../android/dexcom/PacketBuilder.java | 61 +++++++++++++ 2 files changed, 61 insertions(+), 86 deletions(-) delete mode 100644 src/com/nightscout/android/dexcom/DexcomCommandPacket.java create mode 100644 src/com/nightscout/android/dexcom/PacketBuilder.java diff --git a/src/com/nightscout/android/dexcom/DexcomCommandPacket.java b/src/com/nightscout/android/dexcom/DexcomCommandPacket.java deleted file mode 100644 index 6a34896f..00000000 --- a/src/com/nightscout/android/dexcom/DexcomCommandPacket.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.nightscout.android.dexcom; - -import java.util.ArrayList; - - -public class DexcomCommandPacket { - 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_CMD = 3; - public static final int OFFSET_PAYLOAD = 4; - private static final String TAG = DexcomCommandPacket.class.getSimpleName(); - private ArrayList packet; - private int command; - private ArrayList payload; - - public DexcomCommandPacket(int command) { - this.command = command; - } - - private void resetPacket() { - packet = new ArrayList(); - packet.add(SOF); - setLength(); - packet.add((byte) 0); - packet.add((byte) command); - } - - public static short calculateCRC16(byte[] buff, int start, int end) { - - int crc = 0; - for (int i = start; i < end; i++) { - - crc = ((crc >>> 8) | (crc << 8)) & 0xffff; - crc ^= (buff[i] & 0xff); - crc ^= ((crc & 0xff) >> 4); - crc ^= (crc << 12) & 0xffff; - crc ^= ((crc & 0xFF) << 5) & 0xffff; - - } - crc &= 0xffff; - return (short) crc; - - } - - private void setLength() { - byte packetSize = (byte) Math.max(this.packet.size() + 2, MIN_LEN); - if (this.packet.size() < 2) { - packet.add(packetSize); - } else { - packet.set(1, packetSize); - } - } - - private void setCRC16() { - short crc16 = calculateCRC16(bytes(), 0, this.packet.size()); - this.packet.add((byte) (crc16 & 0xff)); - this.packet.add((byte) ((crc16 >> 8) & 0xff)); - } - - private byte[] bytes() { - 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 void setPayload(ArrayList payload) { - this.payload = payload; - } - - public byte[] Compose() { - resetPacket(); - if (this.payload != null) { - this.packet.addAll(this.payload); - } - setLength(); - setCRC16(); - return this.bytes(); - } - -} diff --git a/src/com/nightscout/android/dexcom/PacketBuilder.java b/src/com/nightscout/android/dexcom/PacketBuilder.java new file mode 100644 index 00000000..90c36207 --- /dev/null +++ b/src/com/nightscout/android/dexcom/PacketBuilder.java @@ -0,0 +1,61 @@ +package com.nightscout.android.dexcom; + +import java.util.ArrayList; + +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; + private ArrayList packet; + private int command; + private ArrayList payload; + + public PacketBuilder(int command) { + this.command = command; + } + + public PacketBuilder(int command, ArrayList payload) { + this.command = command; + this.payload = payload; + } + + public byte[] compose() { + packet = new ArrayList(); + 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]); + return this.toBytes(); + } + 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; + } + + private 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; + } +} \ No newline at end of file From 1b3c0898d717927a89bb58ac9a742d48ff567250 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 7 Aug 2014 00:35:21 -0700 Subject: [PATCH 008/212] Adding new EGRecord class, still needs some work. --- .../android/dexcom/records/EGRecord.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/records/EGRecord.java diff --git a/src/com/nightscout/android/dexcom/records/EGRecord.java b/src/com/nightscout/android/dexcom/records/EGRecord.java new file mode 100644 index 00000000..0d75535a --- /dev/null +++ b/src/com/nightscout/android/dexcom/records/EGRecord.java @@ -0,0 +1,36 @@ +package com.nightscout.android.dexcom.records; + +import com.nightscout.android.dexcom.Constants; + +import java.io.Serializable; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +public class EGRecord implements Serializable { + + private int displayTime; + private int bGValue; + private String trend = "---"; + + public EGRecord(byte[] packet) { + // uint, uint, ushort, byte, ushort + // (system_time, display_time, glucose, trend_arrow, crc) + // TODO: convert time using epoch + displayTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4); + int eGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8); + bGValue = eGValue & Constants.EGV_VALUE_MASK; +// trend = Constants.TREND_ARROW_VALUES.values()[ByteBuffer.wrap(packet).get(10)].friendlyTrendName(); + } + + public int getDisplayTime() { + return displayTime; + } + + public int getBGValue() { + return bGValue; + } + + public String getTrend() { + return trend; + } +} From 7cb719bb189c67c04da8368ed893e80d88b97491 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 7 Aug 2014 00:37:01 -0700 Subject: [PATCH 009/212] Make MeterRecord implement Serializable. --- src/com/nightscout/android/dexcom/records/MeterRecord.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/nightscout/android/dexcom/records/MeterRecord.java b/src/com/nightscout/android/dexcom/records/MeterRecord.java index 4fca8ec8..9d7591c0 100644 --- a/src/com/nightscout/android/dexcom/records/MeterRecord.java +++ b/src/com/nightscout/android/dexcom/records/MeterRecord.java @@ -1,9 +1,10 @@ package com.nightscout.android.dexcom.records; +import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; -public class MeterRecord { +public class MeterRecord implements Serializable { private int systemTime; private int displayTime; private int meterBG; From 2dd3a6bea0e3f16ecfa536a932e7362e046d1b59 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 7 Aug 2014 00:37:57 -0700 Subject: [PATCH 010/212] Add ReadPacket class that generically translates a read packet. --- .../nightscout/android/dexcom/ReadPacket.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/ReadPacket.java diff --git a/src/com/nightscout/android/dexcom/ReadPacket.java b/src/com/nightscout/android/dexcom/ReadPacket.java new file mode 100644 index 00000000..2a93dc45 --- /dev/null +++ b/src/com/nightscout/android/dexcom/ReadPacket.java @@ -0,0 +1,24 @@ +package com.nightscout.android.dexcom; + +import java.util.Arrays; + +public class ReadPacket { + private int command; + private byte[] data; + 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); + } + + public int getCommand() { + return command; + } + + public byte[] getData() { + return data; + } +} From d61318c786e59c0aa44e58caa53d96aef9e01aa5 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 7 Aug 2014 00:38:48 -0700 Subject: [PATCH 011/212] Add TODO note. --- src/com/nightscout/android/dexcom/ReadPacket.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/nightscout/android/dexcom/ReadPacket.java b/src/com/nightscout/android/dexcom/ReadPacket.java index 2a93dc45..f8075785 100644 --- a/src/com/nightscout/android/dexcom/ReadPacket.java +++ b/src/com/nightscout/android/dexcom/ReadPacket.java @@ -12,6 +12,7 @@ public class ReadPacket { public ReadPacket(byte[] readPacket) { this.command = readPacket[OFFSET_CMD]; this.data = Arrays.copyOfRange(readPacket, OFFSET_DATA, readPacket.length - CRC_LEN); + //TODO: check CRC } public int getCommand() { From 84d6f0c5d4d6aa12a87204a131f5e85cad969863 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 7 Aug 2014 00:40:35 -0700 Subject: [PATCH 012/212] Adding new receiver reader class that will replace old one, needs lots of work. --- .../nightscout/android/dexcom/ReadData.java | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/ReadData.java diff --git a/src/com/nightscout/android/dexcom/ReadData.java b/src/com/nightscout/android/dexcom/ReadData.java new file mode 100644 index 00000000..8502c188 --- /dev/null +++ b/src/com/nightscout/android/dexcom/ReadData.java @@ -0,0 +1,128 @@ +package com.nightscout.android.dexcom; + +import android.os.AsyncTask; +import android.util.Log; +import com.nightscout.android.dexcom.USB.UsbSerialDriver; +import com.nightscout.android.dexcom.records.EGRecord; +import com.nightscout.android.dexcom.records.MeterRecord; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.Arrays; + +public class ReadData extends AsyncTask { + + private static final String TAG = ReadData.class.getSimpleName(); + private static final int IO_TIMEOUT = 200; + private static final int MIN_LEN = 256; + private UsbSerialDriver mSerialDevice; + + public ReadData(UsbSerialDriver device) { + mSerialDevice = device; + } + + public boolean ping() { + writeCommand(Constants.PING); + return read(MIN_LEN).getCommand() == Constants.ACK; + } + + public long readDisplayTimeOffset() { + writeCommand(Constants.READ_DISPLAY_TIME_OFFSET); + byte[] readData = read(MIN_LEN).getData(); + return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt() & 0xffffffffL; + } + + public int readDataBasePageRange(int recordType) { + ArrayList payload = new ArrayList(); + payload.add((byte) recordType); + writeCommand(Constants.READ_DATABASE_PAGE_RANGE, payload); + byte[] readData = read(MIN_LEN).getData(); + return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt(4); + } + + public T readDataBasePage(int recordType, int page) { + byte numOfPages = 1; + ArrayList payload = new ArrayList(); + 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(Constants.READ_DATABASE_PAGES, payload); + byte[] readData = read(2122).getData(); + ParsePage(readData, recordType); + return ParsePage(readData, recordType); + } + + private void writeCommand(int command, ArrayList payload) { + byte[] packet = new PacketBuilder(command, payload).compose(); + try { + mSerialDevice.write(packet, IO_TIMEOUT); + } catch (IOException e) { + Log.e(TAG, "Unable to write to serial device.", e); + } + } + + private void writeCommand(int command) { + byte[] packet = new PacketBuilder(command).compose(); + try { + mSerialDevice.write(packet, IO_TIMEOUT); + } catch (IOException 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 { + len = mSerialDevice.read(readData, IO_TIMEOUT); + } catch (IOException e) { + Log.e(TAG, "Unable to read from serial device.", e); + } + byte[] data = Arrays.copyOfRange(readData, 0, len); + return new ReadPacket(data); + } + + // TODO: not sure if I want to use generics or just separate methods, hmmm + private T ParsePage(byte[] data, int recordType) { + int HEADER_LEN = 28; + int NUM_REC_OFFSET = 4; + int numRec = data[NUM_REC_OFFSET]; + int rec_len; + + switch (Constants.RECORD_TYPES.values()[recordType]) { + case EGV_DATA: + rec_len = 13; + EGRecord[] egRecords = new EGRecord[numRec]; + for (int i = 0; i < numRec; i++) { + int startIdx = HEADER_LEN + rec_len * i; + egRecords[i] = new EGRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1)); + } + return (T) egRecords; + 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; + default: + // Throw error "Database record not supported" + break; + } + + return (T) null; + } + + @Override + protected Object doInBackground(UsbSerialDriver... params) { + // TODO Auto-generated method stub + return null; + } +} \ No newline at end of file From 78c982d004486e8bfd869df0dacbcb1302ef33d5 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 7 Aug 2014 00:44:24 -0700 Subject: [PATCH 013/212] Adding new CRC16 static class. --- src/com/nightscout/android/dexcom/CRC16.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/CRC16.java diff --git a/src/com/nightscout/android/dexcom/CRC16.java b/src/com/nightscout/android/dexcom/CRC16.java new file mode 100644 index 00000000..bd4fd82c --- /dev/null +++ b/src/com/nightscout/android/dexcom/CRC16.java @@ -0,0 +1,18 @@ +package com.nightscout.android.dexcom; + +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; + byte[] crc = {(byte) (crcShort & 0xff), (byte) ((crcShort >> 8) & 0xff)}; + return crc; + } +} \ No newline at end of file From ccfe1751810dd9f587f04ba0130e37579907aa79 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Sun, 10 Aug 2014 22:40:53 -0700 Subject: [PATCH 014/212] Adding GerericXMLRecord class. --- .../dexcom/records/GenericXMLRecord.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/com/nightscout/android/dexcom/records/GenericXMLRecord.java diff --git a/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java b/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java new file mode 100644 index 00000000..fee85193 --- /dev/null +++ b/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java @@ -0,0 +1,38 @@ +package com.nightscout.android.dexcom.records; + +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; + +public class GenericXMLRecord implements Serializable { + int XML_START = 36; + int XML_END = 241; + + private Element xmlElement; + + public GenericXMLRecord(byte[] packet) { + Document document; + 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) { + e.printStackTrace(); + } + } + + // example: String sn = getXmlElement().getAttribute("SerialNumber"); + public Element getXmlElement() { + return xmlElement; + } +} From bf2f85a4a0d937f0c71d4802c0a990e4d3fa0afb Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Sun, 10 Aug 2014 22:41:38 -0700 Subject: [PATCH 015/212] Fixed trend on EGRecord class. --- src/com/nightscout/android/dexcom/records/EGRecord.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/com/nightscout/android/dexcom/records/EGRecord.java b/src/com/nightscout/android/dexcom/records/EGRecord.java index 0d75535a..71ab9a4a 100644 --- a/src/com/nightscout/android/dexcom/records/EGRecord.java +++ b/src/com/nightscout/android/dexcom/records/EGRecord.java @@ -10,7 +10,7 @@ public class EGRecord implements Serializable { private int displayTime; private int bGValue; - private String trend = "---"; + private String trend; public EGRecord(byte[] packet) { // uint, uint, ushort, byte, ushort @@ -19,7 +19,8 @@ public EGRecord(byte[] packet) { displayTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4); int eGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8); bGValue = eGValue & Constants.EGV_VALUE_MASK; -// trend = Constants.TREND_ARROW_VALUES.values()[ByteBuffer.wrap(packet).get(10)].friendlyTrendName(); + int trendValue = ByteBuffer.wrap(packet).get(10) & Constants.EGV_TREND_ARROW_MASK; + trend = Constants.TREND_ARROW_VALUES.values()[trendValue].friendlyTrendName(); } public int getDisplayTime() { From a48d741c4cb3d5a7e45aba409800aca1da7ab33e Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Sun, 10 Aug 2014 22:43:17 -0700 Subject: [PATCH 016/212] Added Manufacturing data to page reader. --- src/com/nightscout/android/dexcom/ReadData.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/com/nightscout/android/dexcom/ReadData.java b/src/com/nightscout/android/dexcom/ReadData.java index 8502c188..fa928bc9 100644 --- a/src/com/nightscout/android/dexcom/ReadData.java +++ b/src/com/nightscout/android/dexcom/ReadData.java @@ -4,6 +4,7 @@ import android.util.Log; import com.nightscout.android.dexcom.USB.UsbSerialDriver; import com.nightscout.android.dexcom.records.EGRecord; +import com.nightscout.android.dexcom.records.GenericXMLRecord; import com.nightscout.android.dexcom.records.MeterRecord; import java.io.IOException; @@ -42,7 +43,7 @@ public int readDataBasePageRange(int recordType) { return ByteBuffer.wrap(readData).order(ByteOrder.LITTLE_ENDIAN).getInt(4); } - public T readDataBasePage(int recordType, int page) { + private T readDataBasePage(int recordType, int page) { byte numOfPages = 1; ArrayList payload = new ArrayList(); payload.add((byte) recordType); @@ -112,6 +113,9 @@ private T ParsePage(byte[] data, int recordType) { meterRecords[i] = new MeterRecord(Arrays.copyOfRange(data, startIdx, startIdx + rec_len - 1)); } return (T) meterRecords; + case MANUFACTURING_DATA: + GenericXMLRecord xmlRecord = new GenericXMLRecord(data); + return (T) xmlRecord; default: // Throw error "Database record not supported" break; From ba996b3c1c0ebfdadd99cf75a4f9397172728d96 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 00:24:34 -0700 Subject: [PATCH 017/212] Added readSerialNumber method. --- src/com/nightscout/android/dexcom/ReadData.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/com/nightscout/android/dexcom/ReadData.java b/src/com/nightscout/android/dexcom/ReadData.java index fa928bc9..6dba2d2b 100644 --- a/src/com/nightscout/android/dexcom/ReadData.java +++ b/src/com/nightscout/android/dexcom/ReadData.java @@ -6,6 +6,7 @@ import com.nightscout.android.dexcom.records.EGRecord; import com.nightscout.android.dexcom.records.GenericXMLRecord; import com.nightscout.android.dexcom.records.MeterRecord; +import org.w3c.dom.Element; import java.io.IOException; import java.nio.ByteBuffer; @@ -29,6 +30,12 @@ public boolean ping() { return read(MIN_LEN).getCommand() == Constants.ACK; } + public String readSerialNumber() { + byte[] readData = readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), 0); + Element md = ParsePage(readData, Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal()); + return md.getAttribute("SerialNumber"); + } + public long readDisplayTimeOffset() { writeCommand(Constants.READ_DISPLAY_TIME_OFFSET); byte[] readData = read(MIN_LEN).getData(); From f1a94f98aa70e9ee71f8731097f98f4dd981b147 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 00:25:23 -0700 Subject: [PATCH 018/212] Cleanup of mystery number. --- src/com/nightscout/android/dexcom/ReadData.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/nightscout/android/dexcom/ReadData.java b/src/com/nightscout/android/dexcom/ReadData.java index 6dba2d2b..dfa0d542 100644 --- a/src/com/nightscout/android/dexcom/ReadData.java +++ b/src/com/nightscout/android/dexcom/ReadData.java @@ -31,7 +31,8 @@ public boolean ping() { } public String readSerialNumber() { - byte[] readData = readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), 0); + int PAGE_OFFSET = 0; + byte[] readData = readDataBasePage(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal(), PAGE_OFFSET); Element md = ParsePage(readData, Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal()); return md.getAttribute("SerialNumber"); } From c8061e7e564365ccf3019c7b81eb4bd7b5d05799 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 00:25:59 -0700 Subject: [PATCH 019/212] Cleanup TODO statement. --- src/com/nightscout/android/dexcom/DexcomG4Service.java | 5 +++++ src/com/nightscout/android/dexcom/ReadData.java | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/nightscout/android/dexcom/DexcomG4Service.java b/src/com/nightscout/android/dexcom/DexcomG4Service.java index bdbd8e38..1d8f4d85 100644 --- a/src/com/nightscout/android/dexcom/DexcomG4Service.java +++ b/src/com/nightscout/android/dexcom/DexcomG4Service.java @@ -191,6 +191,11 @@ protected void doReadAndUpload() { uploader.execute(dexcomReader.mRD[dexcomReader.mRD.length - 1]); } + ReadData r = new ReadData(mSerialDevice); +// r.readDataBasePage(Constants.RECORD_TYPES.EGV_DATA.ordinal(), 1536); + r.readDataBasePageRange(Constants.RECORD_TYPES.MANUFACTURING_DATA.ordinal()); + String sn = r.readSerialNumber(); + initialRead = false; nextUploadTimer = getNextUploadTimer(dexcomReader); diff --git a/src/com/nightscout/android/dexcom/ReadData.java b/src/com/nightscout/android/dexcom/ReadData.java index dfa0d542..e0fbdd8a 100644 --- a/src/com/nightscout/android/dexcom/ReadData.java +++ b/src/com/nightscout/android/dexcom/ReadData.java @@ -97,7 +97,7 @@ private ReadPacket read(int numOfBytes) { return new ReadPacket(data); } - // TODO: not sure if I want to use generics or just separate methods, hmmm + // TODO: not sure if I want to use generics or just separate methods, hmmm make it private in casec private T ParsePage(byte[] data, int recordType) { int HEADER_LEN = 28; int NUM_REC_OFFSET = 4; From b56c3a2aaa936e528d272f56ce06850e0ce4c7c4 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 18:23:52 -0700 Subject: [PATCH 020/212] Adding GenericTimestampRecord. --- .../nightscout/android/dexcom/Constants.java | 1 - .../records/GenericTimestampRecord.java | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java diff --git a/src/com/nightscout/android/dexcom/Constants.java b/src/com/nightscout/android/dexcom/Constants.java index ae93a614..b3977381 100644 --- a/src/com/nightscout/android/dexcom/Constants.java +++ b/src/com/nightscout/android/dexcom/Constants.java @@ -48,7 +48,6 @@ public class Constants { 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 String EPOCH = "01-01-2009"; public enum BATTERY_STATES { NONE, diff --git a/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java b/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java new file mode 100644 index 00000000..7f095c19 --- /dev/null +++ b/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java @@ -0,0 +1,22 @@ +package com.nightscout.android.dexcom.records; + +import java.util.Date; + +public class GenericTimestampRecord { + + public final String EPOCH = "01-01-2009"; + private Date systemTime; + private Date displayTime; + + public GenericTimestampRecord(byte[] packet) { + + } + + public Date getSystemTime() { + return systemTime; + } + + public Date getDisplayTime() { + return displayTime; + } +} From 85616d6afe99572302bd7f6a8c286b05bfb25b11 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 18:43:05 -0700 Subject: [PATCH 021/212] Adding to timestamp record and used to extend needed record classes. --- .../android/dexcom/records/EGRecord.java | 14 ++++------- .../records/GenericTimestampRecord.java | 23 +++++++++++++++++-- .../android/dexcom/records/MeterRecord.java | 7 +++--- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/com/nightscout/android/dexcom/records/EGRecord.java b/src/com/nightscout/android/dexcom/records/EGRecord.java index 71ab9a4a..2c9beaf7 100644 --- a/src/com/nightscout/android/dexcom/records/EGRecord.java +++ b/src/com/nightscout/android/dexcom/records/EGRecord.java @@ -5,28 +5,22 @@ import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; -public class EGRecord implements Serializable { +public class EGRecord extends GenericTimestampRecord implements Serializable { - private int displayTime; private int bGValue; private String trend; public EGRecord(byte[] packet) { - // uint, uint, ushort, byte, ushort - // (system_time, display_time, glucose, trend_arrow, crc) - // TODO: convert time using epoch - displayTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4); + // system_time (UInt), display_time (UInt), glucose (UShort), trend_arrow (Byte), crc (UShort)) + super(Arrays.copyOfRange(packet, 0, 7)); int eGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8); bGValue = eGValue & Constants.EGV_VALUE_MASK; int trendValue = ByteBuffer.wrap(packet).get(10) & Constants.EGV_TREND_ARROW_MASK; trend = Constants.TREND_ARROW_VALUES.values()[trendValue].friendlyTrendName(); } - public int getDisplayTime() { - return displayTime; - } - public int getBGValue() { return bGValue; } diff --git a/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java b/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java index 7f095c19..b33a3857 100644 --- a/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java +++ b/src/com/nightscout/android/dexcom/records/GenericTimestampRecord.java @@ -1,15 +1,22 @@ package com.nightscout.android.dexcom.records; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; public class GenericTimestampRecord { - public final String EPOCH = "01-01-2009"; + public final Date EPOCH = new GregorianCalendar(2009, 0, 1).getTime(); private Date systemTime; private Date displayTime; public GenericTimestampRecord(byte[] packet) { - + int st = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(0); + systemTime = getDate(st); + int dt = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4); + displayTime = getDate(dt); } public Date getSystemTime() { @@ -19,4 +26,16 @@ public Date getSystemTime() { public Date getDisplayTime() { return displayTime; } + + // TODO: this will be used in 1 other place, thus might be best to get in a utilities class + private Date getDate(int receiverTime) { + // Epoch is PST, but but having epoch have user timezone added, then don't have to add to the + // display time + // TODO: probably best to do this Adriens way, TBD + long milliseconds = EPOCH.getTime(); + long timeAdd = milliseconds + (1000L * receiverTime); + TimeZone tz = TimeZone.getDefault(); + if (tz.inDaylightTime(new Date())) timeAdd = timeAdd - 3600000L; + return new Date(timeAdd); + } } diff --git a/src/com/nightscout/android/dexcom/records/MeterRecord.java b/src/com/nightscout/android/dexcom/records/MeterRecord.java index 9d7591c0..89dc2f41 100644 --- a/src/com/nightscout/android/dexcom/records/MeterRecord.java +++ b/src/com/nightscout/android/dexcom/records/MeterRecord.java @@ -3,14 +3,15 @@ import java.io.Serializable; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.util.Arrays; + +public class MeterRecord extends GenericTimestampRecord implements Serializable { -public class MeterRecord implements Serializable { - private int systemTime; - private int displayTime; private int meterBG; private int meterTime; public MeterRecord(byte[] packet) { + super(Arrays.copyOfRange(packet, 0, 7)); meterBG = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8); meterTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(10); } From 1c1b97eec2599e1c89e9613e3bd3794b3428929a Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 18:54:47 -0700 Subject: [PATCH 022/212] Extended GenericXMLRecord with GenericTimestampRecord and removed header from reading of manufacture data. --- src/com/nightscout/android/dexcom/ReadData.java | 2 +- .../nightscout/android/dexcom/records/GenericXMLRecord.java | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/com/nightscout/android/dexcom/ReadData.java b/src/com/nightscout/android/dexcom/ReadData.java index e0fbdd8a..e9a41388 100644 --- a/src/com/nightscout/android/dexcom/ReadData.java +++ b/src/com/nightscout/android/dexcom/ReadData.java @@ -122,7 +122,7 @@ private T ParsePage(byte[] data, int recordType) { } return (T) meterRecords; case MANUFACTURING_DATA: - GenericXMLRecord xmlRecord = new GenericXMLRecord(data); + GenericXMLRecord xmlRecord = new GenericXMLRecord(Arrays.copyOfRange(data, HEADER_LEN, data.length - 1)); return (T) xmlRecord; default: // Throw error "Database record not supported" diff --git a/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java b/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java index fee85193..677fc618 100644 --- a/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java +++ b/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java @@ -10,14 +10,16 @@ import java.io.StringReader; import java.util.Arrays; -public class GenericXMLRecord implements Serializable { - int XML_START = 36; +public class GenericXMLRecord extends GenericTimestampRecord implements Serializable { + int XML_START = 8; int XML_END = 241; private Element xmlElement; public GenericXMLRecord(byte[] packet) { + super(Arrays.copyOfRange(packet, 0, 7)); Document document; + // TODO: it would be best if we could just remove /x00 character and read till end String xml = new String(Arrays.copyOfRange(packet, XML_START, XML_END)); DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder; From 936fc892d663b9aae72ecdbbf8efad839162db52 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 11 Aug 2014 18:55:23 -0700 Subject: [PATCH 023/212] Fixed comment. --- src/com/nightscout/android/dexcom/records/GenericXMLRecord.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java b/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java index 677fc618..4a949392 100644 --- a/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java +++ b/src/com/nightscout/android/dexcom/records/GenericXMLRecord.java @@ -19,7 +19,7 @@ public class GenericXMLRecord extends GenericTimestampRecord implements Serializ public GenericXMLRecord(byte[] packet) { super(Arrays.copyOfRange(packet, 0, 7)); Document document; - // TODO: it would be best if we could just remove /x00 character and read till end + // 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; From 7a828d69e897e8be3e5537e88c1b430bb12e70f2 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Thu, 21 Aug 2014 22:24:27 -0700 Subject: [PATCH 024/212] Clean up records with constant offset for time records. --- .../com/nightscout/android/dexcom/records/EGRecord.java | 2 +- .../android/dexcom/records/GenericTimestampRecord.java | 6 ++++-- .../nightscout/android/dexcom/records/GenericXMLRecord.java | 2 +- .../com/nightscout/android/dexcom/records/MeterRecord.java | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/nightscout/android/dexcom/records/EGRecord.java b/app/src/main/java/com/nightscout/android/dexcom/records/EGRecord.java index 2c9beaf7..03e7ca2d 100644 --- a/app/src/main/java/com/nightscout/android/dexcom/records/EGRecord.java +++ b/app/src/main/java/com/nightscout/android/dexcom/records/EGRecord.java @@ -14,7 +14,7 @@ public class EGRecord extends GenericTimestampRecord implements Serializable { public EGRecord(byte[] packet) { // system_time (UInt), display_time (UInt), glucose (UShort), trend_arrow (Byte), crc (UShort)) - super(Arrays.copyOfRange(packet, 0, 7)); + super(packet); int eGValue = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8); bGValue = eGValue & Constants.EGV_VALUE_MASK; int trendValue = ByteBuffer.wrap(packet).get(10) & Constants.EGV_TREND_ARROW_MASK; diff --git a/app/src/main/java/com/nightscout/android/dexcom/records/GenericTimestampRecord.java b/app/src/main/java/com/nightscout/android/dexcom/records/GenericTimestampRecord.java index b33a3857..98fe82a3 100644 --- a/app/src/main/java/com/nightscout/android/dexcom/records/GenericTimestampRecord.java +++ b/app/src/main/java/com/nightscout/android/dexcom/records/GenericTimestampRecord.java @@ -9,13 +9,15 @@ public class GenericTimestampRecord { public final Date EPOCH = new GregorianCalendar(2009, 0, 1).getTime(); + private final int OFFSET_SYS_TIME = 0; + private final int OFFSET_DISPLAY_TIME = 4; private Date systemTime; private Date displayTime; public GenericTimestampRecord(byte[] packet) { - int st = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(0); + int st = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_SYS_TIME); systemTime = getDate(st); - int dt = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(4); + int dt = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(OFFSET_DISPLAY_TIME); displayTime = getDate(dt); } diff --git a/app/src/main/java/com/nightscout/android/dexcom/records/GenericXMLRecord.java b/app/src/main/java/com/nightscout/android/dexcom/records/GenericXMLRecord.java index 4a949392..82e9eb02 100644 --- a/app/src/main/java/com/nightscout/android/dexcom/records/GenericXMLRecord.java +++ b/app/src/main/java/com/nightscout/android/dexcom/records/GenericXMLRecord.java @@ -17,7 +17,7 @@ public class GenericXMLRecord extends GenericTimestampRecord implements Serializ private Element xmlElement; public GenericXMLRecord(byte[] packet) { - super(Arrays.copyOfRange(packet, 0, 7)); + 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)); diff --git a/app/src/main/java/com/nightscout/android/dexcom/records/MeterRecord.java b/app/src/main/java/com/nightscout/android/dexcom/records/MeterRecord.java index 89dc2f41..17c421cd 100644 --- a/app/src/main/java/com/nightscout/android/dexcom/records/MeterRecord.java +++ b/app/src/main/java/com/nightscout/android/dexcom/records/MeterRecord.java @@ -11,7 +11,7 @@ public class MeterRecord extends GenericTimestampRecord implements Serializable private int meterTime; public MeterRecord(byte[] packet) { - super(Arrays.copyOfRange(packet, 0, 7)); + super(packet); meterBG = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getShort(8); meterTime = ByteBuffer.wrap(packet).order(ByteOrder.LITTLE_ENDIAN).getInt(10); } From 8dfd053d984675e26266ade792b0b6714559c991 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Wed, 27 Aug 2014 00:11:56 -0700 Subject: [PATCH 025/212] Adding an intent service to possibly take over current service. --- .../android/dexcom/SyncingService.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 app/src/main/java/com/nightscout/android/dexcom/SyncingService.java diff --git a/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java b/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java new file mode 100644 index 00000000..bd26d5c2 --- /dev/null +++ b/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java @@ -0,0 +1,57 @@ +package com.nightscout.android.dexcom; + +import android.app.IntentService; +import android.content.Intent; +import android.content.Context; + +/** + * An {@link IntentService} subclass for handling asynchronous Dexcom downloads and cloud upload + * requests in a service on a separate handler thread. + *

+ * helper methods. + */ +public class SyncingService extends IntentService { + + private static final String ACTION_SYNC = "com.nightscout.android.dexcom.action.SYNC"; + + private static final String EXTRA_PARAM1 = "com.nightscout.android.dexcom.extra.2DAY"; + private static final String EXTRA_PARAM2 = "com.nightscout.android.dexcom.extra.SINGLE"; + + /** + * Starts this service to perform action Foo with the given parameters. If + * the service is already performing a task this action will be queued. + * + * @see IntentService + */ + public static void startActionSync(Context context, String param1, String param2) { + Intent intent = new Intent(context, SyncingService.class); + intent.setAction(ACTION_SYNC); + intent.putExtra(EXTRA_PARAM2, param1); + context.startService(intent); + } + + public SyncingService() { + super("SyncingService"); + } + + @Override + protected void onHandleIntent(Intent intent) { + if (intent != null) { + final String action = intent.getAction(); + if (ACTION_SYNC.equals(action)) { + final String param1 = intent.getStringExtra(EXTRA_PARAM1); + handleActionSync(param1); + } + } + } + + /** + * Handle action Sync in the provided background thread with the provided + * parameters. + */ + private void handleActionSync(String param1) { + // TODO: Handle action Sync + throw new UnsupportedOperationException("Not yet implemented"); + } + +} From 5f1681482439dc6ce8b28b06398236aa98473cb1 Mon Sep 17 00:00:00 2001 From: rnpenguin Date: Mon, 1 Sep 2014 12:27:03 -0700 Subject: [PATCH 026/212] Adding a new activity, updated intent service, and change manifest to use new activity instead of old. --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 52 ++++++++-------- .../com/nightscout/android/MainActivity.java | 59 +++++++++++++++++++ .../android/dexcom/SyncingService.java | 35 +++++++++-- app/src/main/res/layout/activity_main.xml | 46 +++++++++++++++ app/src/main/res/menu/main.xml | 9 +++ app/src/main/res/values-w820dp/dimens.xml | 6 ++ app/src/main/res/values/dimens.xml | 5 ++ app/src/main/res/values/strings.xml | 30 ++++++---- 9 files changed, 203 insertions(+), 40 deletions(-) create mode 100644 app/src/main/java/com/nightscout/android/MainActivity.java create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/menu/main.xml create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/dimens.xml diff --git a/app/build.gradle b/app/build.gradle index 6ac5e4ae..fdddd099 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,4 +24,5 @@ android { dependencies { compile files('libs/mongo-2.10.1.jar') + compile 'com.android.support:appcompat-v7:20.0.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3141821b..e8c121bb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,39 +1,45 @@ + package="com.nightscout.android" > + - - - - - - - - - + + + + + + + + + + + + + android:name=".MainActivity" + android:launchMode="singleTask" > + - - + + android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" + android:resource="@xml/device_filter" /> - - + + - + \ No newline at end of file diff --git a/app/src/main/java/com/nightscout/android/MainActivity.java b/app/src/main/java/com/nightscout/android/MainActivity.java new file mode 100644 index 00000000..f4a6f99a --- /dev/null +++ b/app/src/main/java/com/nightscout/android/MainActivity.java @@ -0,0 +1,59 @@ +package com.nightscout.android; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; + +import com.nightscout.android.dexcom.SyncingService; + + +public class MainActivity extends Activity { + + private static boolean isRunning = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_main); + + isRunning = true; + + final Context context = getApplicationContext(); + final Intent intent = new Intent(this, SyncingService.class); + + Button button = (Button)findViewById(R.id.stopSyncingButton); + button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + SyncingService.startActionSync(context, "test", "test"); + startService(intent); + } + }); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + return true; + } + return super.onOptionsItemSelected(item); + } +} diff --git a/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java b/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java index bd26d5c2..21837b32 100644 --- a/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java +++ b/app/src/main/java/com/nightscout/android/dexcom/SyncingService.java @@ -3,12 +3,17 @@ import android.app.IntentService; import android.content.Intent; import android.content.Context; +import android.hardware.usb.UsbManager; +import android.util.Log; + +import com.nightscout.android.dexcom.USB.UsbSerialDriver; +import com.nightscout.android.dexcom.USB.UsbSerialProber; + +import java.io.IOException; /** - * An {@link IntentService} subclass for handling asynchronous Dexcom downloads and cloud upload + * An {@link IntentService} subclass for handling asynchronous Dexcom downloads and cloud uploads * requests in a service on a separate handler thread. - *

- * helper methods. */ public class SyncingService extends IntentService { @@ -17,6 +22,11 @@ public class SyncingService extends IntentService { private static final String EXTRA_PARAM1 = "com.nightscout.android.dexcom.extra.2DAY"; private static final String EXTRA_PARAM2 = "com.nightscout.android.dexcom.extra.SINGLE"; + private final String TAG = SyncingService.class.getSimpleName(); + + private UsbManager mUsbManager; + private UsbSerialDriver mSerialDevice; + /** * Starts this service to perform action Foo with the given parameters. If * the service is already performing a task this action will be queued. @@ -50,8 +60,23 @@ protected void onHandleIntent(Intent intent) { * parameters. */ private void handleActionSync(String param1) { - // TODO: Handle action Sync - throw new UnsupportedOperationException("Not yet implemented"); + acquireSerialDevice(); + ReadData readData = new ReadData(mSerialDevice); + boolean test = readData.ping(); + } + + private void acquireSerialDevice() { + mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + mSerialDevice = UsbSerialProber.acquire(mUsbManager); + if (mSerialDevice != null) { + try { + mSerialDevice.open(); + } catch (IOException e) { + e.printStackTrace(); + } + } else { + Log.d(TAG, "Unable to acquire USB device from manager."); + } } } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 00000000..632aeda1 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,46 @@ + + +