Android Open Source - original-android-cgm Dexcom Reader






From Project

Back to project page original-android-cgm.

License

The source code is released under:

Copyright (c) 2014, John Costik All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * ...

If you think the Android project original-android-cgm listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.ht1.cc.cgm;
/*w  w w  .ja  v a 2s  .c  o  m*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.TimeZone;

import com.ht1.cc.USB.UsbSerialDriver;
import com.ht1.cc.USB.UsbSerialProber;

import android.content.Context;
import android.hardware.usb.UsbManager;
import android.os.AsyncTask;

//Still kludgy
//Newer, similar to Dex's architecture, classes are in progress, but this works reliably, if not the 
//most efficient, elegant design around.

public class DexcomReader extends AsyncTask<UsbSerialDriver, Object, Object>{
  
  private UsbSerialDriver mSerialDevice;
  public String bGValue;
  public String displayTime;
  public String trend;
  
  public DexcomReader (UsbSerialDriver device)
  {
    mSerialDevice = device;
  }
  public DexcomReader ()
  {

  }
  
  //The basic flow
  //for my requirements, I only care about the most recent data
  //Dex grabs 4 pages of data at a time, so I parse the last 4 pages
  //save the data to CSV and the most recent data to a serialized object for the
  //gui to quickly ingest
  public void readFromReceiver(Context context) {
        
    //locate the EGV data pages
        byte[] dexcomPageRange = getEGVDataPageRange();
        //Get the last 4 pages
        byte[] databasePages = getLastFourPages(dexcomPageRange);
        //Parse 'dem pages
        EGVRecord[] mostRecentData = parseDatabasePages(databasePages);
        
        //save them to the android file system for late access
    writeLocalCSV(mostRecentData, context);
        
  }
  
  //Not being used, but this is a nice to have if we want to kill the receiver, etc from
  //UI
  public void shutDownReceiver(Context context){

    UsbManager manager = (UsbManager) context
        .getSystemService(Context.USB_SERVICE);
    UsbSerialDriver mSerialDevice = UsbSerialProber.acquire(manager);
    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;
        try {
          mSerialDevice.write(resetPacket, 200);
        } catch (IOException e) {
          // mTitleTextView.setText("Error Writing.");
        }
      } catch (IOException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
      }

    }
    
  }
  
  private byte[] getEGVDataPageRange(){
      int[] rets = new int[24];
        int c = 0;
        
        //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(readEGVDataPageRange, 200);
    } catch (IOException e) {
      //mTitleTextView.setText("Error Writing.");
    }
        byte[] dexcomPageRange = new byte[256];
        try {
          rets[c++] = mSerialDevice.read(dexcomPageRange, 200);
    } catch (IOException e) {
      //mTitleTextView.setText("Error Writing.");
    }
        
        return dexcomPageRange;
  }

  private byte[] getLastFourPages(byte [] dexcomPageRange)
  {
      int[] rets = new int[24];
        int c = 0;
        byte [] endPage = new byte[]{dexcomPageRange[8], dexcomPageRange[9], dexcomPageRange[10], dexcomPageRange[11]};
        
        //ONLY interested in the last 4 pages of data for this app's requirements
        int endInt = toInt(endPage, 1);
        int lastFour = endInt-3;
        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;
        getLastEGVPage[1] = 0x0c;
        getLastEGVPage[2] = 0x00;
        getLastEGVPage[3] = 0x11;
        getLastEGVPage[4] = 0x04;
        getLastEGVPage[5] = result[3];
        getLastEGVPage[6] = result[2];
        getLastEGVPage[7] = result[1];
        getLastEGVPage[8] = result[0];
        getLastEGVPage[9] = 0x04;
   
        //Get checksum
        int getLastEGVCRC = calculateCRC16(getLastEGVPage, 0, 10);    
        byte crcByte1 = (byte) (getLastEGVCRC & 0xff);
        byte crcByte2 = (byte) ((getLastEGVCRC >> 8) & 0xff);
        
        getLastEGVPage[10] = crcByte1;
        getLastEGVPage[11] = crcByte2;
                  
        try {

          rets[c++] = mSerialDevice.write(getLastEGVPage, 200);
    } catch (IOException e) {
      
    }
        
        //Get pages
        byte[] dexcomDatabasePages = new byte[2122];

        try {
          rets[c++] = mSerialDevice.read(dexcomDatabasePages, 20000);

    } catch (IOException e) {
      
    }
        
       //Parse pages
        byte [] databasePages = new byte[2112];
        System.arraycopy(dexcomDatabasePages, 4, databasePages, 0, 2112);
        return databasePages;        
  }

    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++)
        {
          System.arraycopy(databasePages, 528*i, fourPages[i], 0, 528);
          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++)
        {
          for (int j = 0; j < recordCounts[i]; j++)
          {
            System.arraycopy(fourPages[i], 28 + j*13, tempRecord, 0, 13);
            
            byte [] eGValue = new byte[]{tempRecord[8],tempRecord[9]};

                int bGValue = ((eGValue[1]<<8) + (eGValue[0] & 0xff)) & 0x3ff;
                   
                byte [] dateTime = new byte[]{tempRecord[7],tempRecord[6],tempRecord[5],tempRecord[4]};
                
                ByteBuffer buffer = ByteBuffer.wrap(dateTime);
                int dt = buffer.getInt();//*1000;

                String string_date = "1-January-2009";
                SimpleDateFormat f = new SimpleDateFormat("dd-MMM-yyyy");
                Date d;
        try {
          d = f.parse(string_date);
        } catch (ParseException e) {
          // TODO Auto-generated catch block
          d = new Date();
        }
                long milliseconds = d.getTime();
                
                long timeAdd = milliseconds + (1000L*dt);
                TimeZone tz = TimeZone.getDefault();
                
                if (tz.inDaylightTime(new Date()))
                  timeAdd = timeAdd - 3600000L;
                
            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;
            }
                
            this.trend = trend;
            this.displayTime = new SimpleDateFormat("MM/dd/yyy hh:mm:ss aa").format(display);
            this.bGValue = String.valueOf((int)bGValue);
            
            EGVRecord record = new EGVRecord();
            record.setBGValue(this.bGValue);
            record.setDisplayTime(this.displayTime);
            record.setTrend(this.trend);
            record.setTrendArrow(trendA);
            
            recordsToReturn[k++] = record;
          }
        }       
    return recordsToReturn;
    
  }

  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 ex)
        {
          ex.printStackTrace();
        }
        
    //Write CSV of EGV from last 4 pages
        CSVWriter writer;
    try {
      
      writer = new CSVWriter(new FileWriter(new File(context.getFilesDir(), "data.csv")),',', CSVWriter.NO_QUOTE_CHARACTER);
          List<String[]> data = new ArrayList<String[]>();
          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) {
      e.printStackTrace();
    }       
  }
  
  //CRC methods
  public static int 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 crc;
      
    }
    
  //Convert the packet data
  public static int toInt(byte[] b, int flag) {
    switch(flag){
      case 0: //BitConverter.FLAG_JAVA:
        return (int)(((b[0] & 0xff)<<24) | ((b[1] & 0xff)<<16) | ((b[2] & 0xff)<<8) | (b[3] & 0xff));
      case 1: //BitConverter.FLAG_REVERSE:
        return (int)(((b[3] & 0xff)<<24) | ((b[2] & 0xff)<<16) | ((b[1] & 0xff)<<8) | (b[0] & 0xff));
      default:
        throw new IllegalArgumentException("BitConverter:toInt");
    }
  }
  
  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) {
    
    return new String[]{displayTime, bGValue, trend}; 
    
  }



}




Java Source Code List

com.ht1.cc.USB.CdcAcmSerialDriver.java
com.ht1.cc.USB.CommonUsbSerialDriver.java
com.ht1.cc.USB.HexDump.java
com.ht1.cc.USB.SerialInputOutputManager.java
com.ht1.cc.USB.USBPower.java
com.ht1.cc.USB.UsbSerialDriver.java
com.ht1.cc.USB.UsbSerialProber.java
com.ht1.cc.cgm.CSVWriter.java
com.ht1.cc.cgm.DexcomG4Activity.java
com.ht1.cc.cgm.DexcomG4Service.java
com.ht1.cc.cgm.DexcomReader.java
com.ht1.cc.cgm.EGVRecord.java
com.ht1.cc.cgm.ResultSetHelperService.java
com.ht1.cc.cgm.ResultSetHelper.java
com.ht1.cc.upload.UploadHelper.java