From ed6cabe7fa0c596b9b4976515d200be92b7fc9a1 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Wed, 13 Sep 2017 00:35:03 +0200 Subject: [PATCH 001/111] initial RS work --- app/build.gradle | 4 + app/src/main/AndroidManifest.xml | 11 + .../com/cozmo/danar/util/BleCommandUtil.java | 116 +++ .../info/nightscout/androidaps/Config.java | 2 +- .../info/nightscout/androidaps/MainApp.java | 6 +- .../androidaps/PreferencesActivity.java | 9 +- .../plugins/PumpDanaR/DanaRPump.java | 24 + .../plugins/PumpDanaRS/DanaRSPlugin.java | 765 ++++++++++++++++++ .../activities/BLEScanActivity.java | 232 ++++++ .../activities/PairingHelperActivity.java | 15 + .../activities/PairingProgressDialog.java | 148 ++++ .../comm/DanaRSMessageHashTable.java | 103 +++ .../PumpDanaRS/comm/DanaRS_Packet.java | 383 +++++++++ ...S_Packet_Basal_Cancel_Temporary_Basal.java | 36 + .../DanaRS_Packet_Basal_Get_Basal_Rate.java | 55 ++ ...S_Packet_Basal_Get_Profile_Basal_Rate.java | 61 ++ ...anaRS_Packet_Basal_Get_Profile_Number.java | 37 + .../DanaRS_Packet_Basal_Set_Basal_Rate.java | 53 ++ ...S_Packet_Basal_Set_Profile_Basal_Rate.java | 56 ++ ...anaRS_Packet_Basal_Set_Profile_Number.java | 48 ++ .../DanaRS_Packet_Basal_Set_Suspend_Off.java | 35 + .../DanaRS_Packet_Basal_Set_Suspend_On.java | 35 + ...naRS_Packet_Basal_Set_Temporary_Basal.java | 52 ++ ...RS_Packet_Basal_Temporary_Basal_State.java | 77 ++ .../DanaRS_Packet_Bolus_Get_Bolus_Option.java | 124 +++ .../DanaRS_Packet_Bolus_Get_CIR_CF_Array.java | 145 ++++ ...ket_Bolus_Get_Calculation_Information.java | 77 ++ ..._Carbohydrate_Calculation_Information.java | 47 ++ .../DanaRS_Packet_Bolus_Get_Dual_Bolus.java | 55 ++ ...anaRS_Packet_Bolus_Get_Extended_Bolus.java | 52 ++ ...Packet_Bolus_Get_Extended_Bolus_State.java | 62 ++ ..._Bolus_Get_Extended_Menu_Option_State.java | 42 + ...DanaRS_Packet_Bolus_Get_Initial_Bolus.java | 46 ++ ...cket_Bolus_Get_Step_Bolus_Information.java | 72 ++ .../DanaRS_Packet_Bolus_Set_Bolus_Option.java | 127 +++ .../DanaRS_Packet_Bolus_Set_CIR_CF_Array.java | 100 +++ .../DanaRS_Packet_Bolus_Set_Dual_Bolus.java | 60 ++ ...anaRS_Packet_Bolus_Set_Extended_Bolus.java | 56 ++ ...acket_Bolus_Set_Extended_Bolus_Cancel.java | 35 + ...DanaRS_Packet_Bolus_Set_Initial_Bolus.java | 60 ++ ...aRS_Packet_Bolus_Set_Step_Bolus_Start.java | 62 ++ ...naRS_Packet_Bolus_Set_Step_Bolus_Stop.java | 60 ++ .../DanaRS_Packet_Etc_Keep_Connection.java | 32 + .../DanaRS_Packet_Etc_Set_History_Save.java | 71 ++ ...DanaRS_Packet_General_Delivery_Status.java | 32 + ...S_Packet_General_Get_More_Information.java | 70 ++ .../DanaRS_Packet_General_Get_Password.java | 36 + .../DanaRS_Packet_General_Get_Pump_Check.java | 45 ++ ...cket_General_Get_Shipping_Information.java | 46 ++ ...cket_General_Get_Today_Delivery_Total.java | 47 ++ ...ket_General_Get_User_Time_Change_Flag.java | 32 + ...et_General_Initial_Screen_Information.java | 85 ++ ...acket_General_Set_History_Upload_Mode.java | 47 ++ ...neral_Set_User_Time_Change_Flag_Clear.java | 33 + .../comm/DanaRS_Packet_History_.java | 124 +++ .../comm/DanaRS_Packet_History_Alarm.java | 23 + .../DanaRS_Packet_History_All_History.java | 23 + .../comm/DanaRS_Packet_History_Basal.java | 23 + .../DanaRS_Packet_History_Blood_Glucose.java | 23 + .../comm/DanaRS_Packet_History_Bolus.java | 23 + .../DanaRS_Packet_History_Carbohydrate.java | 23 + .../comm/DanaRS_Packet_History_Daily.java | 23 + .../comm/DanaRS_Packet_History_Prime.java | 23 + .../comm/DanaRS_Packet_History_Refill.java | 23 + .../comm/DanaRS_Packet_History_Suspend.java | 23 + .../comm/DanaRS_Packet_History_Temporary.java | 23 + .../comm/DanaRS_Packet_Notify_Alarm.java | 88 ++ ...anaRS_Packet_Notify_Delivery_Complete.java | 54 ++ ...S_Packet_Notify_Delivery_Rate_Display.java | 56 ++ ...naRS_Packet_Notify_Missed_Bolus_Alarm.java | 54 ++ .../DanaRS_Packet_Option_Get_Pump_Time.java | 61 ++ .../DanaRS_Packet_Option_Get_User_Option.java | 114 +++ .../DanaRS_Packet_Option_Set_Pump_Time.java | 56 ++ .../DanaRS_Packet_Option_Set_User_Option.java | 58 ++ .../comm/DanaRS_Packet_Review_Bolus_Avg.java | 52 ++ .../events/EventDanaRSConnection.java | 21 + .../events/EventDanaRSDeviceChange.java | 8 + .../PumpDanaRS/events/EventDanaRSPacket.java | 15 + .../events/EventDanaRSPairingSuccess.java | 8 + .../PumpDanaRS/services/DanaRSService.java | 671 +++++++++++++++ .../plugins/PumpDanaRv2/DanaRv2Plugin.java | 2 +- .../jniLibs/arm64-v8a/libBleCommandUtil.so | Bin 0 -> 14000 bytes .../jniLibs/armeabi-v7a/libBleCommandUtil.so | Bin 0 -> 13728 bytes .../main/jniLibs/armeabi/libBleCommandUtil.so | Bin 0 -> 13724 bytes .../main/jniLibs/mips/libBleCommandUtil.so | Bin 0 -> 71484 bytes .../main/jniLibs/mips64/libBleCommandUtil.so | Bin 0 -> 14808 bytes app/src/main/jniLibs/x86/libBleCommandUtil.so | Bin 0 -> 13668 bytes .../main/jniLibs/x86_64/libBleCommandUtil.so | Bin 0 -> 14272 bytes .../res/layout/danars_blescanner_activity.xml | 22 + .../res/layout/danars_blescanner_item.xml | 33 + .../layout/danars_pairingprogressdialog.xml | 41 + app/src/main/res/values/strings.xml | 15 + app/src/main/res/xml/pref_danars.xml | 26 + 93 files changed, 6049 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/com/cozmo/danar/util/BleCommandUtil.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingHelperActivity.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRSMessageHashTable.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Cancel_Temporary_Basal.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Basal_Rate.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Basal_Rate.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Number.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Basal_Rate.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Basal_Rate.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Number.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_Off.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_On.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Temporary_Basal.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Temporary_Basal_State.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Bolus_Option.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_CIR_CF_Array.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Calculation_Information.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Initial_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Step_Bolus_Information.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Bolus_Option.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_CIR_CF_Array.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Dual_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Initial_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Start.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Keep_Connection.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Set_History_Save.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Delivery_Status.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_More_Information.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Password.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Pump_Check.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Shipping_Information.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Today_Delivery_Total.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_User_Time_Change_Flag.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Initial_Screen_Information.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_History_Upload_Mode.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Alarm.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_All_History.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Basal.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Blood_Glucose.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Bolus.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Carbohydrate.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Daily.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Prime.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Refill.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Suspend.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Temporary.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Alarm.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Complete.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Rate_Display.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Missed_Bolus_Alarm.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_Pump_Time.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_User_Option.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_Pump_Time.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_User_Option.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Review_Bolus_Avg.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSConnection.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java create mode 100644 app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so create mode 100644 app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so create mode 100644 app/src/main/jniLibs/armeabi/libBleCommandUtil.so create mode 100644 app/src/main/jniLibs/mips/libBleCommandUtil.so create mode 100644 app/src/main/jniLibs/mips64/libBleCommandUtil.so create mode 100644 app/src/main/jniLibs/x86/libBleCommandUtil.so create mode 100644 app/src/main/jniLibs/x86_64/libBleCommandUtil.so create mode 100644 app/src/main/res/layout/danars_blescanner_activity.xml create mode 100644 app/src/main/res/layout/danars_blescanner_item.xml create mode 100644 app/src/main/res/layout/danars_pairingprogressdialog.xml create mode 100644 app/src/main/res/xml/pref_danars.xml diff --git a/app/build.gradle b/app/build.gradle index 8d62dbe7f3..9631b4c5c0 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -47,6 +47,10 @@ android { version "1.52" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", generateGitBuild() + + ndk { + moduleName "BleCommandUtil" + } } lintOptions { disable 'MissingTranslation' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7d792556b7..0c23c1ee23 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,6 +50,13 @@ + + + + + + + + diff --git a/app/src/main/java/com/cozmo/danar/util/BleCommandUtil.java b/app/src/main/java/com/cozmo/danar/util/BleCommandUtil.java new file mode 100644 index 0000000000..65be0a57f4 --- /dev/null +++ b/app/src/main/java/com/cozmo/danar/util/BleCommandUtil.java @@ -0,0 +1,116 @@ +package com.cozmo.danar.util; + +import android.content.Context; + +import info.nightscout.androidaps.MainApp; + +public class BleCommandUtil { + public static final int DANAR_PACKET__TYPE_ENCRYPTION_REQUEST = 0x01; + public static final int DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE = 0x02; + public static final int DANAR_PACKET__TYPE_COMMAND = 0xA1; + public static final int DANAR_PACKET__TYPE_RESPONSE = 0xB2; + public static final int DANAR_PACKET__TYPE_NOTIFY = 0xC3; + + public static final int DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK = 0x00; + public static final int DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY = 0xD0; + public static final int DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST = 0xD1; + public static final int DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_RETURN = 0xD2; + public static final int DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION = 0x01; + + public static final int DANAR_PACKET__OPCODE_NOTIFY__DELIVERY_COMPLETE = 0x01; + public static final int DANAR_PACKET__OPCODE_NOTIFY__DELIVERY_RATE_DISPLAY = 0x02; + public static final int DANAR_PACKET__OPCODE_NOTIFY__ALARM = 0x03; + public static final int DANAR_PACKET__OPCODE_NOTIFY__MISSED_BOLUS_ALARM = 0x04; + + public static final int DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION = 0x02; + public static final int DANAR_PACKET__OPCODE_REVIEW__DELIVERY_STATUS = 0x03; + public static final int DANAR_PACKET__OPCODE_REVIEW__GET_PASSWORD = 0x04; + + public static final int DANAR_PACKET__OPCODE_REVIEW__BOLUS_AVG = 0x10; + public static final int DANAR_PACKET__OPCODE_REVIEW__BOLUS = 0x11; + public static final int DANAR_PACKET__OPCODE_REVIEW__DAILY = 0x12; + public static final int DANAR_PACKET__OPCODE_REVIEW__PRIME = 0x13; + public static final int DANAR_PACKET__OPCODE_REVIEW__REFILL = 0x14; + public static final int DANAR_PACKET__OPCODE_REVIEW__BLOOD_GLUCOSE = 0x15; + public static final int DANAR_PACKET__OPCODE_REVIEW__CARBOHYDRATE = 0x16; + public static final int DANAR_PACKET__OPCODE_REVIEW__TEMPORARY = 0x17; + public static final int DANAR_PACKET__OPCODE_REVIEW__SUSPEND = 0x18; + public static final int DANAR_PACKET__OPCODE_REVIEW__ALARM = 0x19; + public static final int DANAR_PACKET__OPCODE_REVIEW__BASAL = 0x1A; + public static final int DANAR_PACKET__OPCODE_REVIEW__ALL_HISTORY = 0x1F; + public static final int DANAR_PACKET__OPCODE_REVIEW__GET_SHIPPING_INFORMATION = 0x20; + public static final int DANAR_PACKET__OPCODE_REVIEW__GET_PUMP_CHECK = 0x21; + public static final int DANAR_PACKET__OPCODE_REVIEW__GET_USER_TIME_CHANGE_FLAG = 0x22; + public static final int DANAR_PACKET__OPCODE_REVIEW__SET_USER_TIME_CHANGE_FLAG_CLEAR = 0x23; + public static final int DANAR_PACKET__OPCODE_REVIEW__GET_MORE_INFORMATION = 0x24; + public static final int DANAR_PACKET__OPCODE_REVIEW__SET_HISTORY_UPLOAD_MODE = 0x25; + public static final int DANAR_PACKET__OPCODE_REVIEW__GET_TODAY_DELIVERY_TOTAL = 0x26; + + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_STEP_BOLUS_INFORMATION = 0x40; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_BOLUS_STATE = 0x41; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_BOLUS = 0x42; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_DUAL_BOLUS = 0x43; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_STOP = 0x44; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_CARBOHYDRATE_CALCULATION_INFORMATION = 0x45; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_MENU_OPTION_STATE = 0x46; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_EXTENDED_BOLUS = 0x47; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_DUAL_BOLUS = 0x48; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_EXTENDED_BOLUS_CANCEL = 0x49; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_START = 0x4A; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_CALCULATION_INFORMATION = 0x4B; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_BOLUS_RATE = 0x4C; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_BOLUS_RATE = 0x4D; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_CIR_CF_ARRAY = 0x4E; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_CIR_CF_ARRAY = 0x4F; + public static final int DANAR_PACKET__OPCODE_BOLUS__GET_BOLUS_OPTION = 0x50; + public static final int DANAR_PACKET__OPCODE_BOLUS__SET_BOLUS_OPTION = 0x51; + + public static final int DANAR_PACKET__OPCODE_BASAL__SET_TEMPORARY_BASAL = 0x60; + public static final int DANAR_PACKET__OPCODE_BASAL__TEMPORARY_BASAL_STATE = 0x61; + public static final int DANAR_PACKET__OPCODE_BASAL__CANCEL_TEMPORARY_BASAL = 0x62; + public static final int DANAR_PACKET__OPCODE_BASAL__GET_PROFILE_NUMBER = 0x63; + public static final int DANAR_PACKET__OPCODE_BASAL__SET_PROFILE_NUMBER = 0x64; + public static final int DANAR_PACKET__OPCODE_BASAL__GET_PROFILE_BASAL_RATE = 0x65; + public static final int DANAR_PACKET__OPCODE_BASAL__SET_PROFILE_BASAL_RATE = 0x66; + public static final int DANAR_PACKET__OPCODE_BASAL__GET_BASAL_RATE = 0x67; + public static final int DANAR_PACKET__OPCODE_BASAL__SET_BASAL_RATE = 0x68; + public static final int DANAR_PACKET__OPCODE_BASAL__SET_SUSPEND_ON = 0x69; + public static final int DANAR_PACKET__OPCODE_BASAL__SET_SUSPEND_OFF = 0x6A; + + public static final int DANAR_PACKET__OPCODE_OPTION__GET_PUMP_TIME = 0x70; + public static final int DANAR_PACKET__OPCODE_OPTION__SET_PUMP_TIME = 0x71; + public static final int DANAR_PACKET__OPCODE_OPTION__GET_USER_OPTION = 0x72; + public static final int DANAR_PACKET__OPCODE_OPTION__SET_USER_OPTION = 0x73; + + public static final int DANAR_PACKET__OPCODE_ETC__SET_HISTORY_SAVE = 0xE0; + public static final int DANAR_PACKET__OPCODE_ETC__KEEP_CONNECTION = 0xFF; + + static { + System.loadLibrary("BleCommandUtil"); + } + + private static native byte[] getEncryptedPacketJni(Object context, int opcode, byte[] bytes, String deviceName); + + private static native byte[] getDecryptedPacketJni(Object context, byte[] bytes); + + // --------------------------------------------------------- + + private static BleCommandUtil mInstance = null; + + public static BleCommandUtil getInstance() { + if (mInstance == null) { + mInstance = new BleCommandUtil(); + } + return mInstance; + } + + // --------------------------------------------------------- + + public byte[] getEncryptedPacket(int opcode, byte[] bytes, String deviceName) { + return getEncryptedPacketJni(MainApp.instance().getApplicationContext(), opcode, bytes, deviceName); + } + + public byte[] getDecryptedPacket(byte[] bytes) { + return getDecryptedPacketJni(MainApp.instance().getApplicationContext(), bytes); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/Config.java b/app/src/main/java/info/nightscout/androidaps/Config.java index e6c06583c9..98b735feae 100644 --- a/app/src/main/java/info/nightscout/androidaps/Config.java +++ b/app/src/main/java/info/nightscout/androidaps/Config.java @@ -44,6 +44,6 @@ public class Config { // DanaR specific public static final boolean logDanaBTComm = true; - public static final boolean logDanaMessageDetail = true; + public static boolean logDanaMessageDetail = true; public static final boolean logDanaSerialEngine = true; } diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index fcd92331b0..b6fd597207 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainApp.java +++ b/app/src/main/java/info/nightscout/androidaps/MainApp.java @@ -52,6 +52,8 @@ import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.services.DanaRKoreanExecutionService; +import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; +import info.nightscout.androidaps.plugins.PumpDanaRS.services.DanaRSService; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.services.DanaRv2ExecutionService; import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin; @@ -123,7 +125,8 @@ public class MainApp extends Application { pluginsList.add(SensitivityWeightedAveragePlugin.getPlugin()); if (Config.DANAR) pluginsList.add(DanaRPlugin.getPlugin()); if (Config.DANAR) pluginsList.add(DanaRKoreanPlugin.getPlugin()); - if (Config.DANARv2) pluginsList.add(DanaRv2Plugin.getPlugin()); + if (Config.DANAR) pluginsList.add(DanaRv2Plugin.getPlugin()); + if (Config.DANAR) pluginsList.add(DanaRSPlugin.getPlugin()); pluginsList.add(CareportalFragment.getPlugin()); if (Config.MDI) pluginsList.add(MDIPlugin.getPlugin()); if (Config.VIRTUALPUMP) pluginsList.add(VirtualPumpPlugin.getInstance()); @@ -207,6 +210,7 @@ public class MainApp extends Application { startService(new Intent(this, DanaRExecutionService.class)); startService(new Intent(this, DanaRKoreanExecutionService.class)); startService(new Intent(this, DanaRv2ExecutionService.class)); + startService(new Intent(this, DanaRSService.class)); } keepAliveReceiver.setAlarm(this); } diff --git a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java index c5abda1eae..6abd8d58fb 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -20,6 +20,7 @@ import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; import info.nightscout.androidaps.plugins.NSClientInternal.NSClientInternalPlugin; import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin; +import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin; import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin; import info.nightscout.androidaps.plugins.SensitivityAAPS.SensitivityAAPSPlugin; @@ -69,6 +70,8 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre EditTextPreference editTextPref = (EditTextPreference) pref; if (pref.getKey().contains("password") || pref.getKey().contains("secret")) { pref.setSummary("******"); + } else if (pref.getKey().equals(MainApp.sResources.getString(R.string.key_danars_name))) { + pref.setSummary(SP.getString(R.string.key_danars_name,"")); } else if (editTextPref.getText() != null && !editTextPref.getText().equals("")) { ((EditTextPreference) pref).setDialogMessage(editTextPref.getDialogMessage()); pref.setSummary(editTextPref.getText()); @@ -126,12 +129,16 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre DanaRPlugin danaRPlugin = MainApp.getSpecificPlugin(DanaRPlugin.class); DanaRKoreanPlugin danaRKoreanPlugin = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class); DanaRv2Plugin danaRv2Plugin = MainApp.getSpecificPlugin(DanaRv2Plugin.class); + DanaRSPlugin danaRSPlugin = MainApp.getSpecificPlugin(DanaRSPlugin.class); if (danaRPlugin.isEnabled(PluginBase.PUMP) || danaRKoreanPlugin.isEnabled(PluginBase.PUMP)) { addPreferencesFromResource(R.xml.pref_danar); } if (danaRv2Plugin != null && danaRv2Plugin.isEnabled(PluginBase.PUMP)) { addPreferencesFromResource(R.xml.pref_danarv2); } + if (danaRSPlugin != null && danaRSPlugin.isEnabled(PluginBase.PUMP)) { + addPreferencesFromResource(R.xml.pref_danars); + } if (danaRPlugin.isEnabled(PluginBase.PROFILE) || danaRKoreanPlugin.isEnabled(PluginBase.PROFILE) || danaRv2Plugin != null && danaRv2Plugin.isEnabled(PluginBase.PROFILE)) { addPreferencesFromResource(R.xml.pref_danarprofile); } @@ -141,7 +148,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre addPreferencesFromResource(R.xml.pref_virtualpump); } InsulinOrefFreePeakPlugin insulinOrefFreePeakPlugin = MainApp.getSpecificPlugin(InsulinOrefFreePeakPlugin.class); - if(insulinOrefFreePeakPlugin.isEnabled(PluginBase.INSULIN)){ + if (insulinOrefFreePeakPlugin.isEnabled(PluginBase.INSULIN)) { addPreferencesFromResource(R.xml.pref_insulinoreffreepeak); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java index 7948d00d96..021b4d7a3d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPump.java @@ -78,6 +78,8 @@ public class DanaRPump { public boolean pumpSuspended; public boolean calculatorEnabled; public double dailyTotalUnits; + public double dailyTotalBolusUnits = 0; // RS only + public double dailyTotalBasalUnits = 0; // RS only public int maxDailyTotalUnits; public double bolusStep; @@ -108,6 +110,7 @@ public class DanaRPump { public int extendedBolusSoFarInMinutes; public Date extendedBolusStart; public int extendedBolusRemainingMinutes; + public double extendedBolusDeliveredSoFar; //RS only // Profile public int units; @@ -136,6 +139,27 @@ public class DanaRPump { public double maxBolus; public double maxBasal; + // DanaRS specific + + public String rs_password = ""; + + // User settings + public int timeDisplayType; + public int buttonScrollOnOff; + public int beepAndAlarm; + public int lcdOnTimeSec; + public int backlightOnTimeSec; + public int selectedLanguage; + public int shutdownHour; + public int lowReservoirRate; + public int cannulaVolume; + public int refillAmount; + + public double initialBolusAmount; + // Bolus settings + public int bolusCalculationOption; + public int missedBolusConfig; + public String getUnits() { return units == UNITS_MGDL ? Constants.MGDL : Constants.MMOL; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java new file mode 100644 index 0000000000..3b71df7d2b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java @@ -0,0 +1,765 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.support.annotation.Nullable; + +import com.squareup.otto.Subscribe; + +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; +import java.util.Objects; + +import info.nightscout.androidaps.BuildConfig; +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.ProfileStore; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.db.ExtendedBolus; +import info.nightscout.androidaps.db.TemporaryBasal; +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.DanaRInterface; +import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.ProfileInterface; +import info.nightscout.androidaps.interfaces.PumpDescription; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage; +import info.nightscout.androidaps.plugins.Overview.Notification; +import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; +import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; +import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRFragment; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventAppExit; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSDeviceChange; +import info.nightscout.androidaps.plugins.PumpDanaRS.services.DanaRSService; +import info.nightscout.utils.DateUtil; +import info.nightscout.utils.Round; +import info.nightscout.utils.SP; + +/** + * Created by mike on 03.09.2017. + */ + +public class DanaRSPlugin implements PluginBase, PumpInterface, DanaRInterface, ConstraintsInterface, ProfileInterface { + private static Logger log = LoggerFactory.getLogger(DanaRSPlugin.class); + + @Override + public int getType() { + return PluginBase.PUMP; + } + + @Override + public String getFragmentClass() { + return DanaRFragment.class.getName(); + } + + @Override + public String getName() { + return MainApp.instance().getString(R.string.danarspump); + } + + @Override + public String getNameShort() { + String name = MainApp.sResources.getString(R.string.danarspump_shortname); + if (!name.trim().isEmpty()) { + //only if translation exists + return name; + } + // use long name as fallback + return getName(); + } + + @Override + public boolean isEnabled(int type) { + if (type == PluginBase.PROFILE) return fragmentProfileEnabled && fragmentPumpEnabled; + else if (type == PluginBase.PUMP) return fragmentPumpEnabled; + else if (type == PluginBase.CONSTRAINTS) return fragmentPumpEnabled; + return false; + } + + @Override + public boolean isVisibleInTabs(int type) { + if (type == PluginBase.PROFILE || type == PluginBase.CONSTRAINTS) return false; + else if (type == PluginBase.PUMP) return fragmentPumpVisible; + return false; + } + + @Override + public boolean canBeHidden(int type) { + return true; + } + + @Override + public boolean hasFragment() { + return true; + } + + @Override + public boolean showInList(int type) { + return type == PUMP; + } + + @Override + public void setFragmentEnabled(int type, boolean fragmentEnabled) { + if (type == PluginBase.PROFILE) + this.fragmentProfileEnabled = fragmentEnabled; + else if (type == PluginBase.PUMP) + this.fragmentPumpEnabled = fragmentEnabled; + // if pump profile was enabled need to switch to another too + if (type == PluginBase.PUMP && !fragmentEnabled && this.fragmentProfileEnabled) { + setFragmentEnabled(PluginBase.PROFILE, false); + setFragmentVisible(PluginBase.PROFILE, false); + MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentEnabled(PluginBase.PROFILE, true); + MainApp.getSpecificPlugin(NSProfilePlugin.class).setFragmentVisible(PluginBase.PROFILE, true); + } + } + + @Override + public void setFragmentVisible(int type, boolean fragmentVisible) { + if (type == PluginBase.PUMP) + this.fragmentPumpVisible = fragmentVisible; + } + + static boolean fragmentPumpEnabled = false; + static boolean fragmentProfileEnabled = false; + static boolean fragmentPumpVisible = false; + + public static DanaRSService danaRSService; + + public static String mDeviceAddress = ""; + public static String mDeviceName = ""; + + private static DanaRSPlugin plugin = null; + private static DanaRPump pump = DanaRPump.getInstance(); + public static PumpDescription pumpDescription = new PumpDescription(); + + public static DanaRSPlugin getPlugin() { + if (plugin == null) + plugin = new DanaRSPlugin(); + return plugin; + } + + DanaRSPlugin() { + Context context = MainApp.instance().getApplicationContext(); + Intent intent = new Intent(context, DanaRSService.class); + context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + MainApp.bus().register(this); + onStatusEvent(new EventDanaRSDeviceChange()); // load device name + + pumpDescription.isBolusCapable = true; + pumpDescription.bolusStep = 0.05d; + + pumpDescription.isExtendedBolusCapable = true; + pumpDescription.extendedBolusStep = 0.05d; + pumpDescription.extendedBolusDurationStep = 30; + pumpDescription.extendedBolusMaxDuration = 8 * 60; + + pumpDescription.isTempBasalCapable = true; + pumpDescription.tempBasalStyle = PumpDescription.PERCENT; + + pumpDescription.maxTempPercent = 200; + pumpDescription.tempPercentStep = 10; + + pumpDescription.tempDurationStep = 60; + pumpDescription.tempMaxDuration = 24 * 60; + + + pumpDescription.isSetBasalProfileCapable = true; + pumpDescription.basalStep = 0.01d; + pumpDescription.basalMinimumRate = 0.04d; + + pumpDescription.isRefillingCapable = true; + } + + private ServiceConnection mConnection = new ServiceConnection() { + + public void onServiceDisconnected(ComponentName name) { + log.debug("Service is disconnected"); + danaRSService = null; + } + + public void onServiceConnected(ComponentName name, IBinder service) { + log.debug("Service is connected"); + DanaRSService.LocalBinder mLocalBinder = (DanaRSService.LocalBinder) service; + danaRSService = mLocalBinder.getServiceInstance(); + } + }; + + @SuppressWarnings("UnusedParameters") + @Subscribe + public void onStatusEvent(final EventAppExit e) { + MainApp.instance().getApplicationContext().unbindService(mConnection); + } + + @Subscribe + public void onStatusEvent(final EventDanaRSDeviceChange e) { + mDeviceAddress = SP.getString(R.string.key_danars_address, ""); + mDeviceName = SP.getString(R.string.key_danars_name, ""); + } + + public static void connect(String from) { + if (danaRSService != null && !mDeviceAddress.equals("") && !mDeviceName.equals("")) + danaRSService.connect(from, mDeviceAddress); + } + + public static boolean isConnected() { + return danaRSService != null && danaRSService.isConnected(); + } + + public static boolean isConnecting() { + return danaRSService != null && danaRSService.isConnecting(); + } + + public static void disconnect(String from) { + if (danaRSService != null) danaRSService.disconnect(from); + } + + public static void sendMessage(DanaRS_Packet message) { + if (danaRSService != null) danaRSService.sendMessage(message); + } + + // DanaR interface + + @Override + public boolean loadHistory(byte type) { + return danaRSService.loadHistory(type); + } + + // Constraints interface + + @Override + public boolean isLoopEnabled() { + return true; + } + + @Override + public boolean isClosedModeEnabled() { + return true; + } + + @Override + public boolean isAutosensModeEnabled() { + return true; + } + + @Override + public boolean isAMAModeEnabled() { + return true; + } + + @Override + public Double applyBasalConstraints(Double absoluteRate) { + double origAbsoluteRate = absoluteRate; + if (pump != null) { + if (absoluteRate > pump.maxBasal) { + absoluteRate = pump.maxBasal; + if (Config.logConstraintsChanges && origAbsoluteRate != Constants.basalAbsoluteOnlyForCheckLimit) + log.debug("Limiting rate " + origAbsoluteRate + "U/h by pump constraint to " + absoluteRate + "U/h"); + } + } + return absoluteRate; + } + + @Override + public Integer applyBasalConstraints(Integer percentRate) { + Integer origPercentRate = percentRate; + if (percentRate < 0) percentRate = 0; + if (percentRate > getPumpDescription().maxTempPercent) + percentRate = getPumpDescription().maxTempPercent; + if (!Objects.equals(percentRate, origPercentRate) && Config.logConstraintsChanges && !Objects.equals(origPercentRate, Constants.basalPercentOnlyForCheckLimit)) + log.debug("Limiting percent rate " + origPercentRate + "% to " + percentRate + "%"); + return percentRate; + } + + @Override + public Double applyBolusConstraints(Double insulin) { + double origInsulin = insulin; + if (pump != null) { + if (insulin > pump.maxBolus) { + insulin = pump.maxBolus; + if (Config.logConstraintsChanges && origInsulin != Constants.bolusOnlyForCheckLimit) + log.debug("Limiting bolus " + origInsulin + "U by pump constraint to " + insulin + "U"); + } + } + return insulin; + } + + @Override + public Integer applyCarbsConstraints(Integer carbs) { + return carbs; + } + + @Override + public Double applyMaxIOBConstraints(Double maxIob) { + return maxIob; + } + + // Profile interface + + @Nullable + @Override + public ProfileStore getProfile() { + if (pump.lastSettingsRead.getTime() == 0) + return null; // no info now + return pump.createConvertedProfile(); + } + + @Override + public String getUnits() { + return pump.getUnits(); + } + + @Override + public String getProfileName() { + return pump.createConvertedProfileName(); + } + + // Pump interface + + @Override + public boolean isInitialized() { + return pump.lastConnection.getTime() > 0; + } + + @Override + public boolean isSuspended() { + return pump.pumpSuspended; + } + + @Override + public boolean isBusy() { + if (danaRSService == null) return false; + return danaRSService.isConnected() || danaRSService.isConnecting(); + } + + @Override + public int setNewBasalProfile(Profile profile) { + if (danaRSService == null) { + log.error("setNewBasalProfile sExecutionService is null"); + return FAILED; + } + if (!isInitialized()) { + log.error("setNewBasalProfile not initialized"); + Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.sResources.getString(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT); + MainApp.bus().post(new EventNewNotification(notification)); + return FAILED; + } else { + MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED)); + } + if (!danaRSService.updateBasalsInPump(profile)) { + Notification notification = new Notification(Notification.FAILED_UDPATE_PROFILE, MainApp.sResources.getString(R.string.failedupdatebasalprofile), Notification.URGENT); + MainApp.bus().post(new EventNewNotification(notification)); + return FAILED; + } else { + MainApp.bus().post(new EventDismissNotification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED)); + MainApp.bus().post(new EventDismissNotification(Notification.FAILED_UDPATE_PROFILE)); + return SUCCESS; + } + } + + @Override + public boolean isThisProfileSet(Profile profile) { + if (!isInitialized()) + return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS + if (pump.pumpProfiles == null) + return true; // TODO: not sure what's better. so far TRUE to prevent too many SMS + int basalValues = pump.basal48Enable ? 48 : 24; + int basalIncrement = pump.basal48Enable ? 30 * 60 : 60 * 60; + for (int h = 0; h < basalValues; h++) { + Double pumpValue = pump.pumpProfiles[pump.activeProfile][h]; + Double profileValue = profile.getBasal((Integer) (h * basalIncrement)); + if (profileValue == null) return true; + if (Math.abs(pumpValue - profileValue) > getPumpDescription().basalStep) { + log.debug("Diff found. Hour: " + h + " Pump: " + pumpValue + " Profile: " + profileValue); + return false; + } + } + return true; + } + + @Override + public Date lastDataTime() { + return pump.lastConnection; + } + + @Override + public void refreshDataFromPump(String reason) { + if (!isConnected() && !isConnecting()) { + connect(reason); + } + } + + @Override + public double getBaseBasalRate() { + return pump.currentBasal; + } + + @Override + public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { + ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); + detailedBolusInfo.insulin = configBuilderPlugin.applyBolusConstraints(detailedBolusInfo.insulin); + if (detailedBolusInfo.insulin > 0 || detailedBolusInfo.carbs > 0) { + DetailedBolusInfoStorage.add(detailedBolusInfo); // will be picked up on reading history + // v2 stores end time for bolus, we need to adjust time + // delivery speed is 12 U/min + detailedBolusInfo.date += detailedBolusInfo.insulin / 12d * 60 * 1000; + // clean carbs to prevent counting them as twice because they will picked up as another record + // I don't think it's necessary to copy DetailedBolusInfo right now for carbs records + double carbs = detailedBolusInfo.carbs; + detailedBolusInfo.carbs = 0; + int carbTime = detailedBolusInfo.carbTime; + detailedBolusInfo.carbTime = 0; + + Treatment t = new Treatment(); + boolean connectionOK = false; + if (detailedBolusInfo.insulin > 0 || carbs > 0) + connectionOK = danaRSService.bolus(detailedBolusInfo.insulin, (int) carbs, System.currentTimeMillis() + carbTime * 60 * 1000 + 1000, t); // +1000 to make the record different + PumpEnactResult result = new PumpEnactResult(); + result.success = connectionOK; + result.bolusDelivered = t.insulin; + result.carbsDelivered = detailedBolusInfo.carbs; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + if (Config.logPumpActions) + log.debug("deliverTreatment: OK. Asked: " + detailedBolusInfo.insulin + " Delivered: " + result.bolusDelivered); + // remove carbs because it's get from history seprately + return result; + } else { + PumpEnactResult result = new PumpEnactResult(); + result.success = false; + result.bolusDelivered = 0d; + result.carbsDelivered = 0d; + result.comment = MainApp.instance().getString(R.string.danar_invalidinput); + log.error("deliverTreatment: Invalid input"); + return result; + } + } + + @Override + public void stopBolusDelivering() { + if (danaRSService == null) { + log.error("stopBolusDelivering sExecutionService is null"); + return; + } + danaRSService.bolusStop(); + } + + // This is called from APS + @Override + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { + // Recheck pump status if older than 30 min + if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { + connect("setTempBasalAbsolute old data"); + } + + PumpEnactResult result = new PumpEnactResult(); + + ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); + absoluteRate = configBuilderPlugin.applyBasalConstraints(absoluteRate); + + final boolean doTempOff = getBaseBasalRate() - absoluteRate == 0d; + final boolean doLowTemp = absoluteRate < getBaseBasalRate(); + final boolean doHighTemp = absoluteRate > getBaseBasalRate(); + + if (doTempOff) { + // If temp in progress + if (MainApp.getConfigBuilder().isTempBasalInProgress()) { + if (Config.logPumpActions) + log.debug("setTempBasalAbsolute: Stopping temp basal (doTempOff)"); + return cancelTempBasal(false); + } + result.success = true; + result.enacted = false; + result.percent = 100; + result.isPercent = true; + result.isTempCancel = true; + if (Config.logPumpActions) + log.debug("setTempBasalAbsolute: doTempOff OK"); + return result; + } + + if (doLowTemp || doHighTemp) { + Integer percentRate = Double.valueOf(absoluteRate / getBaseBasalRate() * 100).intValue(); + if (percentRate < 100) percentRate = Round.ceilTo((double) percentRate, 10d).intValue(); + else percentRate = Round.floorTo((double) percentRate, 10d).intValue(); + if (percentRate > 500) // Special high temp 500/15min + percentRate = 500; + // Check if some temp is already in progress + if (MainApp.getConfigBuilder().isTempBasalInProgress()) { + // Correct basal already set ? + if (MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()).percentRate == percentRate) { + if (!force) { + result.success = true; + result.percent = percentRate; + result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory(); + result.enacted = false; + result.duration = ((Double) MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory()).intValue(); + result.isPercent = true; + result.isTempCancel = false; + if (Config.logPumpActions) + log.debug("setTempBasalAbsolute: Correct temp basal already set (doLowTemp || doHighTemp)"); + return result; + } + } + } + // Convert duration from minutes to hours + if (Config.logPumpActions) + log.debug("setTempBasalAbsolute: Setting temp basal " + percentRate + "% for " + durationInMinutes + " mins (doLowTemp || doHighTemp)"); + // use special APS temp basal call ... 100+/15min .... 100-/30min + result = setHighTempBasalPercent(percentRate); + if (!result.success) { + log.error("setTempBasalAbsolute: Failed to set hightemp basal"); + return result; + } + if (Config.logPumpActions) + log.debug("setTempBasalAbsolute: hightemp basal set ok"); + return result; + } + // We should never end here + log.error("setTempBasalAbsolute: Internal error"); + result.success = false; + result.comment = "Internal error"; + return result; + } + + @Override + public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes) { + PumpEnactResult result = new PumpEnactResult(); + ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); + percent = configBuilderPlugin.applyBasalConstraints(percent); + if (percent < 0) { + result.isTempCancel = false; + result.enacted = false; + result.success = false; + result.comment = MainApp.instance().getString(R.string.danar_invalidinput); + log.error("setTempBasalPercent: Invalid input"); + return result; + } + if (percent > getPumpDescription().maxTempPercent) + percent = getPumpDescription().maxTempPercent; + if (pump.isTempBasalInProgress && pump.tempBasalPercent == percent) { + result.enacted = false; + result.success = true; + result.isTempCancel = false; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + result.duration = pump.tempBasalRemainingMin; + result.percent = pump.tempBasalPercent; + result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory(); + result.isPercent = true; + if (Config.logPumpActions) + log.debug("setTempBasalPercent: Correct value already set"); + return result; + } + int durationInHours = Math.max(durationInMinutes / 60, 1); + boolean connectionOK = danaRSService.tempBasal(percent, durationInHours); + if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) { + result.enacted = true; + result.success = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + result.isTempCancel = false; + result.duration = pump.tempBasalRemainingMin; + result.percent = pump.tempBasalPercent; + result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory(); + result.isPercent = true; + if (Config.logPumpActions) + log.debug("setTempBasalPercent: OK"); + return result; + } + result.enacted = false; + result.success = false; + result.comment = MainApp.instance().getString(R.string.tempbasaldeliveryerror); + log.error("setTempBasalPercent: Failed to set temp basal"); + return result; + } + + public PumpEnactResult setHighTempBasalPercent(Integer percent) { + PumpEnactResult result = new PumpEnactResult(); + boolean connectionOK = danaRSService.highTempBasal(percent); + if (connectionOK && pump.isTempBasalInProgress && pump.tempBasalPercent == percent) { + result.enacted = true; + result.success = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + result.isTempCancel = false; + result.duration = pump.tempBasalRemainingMin; + result.percent = pump.tempBasalPercent; + result.isPercent = true; + if (Config.logPumpActions) + log.debug("setHighTempBasalPercent: OK"); + return result; + } + result.enacted = false; + result.success = false; + result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly); + log.error("setHighTempBasalPercent: Failed to set temp basal"); + return result; + } + + @Override + public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { + ConfigBuilderPlugin configBuilderPlugin = MainApp.getConfigBuilder(); + insulin = configBuilderPlugin.applyBolusConstraints(insulin); + // needs to be rounded + int durationInHalfHours = Math.max(durationInMinutes / 30, 1); + insulin = Round.roundTo(insulin, getPumpDescription().extendedBolusStep * (1 + durationInHalfHours % 1)); + PumpEnactResult result = new PumpEnactResult(); + if (pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) { + result.enacted = false; + result.success = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + result.duration = pump.extendedBolusRemainingMinutes; + result.absolute = pump.extendedBolusAbsoluteRate; + result.isPercent = false; + result.isTempCancel = false; + if (Config.logPumpActions) + log.debug("setExtendedBolus: Correct extended bolus already set. Current: " + pump.extendedBolusAmount + " Asked: " + insulin); + return result; + } + boolean connectionOK = danaRSService.extendedBolus(insulin, durationInHalfHours); + if (connectionOK && pump.isExtendedInProgress && Math.abs(pump.extendedBolusAmount - insulin) < getPumpDescription().extendedBolusStep) { + result.enacted = true; + result.success = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + result.isTempCancel = false; + result.duration = pump.extendedBolusRemainingMinutes; + result.absolute = pump.extendedBolusAbsoluteRate; + result.bolusDelivered = pump.extendedBolusAmount; + result.isPercent = false; + if (Config.logPumpActions) + log.debug("setExtendedBolus: OK"); + return result; + } + result.enacted = false; + result.success = false; + result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly); + log.error("setExtendedBolus: Failed to extended bolus"); + return result; + } + + @Override + public PumpEnactResult cancelTempBasal(boolean force) { + PumpEnactResult result = new PumpEnactResult(); + if (pump.isTempBasalInProgress) { + danaRSService.tempBasalStop(); + result.enacted = true; + result.isTempCancel = true; + } + if (!pump.isTempBasalInProgress) { + result.success = true; + result.isTempCancel = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + if (Config.logPumpActions) + log.debug("cancelRealTempBasal: OK"); + return result; + } else { + result.success = false; + result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly); + result.isTempCancel = true; + log.error("cancelRealTempBasal: Failed to cancel temp basal"); + return result; + } + } + + @Override + public PumpEnactResult cancelExtendedBolus() { + PumpEnactResult result = new PumpEnactResult(); + if (pump.isExtendedInProgress) { + danaRSService.extendedBolusStop(); + result.enacted = true; + result.isTempCancel = true; + } + if (!pump.isExtendedInProgress) { + result.success = true; + result.comment = MainApp.instance().getString(R.string.virtualpump_resultok); + if (Config.logPumpActions) + log.debug("cancelExtendedBolus: OK"); + return result; + } else { + result.success = false; + result.comment = MainApp.instance().getString(R.string.danar_valuenotsetproperly); + log.error("cancelExtendedBolus: Failed to cancel extended bolus"); + return result; + } + } + + @Override + public JSONObject getJSONStatus() { + if (pump.lastConnection.getTime() + 5 * 60 * 1000L < System.currentTimeMillis()) { + return null; + } + JSONObject pumpjson = new JSONObject(); + JSONObject battery = new JSONObject(); + JSONObject status = new JSONObject(); + JSONObject extended = new JSONObject(); + try { + battery.put("percent", pump.batteryRemaining); + status.put("status", pump.pumpSuspended ? "suspended" : "normal"); + status.put("timestamp", DateUtil.toISOString(pump.lastConnection)); + extended.put("Version", BuildConfig.VERSION_NAME + "-" + BuildConfig.BUILDVERSION); + extended.put("PumpIOB", pump.iob); + if (pump.lastBolusTime.getTime() != 0) { + extended.put("LastBolus", pump.lastBolusTime.toLocaleString()); + extended.put("LastBolusAmount", pump.lastBolusAmount); + } + TemporaryBasal tb = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); + if (tb != null) { + extended.put("TempBasalAbsoluteRate", tb.tempBasalConvertedToAbsolute(System.currentTimeMillis())); + extended.put("TempBasalStart", DateUtil.dateAndTimeString(tb.date)); + extended.put("TempBasalRemaining", tb.getPlannedRemainingMinutes()); + } + ExtendedBolus eb = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()); + if (eb != null) { + extended.put("ExtendedBolusAbsoluteRate", eb.absoluteRate()); + extended.put("ExtendedBolusStart", DateUtil.dateAndTimeString(eb.date)); + extended.put("ExtendedBolusRemaining", eb.getPlannedRemainingMinutes()); + } + extended.put("BaseBasalRate", getBaseBasalRate()); + try { + extended.put("ActiveProfile", MainApp.getConfigBuilder().getProfileName()); + } catch (Exception e) { + } + + pumpjson.put("battery", battery); + pumpjson.put("status", status); + pumpjson.put("extended", extended); + pumpjson.put("reservoir", (int) pump.reservoirRemainingUnits); + pumpjson.put("clock", DateUtil.toISOString(new Date())); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return pumpjson; + } + + @Override + public String deviceID() { + return pump.serialNumber; + } + + @Override + public PumpDescription getPumpDescription() { + return pumpDescription; + } + + @Override + public String shortStatus(boolean veryShort) { + return null; + } + + @Override + public boolean isFakingTempsByExtendedBoluses() { + return false; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java new file mode 100644 index 0000000000..8e973903f9 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/BLEScanActivity.java @@ -0,0 +1,232 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.activities; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanResult; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.support.v7.app.AppCompatActivity; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; +import android.widget.ListView; +import android.widget.TextView; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSDeviceChange; +import info.nightscout.utils.SP; + +public class BLEScanActivity extends AppCompatActivity { + private static Logger log = LoggerFactory.getLogger(BLEScanActivity.class); + + private Context mContext = null; + + private ListView listView = null; + private ListAdapter mListAdapter = null; + private ArrayList mDevices = new ArrayList<>(); + ; + + private BluetoothAdapter mBluetoothAdapter = null; + private BluetoothLeScanner mBluetoothLeScanner = null; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.danars_blescanner_activity); + + mListAdapter = new ListAdapter(); + + listView = (ListView) findViewById(R.id.danars_blescanner_listview); + listView.setEmptyView(findViewById(R.id.danars_blescanner_nodevice)); + listView.setAdapter(mListAdapter); + + initView(); + } + + private void initView() { + mContext = getApplicationContext(); + + BluetoothManager bluetoothManager = (BluetoothManager) mContext.getSystemService(Context.BLUETOOTH_SERVICE); + mBluetoothAdapter = bluetoothManager.getAdapter(); + mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner(); + + // MIKE: test mBluetoothLeScanner for null (bt disabled) + + mListAdapter.notifyDataSetChanged(); + + } + + @Override + protected void onResume() { + super.onResume(); + + startScan(); + } + + @Override + protected void onPause() { + super.onPause(); + + stopScan(); + } + + private void startScan() { + mBluetoothLeScanner.startScan(mBleScanCallback); + } + + private void stopScan() { + mBluetoothLeScanner.stopScan(mBleScanCallback); + } + + private void addBleDevice(BluetoothDevice device) { + if (device == null || device.getName() == null || device.getName().equals("")) { + return; + } + BluetoothDeviceItem item = new BluetoothDeviceItem(device); + if (!isSNCheck(device.getName()) || mDevices.contains(item)) { + return; + } + + mDevices.add(item); + new Handler().post(new Runnable() { + public void run() { + mListAdapter.notifyDataSetChanged(); + } + }); + } + + private ScanCallback mBleScanCallback = new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + addBleDevice(result.getDevice()); + } + }; + + class ListAdapter extends BaseAdapter { + + @Override + public int getCount() { + return mDevices.size(); + } + + @Override + public BluetoothDeviceItem getItem(int i) { + return mDevices.get(i); + } + + @Override + public long getItemId(int i) { + return 0; + } + + @Override + public View getView(int i, View convertView, ViewGroup parent) { + View v = convertView; + ViewHolder holder; + + if (v == null) { + v = View.inflate(mContext, R.layout.danars_blescanner_item, null); + holder = new ViewHolder(v); + v.setTag(holder); + } else { + holder = (ViewHolder) v.getTag(); + } + + BluetoothDeviceItem item = getItem(i); + holder.setData(i, item); + return v; + } + + private class ViewHolder implements View.OnClickListener { + private BluetoothDeviceItem item = null; + + private TextView mName = null; + private TextView mAddress = null; + + public ViewHolder(View v) { + mName = (TextView) v.findViewById(R.id.ble_name); + mAddress = (TextView) v.findViewById(R.id.ble_address); + + v.setOnClickListener(ViewHolder.this); + } + + @Override + public void onClick(View v) { + SP.putString(R.string.key_danars_address, item.device.getAddress()); + SP.putString(R.string.key_danars_name, mName.getText().toString()); + MainApp.bus().post(new EventDanaRSDeviceChange()); + finish(); + } + + public void setData(int pos, BluetoothDeviceItem data) { + if (data != null) { + try { + String tTitle = data.device.getName(); + if (tTitle == null || tTitle.equals("")) { + tTitle = "(unknown)"; + } else if (tTitle.length() > 10) { + tTitle = tTitle.substring(0, 10); + } + mName.setText(tTitle); + + mAddress.setText(data.device.getAddress()); + + item = data; + } catch (Exception e) { + } + } + } + } + } + + // + private class BluetoothDeviceItem { + private BluetoothDevice device; + + public BluetoothDeviceItem(BluetoothDevice device) { + super(); + this.device = device; + } + + @Override + public boolean equals(Object o) { + if (device == null || o == null || !(o instanceof BluetoothDeviceItem)) { + return false; + } + BluetoothDeviceItem checkItem = (BluetoothDeviceItem) o; + if (checkItem.device == null) { + return false; + } + return stringEquals(device.getAddress(), checkItem.device.getAddress()); + } + + public boolean stringEquals(String arg1, String arg2) { + try { + return arg1.equals(arg2); + } catch (Exception e) { + return false; + } + } + } + + public static boolean isSNCheck(String sn) { + String regex = "^([a-zA-Z]{3})([0-9]{5})([a-zA-Z]{2})$"; + Pattern p = Pattern.compile(regex); + Matcher m = p.matcher(sn); + + return m.matches(); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingHelperActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingHelperActivity.java new file mode 100644 index 0000000000..c67534ac75 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingHelperActivity.java @@ -0,0 +1,15 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.activities; + +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; + +public class PairingHelperActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + PairingProgressDialog bolusProgressDialog = new PairingProgressDialog(); + bolusProgressDialog.setHelperActivity(this); + bolusProgressDialog.show(this.getSupportFragmentManager(), "PairingProgress"); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java new file mode 100644 index 0000000000..00cbdb4628 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/activities/PairingProgressDialog.java @@ -0,0 +1,148 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.activities; + + +import android.app.Activity; +import android.os.Bundle; +import android.os.Handler; +import android.os.HandlerThread; +import android.support.v4.app.DialogFragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.Window; +import android.widget.Button; +import android.widget.ProgressBar; +import android.widget.TextView; + +import com.squareup.otto.Subscribe; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSPairingSuccess; + + +public class PairingProgressDialog extends DialogFragment implements View.OnClickListener { + + TextView statusView; + ProgressBar progressBar; + Button button; + PairingHelperActivity helperActivity; + + static int secondsPassed = 0; + public static boolean pairingEnded = false; + public static boolean running = true; + + private static Handler sHandler; + private static HandlerThread sHandlerThread; + + public PairingProgressDialog() { + super(); + // Required empty public constructor + if (sHandlerThread == null) { + sHandlerThread = new HandlerThread(PairingProgressDialog.class.getSimpleName()); + sHandlerThread.start(); + sHandler = new Handler(sHandlerThread.getLooper()); + } + secondsPassed = 0; + } + + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.danars_pairingprogressdialog, container, false); + getDialog().setTitle(MainApp.sResources.getString(R.string.pairing)); + statusView = (TextView) view.findViewById(R.id.danars_paringprogress_status); + progressBar = (ProgressBar) view.findViewById(R.id.danars_paringprogress_progressbar); + button = (Button) view.findViewById(R.id.ok); + + progressBar.setMax(100); + progressBar.setProgress(0); + statusView.setText(MainApp.sResources.getString(R.string.waitingforpairing)); + button.setVisibility(View.GONE); + button.setOnClickListener(this); + setCancelable(false); + + sHandler.post(new Runnable() { + @Override + public void run() { + for (int i = 0; i < 20; i++) { + if (pairingEnded) { + Activity activity = getActivity(); + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + progressBar.setProgress(100); + statusView.setText(R.string.pairingok); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + dismiss(); + } + }); + } else + dismiss(); + return; + } + progressBar.setProgress(i * 5); + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + } + Activity activity = getActivity(); + if (activity != null) { + activity.runOnUiThread(new Runnable() { + @Override + public void run() { + progressBar.setProgress(100); + statusView.setText(R.string.pairingtimedout); + button.setVisibility(View.VISIBLE); + } + }); + } + } + }); + return view; + } + + @Override + public void onResume() { + super.onResume(); + MainApp.bus().register(this); + running = true; + if (pairingEnded) dismiss(); + } + + @Override + public void dismiss() { + super.dismiss(); + if (helperActivity != null) { + helperActivity.finish(); + } + } + + @Override + public void onPause() { + super.onPause(); + MainApp.bus().unregister(this); + running = false; + } + + @Subscribe + public void onStatusEvent(final EventDanaRSPairingSuccess ev) { + pairingEnded = true; + } + + public void setHelperActivity(PairingHelperActivity activity) { + this.helperActivity = activity; + } + + @Override + public void onClick(View v) { + running = false; + dismiss(); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRSMessageHashTable.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRSMessageHashTable.java new file mode 100644 index 0000000000..fe81fe0acf --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRSMessageHashTable.java @@ -0,0 +1,103 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; + +import info.nightscout.androidaps.Config; + +/** + * Created by mike on 28.05.2016. + */ +public class DanaRSMessageHashTable { + private static Logger log = LoggerFactory.getLogger(DanaRSMessageHashTable.class); + + public static HashMap messages = null; + + static { + if (messages == null) { + boolean savedState = Config.logDanaMessageDetail; + Config.logDanaMessageDetail = false; + + messages = new HashMap<>(); + put(new DanaRS_Packet_Basal_Cancel_Temporary_Basal()); + put(new DanaRS_Packet_Basal_Get_Basal_Rate()); + put(new DanaRS_Packet_Basal_Get_Profile_Basal_Rate()); + put(new DanaRS_Packet_Basal_Get_Profile_Number()); + put(new DanaRS_Packet_Basal_Set_Basal_Rate()); + put(new DanaRS_Packet_Basal_Set_Profile_Basal_Rate()); + put(new DanaRS_Packet_Basal_Set_Profile_Number()); + put(new DanaRS_Packet_Basal_Set_Suspend_Off()); + put(new DanaRS_Packet_Basal_Set_Suspend_On()); + put(new DanaRS_Packet_Basal_Set_Temporary_Basal()); + put(new DanaRS_Packet_Basal_Temporary_Basal_State()); + put(new DanaRS_Packet_Bolus_Get_Bolus_Option()); + put(new DanaRS_Packet_Bolus_Get_Initial_Bolus()); + put(new DanaRS_Packet_Bolus_Get_Calculation_Information()); + put(new DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information()); + put(new DanaRS_Packet_Bolus_Get_CIR_CF_Array()); + put(new DanaRS_Packet_Bolus_Get_Dual_Bolus()); + put(new DanaRS_Packet_Bolus_Get_Extended_Bolus()); + put(new DanaRS_Packet_Bolus_Get_Extended_Bolus_State()); + put(new DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State()); + put(new DanaRS_Packet_Bolus_Get_Step_Bolus_Information()); + put(new DanaRS_Packet_Bolus_Set_Bolus_Option()); + put(new DanaRS_Packet_Bolus_Set_Initial_Bolus()); + put(new DanaRS_Packet_Bolus_Set_CIR_CF_Array()); + put(new DanaRS_Packet_Bolus_Set_Dual_Bolus()); + put(new DanaRS_Packet_Bolus_Set_Extended_Bolus()); + put(new DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel()); + put(new DanaRS_Packet_Bolus_Set_Step_Bolus_Start()); + put(new DanaRS_Packet_Bolus_Set_Step_Bolus_Stop()); + put(new DanaRS_Packet_Etc_Keep_Connection()); + put(new DanaRS_Packet_Etc_Set_History_Save()); + put(new DanaRS_Packet_General_Delivery_Status()); + put(new DanaRS_Packet_General_Get_Password()); + put(new DanaRS_Packet_General_Initial_Screen_Information()); + put(new DanaRS_Packet_Notify_Alarm()); + put(new DanaRS_Packet_Notify_Delivery_Complete()); + put(new DanaRS_Packet_Notify_Delivery_Rate_Display()); + put(new DanaRS_Packet_Notify_Missed_Bolus_Alarm()); + put(new DanaRS_Packet_Option_Get_Pump_Time()); + put(new DanaRS_Packet_Option_Get_User_Option()); + put(new DanaRS_Packet_Option_Set_Pump_Time()); + put(new DanaRS_Packet_Option_Set_User_Option()); + //put(new DanaRS_Packet_History_()); + put(new DanaRS_Packet_History_Alarm()); + put(new DanaRS_Packet_History_All_History()); + put(new DanaRS_Packet_History_Basal()); + put(new DanaRS_Packet_History_Blood_Glucose()); + put(new DanaRS_Packet_History_Bolus()); + put(new DanaRS_Packet_Review_Bolus_Avg()); + put(new DanaRS_Packet_History_Carbohydrate()); + put(new DanaRS_Packet_History_Daily()); + put(new DanaRS_Packet_General_Get_More_Information()); + put(new DanaRS_Packet_General_Get_Pump_Check()); + put(new DanaRS_Packet_General_Get_Shipping_Information()); + put(new DanaRS_Packet_General_Get_Today_Delivery_Total()); + put(new DanaRS_Packet_General_Get_User_Time_Change_Flag()); + put(new DanaRS_Packet_History_Prime()); + put(new DanaRS_Packet_History_Refill()); + put(new DanaRS_Packet_General_Set_History_Upload_Mode()); + put(new DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear()); + put(new DanaRS_Packet_History_Suspend()); + put(new DanaRS_Packet_History_Temporary()); + + Config.logDanaMessageDetail = savedState; + } + } + + public static void put(DanaRS_Packet message) { + int command = message.getCommand(); + messages.put(command, message); + } + + public static DanaRS_Packet findMessage(Integer command) { + if (messages.containsKey(command)) { + return messages.get(command); + } else { + return new DanaRS_Packet(); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet.java new file mode 100644 index 0000000000..bb865d4fb3 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet.java @@ -0,0 +1,383 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import android.annotation.TargetApi; +import android.os.Build; + +import java.nio.charset.StandardCharsets; +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet { + protected static final int TYPE_START = 0; + protected static final int OPCODE_START = 1; + protected static final int DATA_START = 2; + + private boolean received; + protected int type = BleCommandUtil.DANAR_PACKET__TYPE_RESPONSE; // most of the messages, should be changed for others + protected int opCode; + + public DanaRS_Packet() { + received = false; + } + + public void setReceived() { + received = true; + } + + public boolean isReceived() { + return received; + } + + public int getType() { + return type; + } + + public int getOpCode() { + return opCode; + } + + public int getCommand() { + return ((type & 0xFF) << 8) + (opCode & 0xFF); + } + + public byte[] getRequestParams() { + return null; + }; + + // STATIC FUNCTIONS + + public static int getCommand(byte[] data) { + int type = byteArrayToInt(getBytes(data, TYPE_START, 1)); + int opCode = byteArrayToInt(getBytes(data, OPCODE_START, 1)); + return ((type & 0xFF) << 8) + (opCode & 0xFF); + } + + public void handleMessage(byte[] data) { + } + + public String getFriendlyName() { + return "UNKNOWN_PACKET"; + } + +/* + public static DanaRS_Packet parseResponse(byte[] data) { + DanaRS_Packet ret = null; + try { + + int type = byteArrayToInt(getBytes(data, TYPE_START, 1)); + int tOpCode = byteArrayToInt(getBytes(data, OPCODE_START, 1)); + if (type == BleCommandUtil.DANAR_PACKET__TYPE_NOTIFY) { + switch (tOpCode) { + // Notify + case BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__DELIVERY_COMPLETE: + ret = new DanaRS_Packet_Notify_Delivery_Complete(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__DELIVERY_RATE_DISPLAY: + ret = new DanaRS_Packet_Notify_Delivery_Rate_Display(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__ALARM: + ret = new DanaRS_Packet_Notify_Alarm(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__MISSED_BOLUS_ALARM: + ret = new DanaRS_Packet_Notify_Missed_Bolus_Alarm(); + break; + } + } else if (type == BleCommandUtil.DANAR_PACKET__TYPE_RESPONSE) { + switch (tOpCode) { + // Init + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION: + ret = new DanaRS_Packet_General_Initial_Screen_Information(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__DELIVERY_STATUS: + ret = new DanaRS_Packet_General_Delivery_Status(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_PASSWORD: + ret = new DanaRS_Packet_General_Get_Password(); + break; + + // Review + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BOLUS_AVG: + ret = new DanaRS_Packet_Review_Bolus_Avg(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BOLUS: + ret = new DanaRS_Packet_History_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__DAILY: + ret = new DanaRS_Packet_History_Daily(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__PRIME: + ret = new DanaRS_Packet_History_Prime(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__REFILL: + ret = new DanaRS_Packet_History_Refill(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BLOOD_GLUCOSE: + ret = new DanaRS_Packet_History_Blood_Glucose(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__CARBOHYDRATE: + ret = new DanaRS_Packet_History_Carbohydrate(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__TEMPORARY: + ret = new DanaRS_Packet_History_Temporary(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SUSPEND: + ret = new DanaRS_Packet_History_Suspend(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__ALARM: + ret = new DanaRS_Packet_History_Alarm(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BASAL: + ret = new DanaRS_Packet_History_Basal(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__ALL_HISTORY: + ret = new DanaRS_Packet_History_All_History(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_SHIPPING_INFORMATION: + ret = new DanaRS_Packet_General_Get_Shipping_Information(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_PUMP_CHECK: + ret = new DanaRS_Packet_General_Get_Pump_Check(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_USER_TIME_CHANGE_FLAG: + ret = new DanaRS_Packet_General_Get_User_Time_Change_Flag(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SET_USER_TIME_CHANGE_FLAG_CLEAR: + ret = new DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_MORE_INFORMATION: + ret = new DanaRS_Packet_General_Get_More_Information(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SET_HISTORY_UPLOAD_MODE: + ret = new DanaRS_Packet_General_Set_History_Upload_Mode(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_TODAY_DELIVERY_TOTAL: + ret = new DanaRS_Packet_General_Get_Today_Delivery_Total(); + break; + + // Bolus + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_STEP_BOLUS_INFORMATION: + ret = new DanaRS_Packet_Bolus_Get_Step_Bolus_Information(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_BOLUS_STATE: + ret = new DanaRS_Packet_Bolus_Get_Extended_Bolus_State(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_BOLUS: + ret = new DanaRS_Packet_Bolus_Get_Extended_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_DUAL_BOLUS: + ret = new DanaRS_Packet_Bolus_Get_Dual_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_STOP: + ret = new DanaRS_Packet_Bolus_Set_Step_Bolus_Stop(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_CARBOHYDRATE_CALCULATION_INFORMATION: + ret = new DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_MENU_OPTION_STATE: + ret = new DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_EXTENDED_BOLUS: + ret = new DanaRS_Packet_Bolus_Set_Extended_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_DUAL_BOLUS: + ret = new DanaRS_Packet_Bolus_Set_Dual_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_EXTENDED_BOLUS_CANCEL: + ret = new DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_START: + ret = new DanaRS_Packet_Bolus_Set_Step_Bolus_Start(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_CALCULATION_INFORMATION: + ret = new DanaRS_Packet_Bolus_Get_Calculation_Information(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_BOLUS_RATE: + ret = new DanaRS_Packet_Bolus_Get_Initial_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_BOLUS_RATE: + ret = new DanaRS_Packet_Bolus_Set_Initial_Bolus(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_CIR_CF_ARRAY: + ret = new DanaRS_Packet_Bolus_Get_CIR_CF_Array(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_CIR_CF_ARRAY: + ret = new DanaRS_Packet_Bolus_Set_CIR_CF_Array(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_BOLUS_OPTION: + ret = new DanaRS_Packet_Bolus_Get_Bolus_Option(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_BOLUS_OPTION: + ret = new DanaRS_Packet_Bolus_Set_Bolus_Option(); + break; + + // Basal + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_TEMPORARY_BASAL: + ret = new DanaRS_Packet_Basal_Set_Temporary_Basal(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__TEMPORARY_BASAL_STATE: + ret = new DanaRS_Packet_Basal_Temporary_Basal_State(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__CANCEL_TEMPORARY_BASAL: + ret = new DanaRS_Packet_Basal_Cancel_Temporary_Basal(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__GET_PROFILE_NUMBER: + ret = new DanaRS_Packet_Basal_Get_Profile_Number(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_PROFILE_NUMBER: + ret = new DanaRS_Packet_Basal_Set_Profile_Number(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__GET_PROFILE_BASAL_RATE: + ret = new DanaRS_Packet_Basal_Get_Profile_Basal_Rate(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_PROFILE_BASAL_RATE: + ret = new DanaRS_Packet_Basal_Set_Profile_Basal_Rate(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__GET_BASAL_RATE: + ret = new DanaRS_Packet_Basal_Get_Basal_Rate(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_BASAL_RATE: + ret = new DanaRS_Packet_Basal_Set_Basal_Rate(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_SUSPEND_ON: + ret = new DanaRS_Packet_Basal_Set_Suspend_On(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_SUSPEND_OFF: + ret = new DanaRS_Packet_Basal_Set_Suspend_Off(); + break; + + // Option + case BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__GET_PUMP_TIME: + ret = new DanaRS_Packet_Option_Get_Pump_Time(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__SET_PUMP_TIME: + ret = new DanaRS_Packet_Option_Set_Pump_Time(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__GET_USER_OPTION: + ret = new DanaRS_Packet_Option_Get_User_Option(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__SET_USER_OPTION: + ret = new DanaRS_Packet_Option_Set_User_Option(); + break; + + // Etc + case BleCommandUtil.DANAR_PACKET__OPCODE_ETC__SET_HISTORY_SAVE: + ret = new DanaRS_Packet_Etc_Set_History_Save(); + break; + case BleCommandUtil.DANAR_PACKET__OPCODE_ETC__KEEP_CONNECTION: + ret = new DanaRS_Packet_Etc_Keep_Connection(); + break; + } + } + + } catch (Exception e) { + ret = null; + } + + return ret; + } +*/ + protected static byte[] getBytes(byte[] data, int srcStart, int srcLength) { + try { + byte[] ret = new byte[srcLength]; + + System.arraycopy(data, srcStart, ret, 0, srcLength); + + return ret; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + protected static int byteArrayToInt(byte[] b) { + int ret; + + switch (b.length) { + case 1: + ret = b[0] & 0x000000FF; + break; + case 2: + ret = ((b[1] & 0x000000FF) << 8) + (b[0] & 0x000000FF); + break; + case 3: + ret = ((b[2] & 0x000000FF) << 16) + ((b[1] & 0x000000FF) << 8) + (b[0] & 0x000000FF); + break; + case 4: + ret = ((b[3] & 0x000000FF) << 24) + ((b[2] & 0x000000FF) << 16) + ((b[1] & 0x000000FF) << 8) + (b[0] & 0x000000FF); + break; + default: + ret = -1; + break; + } + return ret; + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + public static String stringFromBuff(byte[] buff, int offset, int length) { + byte[] strbuff = new byte[length]; + System.arraycopy(buff, offset, strbuff, 0, length); + return new String(strbuff, StandardCharsets.UTF_8); + } + + public static Date dateFromBuff(byte[] buff, int offset) { + Date date = + new Date( + 100 + byteArrayToInt(getBytes(buff, offset, 1)), + byteArrayToInt(getBytes(buff, offset + 1, 1)) - 1, + byteArrayToInt(getBytes(buff, offset + 2, 1)) + ); + return date; + } + + @TargetApi(Build.VERSION_CODES.KITKAT) + public static String asciiStringFromBuff(byte[] buff, int offset, int length) { + byte[] strbuff = new byte[length]; + System.arraycopy(buff, offset, strbuff, 0, length); + for (int pos = 0; pos < length; pos++) + strbuff[pos] += 65; // "A" + return new String(strbuff, StandardCharsets.UTF_8); + } + + public static String toHexString(byte[] buff) { + if (buff == null) + return ""; + + StringBuffer sb = new StringBuffer(); + + int count = 0; + for (byte element : buff) { + sb.append(String.format("%02X ", element)); + if (++count % 4 == 0) sb.append(" "); + } + + return sb.toString(); + } + + final private static char[] hexArray = "0123456789ABCDEF".toCharArray(); + + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + public static byte[] hexToBytes(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + + Character.digit(s.charAt(i + 1), 16)); + } + return data; + } + + public static int ByteToInt(byte b) { + return b & 0x000000FF; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Cancel_Temporary_Basal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Cancel_Temporary_Basal.java new file mode 100644 index 0000000000..214284d8ef --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Cancel_Temporary_Basal.java @@ -0,0 +1,36 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Cancel_Temporary_Basal extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Cancel_Temporary_Basal.class); + + public int error; + + public DanaRS_Packet_Basal_Cancel_Temporary_Basal() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__CANCEL_TEMPORARY_BASAL; + if (Config.logDanaMessageDetail) { + log.debug("Canceling temp basal"); + } + } + + @Override + public void handleMessage(byte[] data) { + error = byteArrayToInt(getBytes(data, DATA_START, 1)); + if (Config.logDanaMessageDetail) { + log.debug("Result " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__CANCEL_TEMPORARY_BASAL"; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Basal_Rate.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Basal_Rate.java new file mode 100644 index 0000000000..feab29d2b5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Basal_Rate.java @@ -0,0 +1,55 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Get_Basal_Rate extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Cancel_Temporary_Basal.class); + + + public DanaRS_Packet_Basal_Get_Basal_Rate() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__GET_BASAL_RATE; + if (Config.logDanaMessageDetail) { + log.debug("Requesting basal rates"); + } + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 2; + pump.maxBasal = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + pump.basalStep = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (pump.pumpProfiles == null) pump.pumpProfiles = new double[4][]; + pump.pumpProfiles[pump.activeProfile] = new double[24]; + for (int i = 0, size = 24; i < size; i++) { + dataIndex += dataSize; + dataSize = 2; + pump.pumpProfiles[pump.activeProfile][i] = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + } + if (Config.logDanaMessageDetail) { + log.debug("Max basal: " + pump.maxBasal + " U"); + log.debug("Basal step: " + pump.basalStep + " U"); + for (int index = 0; index < 24; index++) + log.debug("Basal " + String.format("%02d", index) + "h: " + pump.pumpProfiles[pump.activeProfile][index]); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__GET_BASAL_RATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Basal_Rate.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Basal_Rate.java new file mode 100644 index 0000000000..8eadb8298d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Basal_Rate.java @@ -0,0 +1,61 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Basal_Get_Profile_Basal_Rate extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Get_Profile_Basal_Rate.class); + + private int profileNumber; + + public DanaRS_Packet_Basal_Get_Profile_Basal_Rate() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__GET_PROFILE_BASAL_RATE; + } + + // 0 - 4 + public DanaRS_Packet_Basal_Get_Profile_Basal_Rate(int profileNumber) { + this(); + this.profileNumber = profileNumber; + if (Config.logDanaMessageDetail) { + log.debug("Requesting basal rates for profile " + profileNumber); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[1]; + request[0] = (byte) (profileNumber & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 2; + + if (pump.pumpProfiles == null) pump.pumpProfiles = new double[4][]; + pump.pumpProfiles[profileNumber] = new double[24]; + for (int i = 0, size = 24; i < size; i++) { + pump.pumpProfiles[profileNumber][i] = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + dataIndex += dataSize; + dataSize = 2; + } + if (Config.logDanaMessageDetail) { + for (int index = 0; index < 24; index++) + log.debug("Basal " + String.format("%02d", index) + "h: " + pump.pumpProfiles[profileNumber][index]); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__GET_PROFILE_BASAL_RATE"; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Number.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Number.java new file mode 100644 index 0000000000..39e230a29e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Profile_Number.java @@ -0,0 +1,37 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Basal_Get_Profile_Number extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Get_Profile_Number.class); + + public DanaRS_Packet_Basal_Get_Profile_Number() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__GET_PROFILE_NUMBER; + if (Config.logDanaMessageDetail) { + log.debug("Requesting active profile"); + } + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + pump.activeProfile = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Active profile: " + pump.activeProfile); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__GET_PROFILE_NUMBER"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Basal_Rate.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Basal_Rate.java new file mode 100644 index 0000000000..6f56464c51 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Basal_Rate.java @@ -0,0 +1,53 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Set_Basal_Rate extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Basal_Rate.class); + + private double[] profileBasalRate; + public int error; + + public DanaRS_Packet_Basal_Set_Basal_Rate() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_BASAL_RATE; + } + + public DanaRS_Packet_Basal_Set_Basal_Rate(double[] profileBasalRate) { + this(); + this.profileBasalRate = profileBasalRate; + if (Config.logDanaMessageDetail) { + log.debug("Setting new basal rates"); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[48]; + for (int i = 0, size = 24; i < size; i++) { + int rate = (int) (profileBasalRate[i] * 100d); + request[0 + (i * 2)] = (byte) (rate & 0xff); + request[1 + (i * 2)] = (byte) ((rate >>> 8) & 0xff); + } + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__SET_BASAL_RATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Basal_Rate.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Basal_Rate.java new file mode 100644 index 0000000000..82a63f0ca7 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Basal_Rate.java @@ -0,0 +1,56 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Set_Profile_Basal_Rate extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Profile_Basal_Rate.class); + + private int profileNumber; // 0 - 4 + private double[] profileBasalRate; + public int error; + + public DanaRS_Packet_Basal_Set_Profile_Basal_Rate() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_PROFILE_BASAL_RATE; + } + + public DanaRS_Packet_Basal_Set_Profile_Basal_Rate(int profileNumber, double[] profileBasalRate) { + this(); + this.profileNumber = profileNumber; + this.profileBasalRate = profileBasalRate; + if (Config.logDanaMessageDetail) { + log.debug("Setting new basal rates for profile " + profileNumber); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[49]; + request[0] = (byte) (profileNumber & 0xff); + for (int i = 0, size = 24; i < size; i++) { + int rate = (int) (profileBasalRate[i] * 100d); + request[1 + (i * 2)] = (byte) (rate & 0xff); + request[2 + (i * 2)] = (byte) ((rate >>> 8) & 0xff); + } + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__SET_PROFILE_BASAL_RATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Number.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Number.java new file mode 100644 index 0000000000..fe47f89dfc --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Profile_Number.java @@ -0,0 +1,48 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Set_Profile_Number extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Profile_Number.class); + private int profileNumber; + public int error; + + public DanaRS_Packet_Basal_Set_Profile_Number() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_PROFILE_NUMBER; + } + public DanaRS_Packet_Basal_Set_Profile_Number(int profileNumber) { + this(); + this.profileNumber = profileNumber; + if (Config.logDanaMessageDetail) { + log.debug("Setting profile number " + profileNumber); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[1]; + request[0] = (byte) (profileNumber & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__SET_PROFILE_NUMBER"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_Off.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_Off.java new file mode 100644 index 0000000000..1b9444c2d3 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_Off.java @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Set_Suspend_Off extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Suspend_Off.class); + public int error; + + public DanaRS_Packet_Basal_Set_Suspend_Off() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_SUSPEND_OFF; + if (Config.logDanaMessageDetail) { + log.debug("Turning off suspend"); + } + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__SET_SUSPEND_OFF"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_On.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_On.java new file mode 100644 index 0000000000..01e90e026c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Suspend_On.java @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Set_Suspend_On extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Suspend_On.class); + public int error; + + public DanaRS_Packet_Basal_Set_Suspend_On() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_SUSPEND_ON; + if (Config.logDanaMessageDetail) { + log.debug("Turning on suspend"); + } + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__SET_SUSPEND_ON"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Temporary_Basal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Temporary_Basal.java new file mode 100644 index 0000000000..a81d85f016 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Temporary_Basal.java @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Basal_Set_Temporary_Basal extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Temporary_Basal.class); + + private int temporaryBasalRatio; + private int temporaryBasalDuration; + public int error; + + public DanaRS_Packet_Basal_Set_Temporary_Basal() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__SET_TEMPORARY_BASAL; + } + + public DanaRS_Packet_Basal_Set_Temporary_Basal(int temporaryBasalRatio, int temporaryBasalDuration) { + this(); + this.temporaryBasalRatio = temporaryBasalRatio; + this.temporaryBasalDuration = temporaryBasalDuration; + if (Config.logDanaMessageDetail) { + log.debug("Setting temporary basal of " + temporaryBasalRatio + "% for " + temporaryBasalDuration + " hours"); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[2]; + request[0] = (byte) (temporaryBasalRatio & 0xff); + request[1] = (byte) (temporaryBasalDuration & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__SET_TEMPORARY_BASAL"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Temporary_Basal_State.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Temporary_Basal_State.java new file mode 100644 index 0000000000..aec45db5d6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Temporary_Basal_State.java @@ -0,0 +1,77 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import android.support.annotation.NonNull; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Basal_Temporary_Basal_State extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Temporary_Basal_State.class); + + public DanaRS_Packet_Basal_Temporary_Basal_State() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__TEMPORARY_BASAL_STATE; + if (Config.logDanaMessageDetail) { + log.debug("Requesting temporary basal status"); + } + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.isTempBasalInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01; + boolean isAPSTempBasalInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x02; + + dataIndex += dataSize; + dataSize = 1; + pump.tempBasalPercent = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (pump.tempBasalPercent > 200) pump.tempBasalPercent = (pump.tempBasalPercent - 200) * 10; + + dataIndex += dataSize; + dataSize = 1; + int durationHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (durationHour == 150) pump.tempBasalTotalSec = 15 * 60; + else if (durationHour == 160) pump.tempBasalTotalSec = 30 * 60; + else pump.tempBasalTotalSec = durationHour * 60 * 60; + + dataIndex += dataSize; + dataSize = 2; + int runningMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + int tempBasalRemainingMin = (pump.tempBasalTotalSec - runningMin * 60) / 60; + Date tempBasalStart = pump.isTempBasalInProgress ? getDateFromTempBasalSecAgo(runningMin * 60) : new Date(0); + + if (Config.logDanaMessageDetail) { + log.debug("Error code: " + error); + log.debug("Is temp basal running: " + pump.isTempBasalInProgress); + log.debug("Is APS temp basal running: " + isAPSTempBasalInProgress); + log.debug("Current temp basal percent: " + pump.tempBasalPercent); + log.debug("Current temp basal remaining min: " + tempBasalRemainingMin); + log.debug("Current temp basal total sec: " + pump.tempBasalTotalSec); + log.debug("Current temp basal start: " + tempBasalStart); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__TEMPORARY_BASAL_STATE"; + } + + @NonNull + private Date getDateFromTempBasalSecAgo(int tempBasalAgoSecs) { + return new Date((long) (Math.ceil(System.currentTimeMillis() / 1000d) - tempBasalAgoSecs) * 1000); + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Bolus_Option.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Bolus_Option.java new file mode 100644 index 0000000000..068d672646 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Bolus_Option.java @@ -0,0 +1,124 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Bolus_Option extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Bolus_Option.class); + + public DanaRS_Packet_Bolus_Get_Bolus_Option() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_BOLUS_OPTION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + pump.isExtendedBolusEnabled = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 1; + + dataIndex += dataSize; + dataSize = 1; + pump.bolusCalculationOption = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.missedBolusConfig = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus01StartHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus01StartMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus01EndHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus01EndMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus02StartHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus02StartMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus02EndHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus02EndMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus03StartHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus03StartMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus03EndHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus03EndMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus04StartHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus04StartMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus04EndHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int missedBolus04EndMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Extended bolus enabled: " + pump.isExtendedBolusEnabled); + log.debug("Missed bolus config: " + pump.missedBolusConfig); + log.debug("missedBolus01StartHour: " + missedBolus01StartHour); + log.debug("missedBolus01StartMin: " + missedBolus01StartMin); + log.debug("missedBolus01EndHour: " + missedBolus01EndHour); + log.debug("missedBolus01EndMin: " + missedBolus01EndMin); + log.debug("missedBolus02StartHour: " + missedBolus02StartHour); + log.debug("missedBolus02StartMin: " + missedBolus02StartMin); + log.debug("missedBolus02EndHour: " + missedBolus02EndHour); + log.debug("missedBolus02EndMin: " + missedBolus02EndMin); + log.debug("missedBolus03StartHour: " + missedBolus03StartHour); + log.debug("missedBolus03StartMin: " + missedBolus03StartMin); + log.debug("missedBolus03EndHour: " + missedBolus03EndHour); + log.debug("missedBolus03EndMin: " + missedBolus03EndMin); + log.debug("missedBolus04StartHour: " + missedBolus04StartHour); + log.debug("missedBolus04StartMin: " + missedBolus04StartMin); + log.debug("missedBolus04EndHour: " + missedBolus04EndHour); + log.debug("missedBolus04EndMin: " + missedBolus04EndMin); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_BOLUS_OPTION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_CIR_CF_Array.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_CIR_CF_Array.java new file mode 100644 index 0000000000..b8a86cc078 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_CIR_CF_Array.java @@ -0,0 +1,145 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_CIR_CF_Array extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_CIR_CF_Array.class); + + public DanaRS_Packet_Bolus_Get_CIR_CF_Array() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_CIR_CF_ARRAY; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int language = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.units = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.morningCIR = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + int cir02 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.afternoonCIR = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + int cir04 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.eveningCIR = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + int cir06 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.nightCIR = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + double cf02, cf04, cf06; + + if (pump.units == DanaRPump.UNITS_MGDL) { + dataIndex += dataSize; + dataSize = 2; + pump.morningCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + cf02 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.afternoonCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + cf04 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.eveningCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + cf06 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.nightCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + } else { + dataIndex += dataSize; + dataSize = 2; + pump.morningCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + cf02 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.afternoonCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + cf04 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.eveningCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + cf06 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.nightCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + } + + if (Config.logDanaMessageDetail) { + log.debug("Language: " + language); + log.debug("Pump units: " + (pump.units == DanaRPump.UNITS_MGDL ? "MGDL" : "MMOL")); + log.debug("Current pump morning CIR: " + pump.morningCIR); + log.debug("Current pump morning CF: " + pump.morningCF); + log.debug("Current pump afternoon CIR: " + pump.afternoonCIR); + log.debug("Current pump afternoon CF: " + pump.afternoonCF); + log.debug("Current pump evening CIR: " + pump.eveningCIR); + log.debug("Current pump evening CF: " + pump.eveningCF); + log.debug("Current pump night CIR: " + pump.nightCIR); + log.debug("Current pump night CF: " + pump.nightCF); + log.debug("cir02: " + cir02); + log.debug("cir04: " + cir04); + log.debug("cir06: " + cir06); + log.debug("cf02: " + cf02); + log.debug("cf04: " + cf04); + log.debug("cf06: " + cf06); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_CIR_CF_ARRAY"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Calculation_Information.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Calculation_Information.java new file mode 100644 index 0000000000..f5acedf3ba --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Calculation_Information.java @@ -0,0 +1,77 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Calculation_Information extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Calculation_Information.class); + + public DanaRS_Packet_Bolus_Get_Calculation_Information() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_CALCULATION_INFORMATION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + double currentBG = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + int carbohydrate = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.currentTarget = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.currentCIR = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.currentCF = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.iob = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + pump.units = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (pump.units == DanaRPump.UNITS_MMOL) { + pump.currentCF = pump.currentCF / 100d; + pump.currentTarget = pump.currentTarget / 100d; + currentBG = currentBG / 100d; + } + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + log.debug("Pump units: " + (pump.units == DanaRPump.UNITS_MGDL ? "MGDL" : "MMOL")); + log.debug("Current BG: " + currentBG); + log.debug("Carbs: " + carbohydrate); + log.debug("Current target: " + pump.currentTarget); + log.debug("Current CIR: " + pump.currentCIR); + log.debug("Current CF: " + pump.currentCF); + log.debug("Pump IOB: " + pump.iob); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_CALCULATION_INFORMATION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information.java new file mode 100644 index 0000000000..c581320c54 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information.java @@ -0,0 +1,47 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information.class); + + public DanaRS_Packet_Bolus_Get_Carbohydrate_Calculation_Information() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_CARBOHYDRATE_CALCULATION_INFORMATION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + int carbs = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.currentCIR = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + log.debug("Carbs: " + carbs); + log.debug("Current CIR: " + pump.currentCIR); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_CARBOHYDRATE_CALCULATION_INFORMATION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.java new file mode 100644 index 0000000000..bd7a0b9ee6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Dual_Bolus.java @@ -0,0 +1,55 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Dual_Bolus extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Dual_Bolus.class); + + public DanaRS_Packet_Bolus_Get_Dual_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_DUAL_BOLUS; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.bolusStep = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.maxBolus = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + double bolusIncrement = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + log.debug("Bolus step: " + pump.bolusStep + " U"); + log.debug("Extended bolus running: " + pump.extendedBolusAbsoluteRate + " U/h"); + log.debug("Max bolus: " + pump.maxBolus + " U"); + log.debug("bolusIncrement: " + bolusIncrement + " U"); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_DUAL_BOLUS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.java new file mode 100644 index 0000000000..682d9b14bb --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus.java @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Extended_Bolus extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Extended_Bolus.class); + + public DanaRS_Packet_Bolus_Get_Extended_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_BOLUS; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.maxBolus = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + pump.bolusStep = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + log.debug("Extended bolus running: " + pump.extendedBolusAbsoluteRate + " U/h"); + log.debug("Max bolus: " + pump.maxBolus + " U"); + log.debug("Bolus step: " + pump.bolusStep + " U"); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_EXTENDED_BOLUS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.java new file mode 100644 index 0000000000..b22a9dfb47 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Bolus_State.java @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Extended_Bolus_State extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Extended_Bolus_State.class); + + public DanaRS_Packet_Bolus_Get_Extended_Bolus_State() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_BOLUS_STATE; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01; + + dataIndex += dataSize; + dataSize = 1; + pump.extendedBolusMinutes = byteArrayToInt(getBytes(data, dataIndex, dataSize)) * 30; + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusSoFarInMinutes = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusDeliveredSoFar = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + log.debug("Is extended bolus running: " + pump.isExtendedInProgress); + log.debug("Extended bolus running: " + pump.extendedBolusAbsoluteRate + " U/h"); + log.debug("Extended bolus duration: " + pump.extendedBolusMinutes + " min"); + log.debug("Extended bolus so far: " + pump.extendedBolusSoFarInMinutes + " min"); + log.debug("Extended bolus delivered so far: " + pump.extendedBolusDeliveredSoFar + " U"); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_EXTENDED_BOLUS_STATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.java new file mode 100644 index 0000000000..5a7ca55e30 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.java @@ -0,0 +1,42 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State.class); + + public DanaRS_Packet_Bolus_Get_Extended_Menu_Option_State() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_EXTENDED_MENU_OPTION_STATE; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int extendedMenuOption = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01; + + if (Config.logDanaMessageDetail) { + log.debug("extendedMenuOption: " + extendedMenuOption); + log.debug("Is extended bolus running: " + pump.isExtendedInProgress); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_EXTENDED_MENU_OPTION_STATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Initial_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Initial_Bolus.java new file mode 100644 index 0000000000..58fa4674ad --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Initial_Bolus.java @@ -0,0 +1,46 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Get_Initial_Bolus extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Initial_Bolus.class); + + public DanaRS_Packet_Bolus_Get_Initial_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_BOLUS_RATE; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 2; + double initialBolusValue01 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double initialBolusValue02 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double initialBolusValue03 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double initialBolusValue04 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + if (Config.logDanaMessageDetail) { + log.debug("Initial bolus amount 01: " + initialBolusValue01); + log.debug("Initial bolus amount 02: " + initialBolusValue02); + log.debug("Initial bolus amount 03: " + initialBolusValue03); + log.debug("Initial bolus amount 04: " + initialBolusValue04); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_BOLUS_RATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Step_Bolus_Information.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Step_Bolus_Information.java new file mode 100644 index 0000000000..922b7886f2 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Step_Bolus_Information.java @@ -0,0 +1,72 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Bolus_Get_Step_Bolus_Information extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Step_Bolus_Information.class); + + public DanaRS_Packet_Bolus_Get_Step_Bolus_Information() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__GET_STEP_BOLUS_INFORMATION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int bolusType = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.initialBolusAmount = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + Date lastBolusTime = new Date(); // it doesn't provide day only hour+min, workaround: expecting today + dataIndex += dataSize; + dataSize = 1; + lastBolusTime.setHours(byteArrayToInt(getBytes(data, dataIndex, dataSize))); + + dataIndex += dataSize; + dataSize = 1; + lastBolusTime.setMinutes(byteArrayToInt(getBytes(data, dataIndex, dataSize))); + + dataIndex += dataSize; + dataSize = 2; + pump.lastBolusAmount = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.maxBolus = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + pump.bolusStep = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + log.debug("BolusType: " + bolusType); + log.debug("Initial bolus amount: " + pump.initialBolusAmount + " U"); + log.debug("Last bolus time: " + lastBolusTime.toLocaleString()); + log.debug("Last bolus amount: " + pump.lastBolusAmount); + log.debug("Max bolus: " + pump.maxBolus + " U"); + log.debug("Bolus step: " + pump.bolusStep + " U"); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__GET_STEP_BOLUS_INFORMATION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Bolus_Option.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Bolus_Option.java new file mode 100644 index 0000000000..e20baeaee6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Bolus_Option.java @@ -0,0 +1,127 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Set_Bolus_Option extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Bolus_Option.class); + private int extendedBolusOptionOnOff; + + private int bolusCalculationOption; + private int missedBolusConfig; + private int missedBolus01StartHour; + private int missedBolus01StartMin; + private int missedBolus01EndHour; + private int missedBolus01EndMin; + private int missedBolus02StartHour; + private int missedBolus02StartMin; + private int missedBolus02EndHour; + private int missedBolus02EndMin; + private int missedBolus03StartHour; + private int missedBolus03StartMin; + private int missedBolus03EndHour; + private int missedBolus03EndMin; + private int missedBolus04StartHour; + private int missedBolus04StartMin; + private int missedBolus04EndHour; + private int missedBolus04EndMin; + + public DanaRS_Packet_Bolus_Set_Bolus_Option() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_BOLUS_OPTION; + } + + public DanaRS_Packet_Bolus_Set_Bolus_Option( + int extendedBolusOptionOnOff, + int bolusCalculationOption, + int missedBolusConfig, + int missedBolus01StartHour, + int missedBolus01StartMin, + int missedBolus01EndHour, + int missedBolus01EndMin, + int missedBolus02StartHour, + int missedBolus02StartMin, + int missedBolus02EndHour, + int missedBolus02EndMin, + int missedBolus03StartHour, + int missedBolus03StartMin, + int missedBolus03EndHour, + int missedBolus03EndMin, + int missedBolus04StartHour, + int missedBolus04StartMin, + int missedBolus04EndHour, + int missedBolus04EndMin) { + this(); + this.extendedBolusOptionOnOff = extendedBolusOptionOnOff; + this.bolusCalculationOption = bolusCalculationOption; + this.missedBolusConfig = missedBolusConfig; + this.missedBolus01StartHour = missedBolus01StartHour; + this.missedBolus01StartMin = missedBolus01StartMin; + this.missedBolus01EndHour = missedBolus01EndHour; + this.missedBolus01EndMin = missedBolus01EndMin; + this.missedBolus02StartHour = missedBolus02StartHour; + this.missedBolus02StartMin = missedBolus02StartMin; + this.missedBolus02EndHour = missedBolus02EndHour; + this.missedBolus02EndMin = missedBolus02EndMin; + this.missedBolus03StartHour = missedBolus03StartHour; + this.missedBolus03StartMin = missedBolus03StartMin; + this.missedBolus03EndHour = missedBolus03EndHour; + this.missedBolus03EndMin = missedBolus03EndMin; + this.missedBolus04StartHour = missedBolus04StartHour; + this.missedBolus04StartMin = missedBolus04StartMin; + this.missedBolus04EndHour = missedBolus04EndHour; + this.missedBolus04EndMin = missedBolus04EndMin; + + if (Config.logDanaMessageDetail) { + log.debug("Setting bolus options"); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[19]; + request[0] = (byte) (extendedBolusOptionOnOff & 0xff); + request[1] = (byte) (bolusCalculationOption & 0xff); + request[2] = (byte) (missedBolusConfig & 0xff); + + request[3] = (byte) (missedBolus01StartHour & 0xff); + request[4] = (byte) (missedBolus01StartMin & 0xff); + request[5] = (byte) (missedBolus01EndHour & 0xff); + request[6] = (byte) (missedBolus01EndMin & 0xff); + + request[7] = (byte) (missedBolus02StartHour & 0xff); + request[8] = (byte) (missedBolus02StartMin & 0xff); + request[9] = (byte) (missedBolus02EndHour & 0xff); + request[10] = (byte) (missedBolus02EndMin & 0xff); + + request[11] = (byte) (missedBolus03StartHour & 0xff); + request[12] = (byte) (missedBolus03StartMin & 0xff); + request[13] = (byte) (missedBolus03EndHour & 0xff); + request[14] = (byte) (missedBolus03EndMin & 0xff); + + request[15] = (byte) (missedBolus04StartHour & 0xff); + request[16] = (byte) (missedBolus04StartMin & 0xff); + request[17] = (byte) (missedBolus04EndHour & 0xff); + request[18] = (byte) (missedBolus04EndMin & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_BOLUS_OPTION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_CIR_CF_Array.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_CIR_CF_Array.java new file mode 100644 index 0000000000..cf6a459d83 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_CIR_CF_Array.java @@ -0,0 +1,100 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Set_CIR_CF_Array extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_CIR_CF_Array.class); + + private int cir01; + private int cir02; + private int cir03; + private int cir04; + private int cir05; + private int cir06; + private int cir07; + private int cf01; + private int cf02; + private int cf03; + private int cf04; + private int cf05; + private int cf06; + private int cf07; + + public DanaRS_Packet_Bolus_Set_CIR_CF_Array() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_CIR_CF_ARRAY; + } + + public DanaRS_Packet_Bolus_Set_CIR_CF_Array(int cir01, int cir02, int cir03, int cir04, int cir05, int cir06, int cir07, int cf01, int cf02, int cf03, int cf04, int cf05, int cf06, int cf07) { + this(); + this.cir01 = cir01; + this.cir02 = cir02; + this.cir03 = cir03; + this.cir04 = cir04; + this.cir05 = cir05; + this.cir06 = cir06; + this.cir07 = cir07; + this.cf01 = cf01; + this.cf02 = cf02; + this.cf03 = cf03; + this.cf04 = cf04; + this.cf05 = cf05; + this.cf06 = cf06; + this.cf07 = cf07; + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[28]; + request[0] = (byte) (cir01 & 0xff); + request[1] = (byte) ((cir01 >>> 8) & 0xff); + request[2] = (byte) (cir02 & 0xff); + request[3] = (byte) ((cir02 >>> 8) & 0xff); + request[4] = (byte) (cir03 & 0xff); + request[5] = (byte) ((cir03 >>> 8) & 0xff); + request[6] = (byte) (cir04 & 0xff); + request[7] = (byte) ((cir04 >>> 8) & 0xff); + request[8] = (byte) (cir05 & 0xff); + request[9] = (byte) ((cir05 >>> 8) & 0xff); + request[10] = (byte) (cir06 & 0xff); + request[11] = (byte) ((cir06 >>> 8) & 0xff); + request[12] = (byte) (cir07 & 0xff); + request[13] = (byte) ((cir07 >>> 8) & 0xff); + request[14] = (byte) (cf01 & 0xff); + request[15] = (byte) ((cf01 >>> 8) & 0xff); + request[16] = (byte) (cf02 & 0xff); + request[17] = (byte) ((cf02 >>> 8) & 0xff); + request[18] = (byte) (cf03 & 0xff); + request[19] = (byte) ((cf03 >>> 8) & 0xff); + request[20] = (byte) (cf04 & 0xff); + request[21] = (byte) ((cf04 >>> 8) & 0xff); + request[22] = (byte) (cf05 & 0xff); + request[23] = (byte) ((cf05 >>> 8) & 0xff); + request[24] = (byte) (cf06 & 0xff); + request[25] = (byte) ((cf06 >>> 8) & 0xff); + request[26] = (byte) (cf07 & 0xff); + request[27] = (byte) ((cf07 >>> 8) & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_CIR_CF_ARRAY"; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Dual_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Dual_Bolus.java new file mode 100644 index 0000000000..31c80a702a --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Dual_Bolus.java @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Set_Dual_Bolus extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Dual_Bolus.class); + + private double amount; + private double extendedAmount; + private int extendedBolusDurationInHalfHours; + + public DanaRS_Packet_Bolus_Set_Dual_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_DUAL_BOLUS; + } + + public DanaRS_Packet_Bolus_Set_Dual_Bolus(double amount, double extendedAmount, int extendedBolusDurationInHalfHours) { + this(); + this.amount = amount; + this.extendedAmount = extendedAmount; + this.extendedBolusDurationInHalfHours = extendedBolusDurationInHalfHours; + + if (Config.logDanaMessageDetail) + log.debug("Dual bolus start : " + amount + " U extended: " + extendedAmount + " U halfhours: " + extendedBolusDurationInHalfHours); + } + + @Override + public byte[] getRequestParams() { + int stepBolusRate = (int) (amount / 100d); + int extendedBolusRate = (int) (extendedAmount / 100d); + + byte[] request = new byte[5]; + request[0] = (byte) (stepBolusRate & 0xff); + request[1] = (byte) ((stepBolusRate >>> 8) & 0xff); + request[2] = (byte) (extendedBolusRate & 0xff); + request[3] = (byte) ((extendedBolusRate >>> 8) & 0xff); + request[4] = (byte) (extendedBolusDurationInHalfHours & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_DUAL_BOLUS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus.java new file mode 100644 index 0000000000..b663b3bf72 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus.java @@ -0,0 +1,56 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Set_Extended_Bolus extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Extended_Bolus.class); + + private double extendedAmount; + private int extendedBolusDurationInHalfHours; + + public DanaRS_Packet_Bolus_Set_Extended_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_EXTENDED_BOLUS; + } + + public DanaRS_Packet_Bolus_Set_Extended_Bolus(double extendedAmount, int extendedBolusDurationInHalfHours) { + this(); + this.extendedAmount = extendedAmount; + this.extendedBolusDurationInHalfHours = extendedBolusDurationInHalfHours; + + if (Config.logDanaMessageDetail) + log.debug("Extended bolus start : " + extendedAmount + " U halfhours: " + extendedBolusDurationInHalfHours); + } + + @Override + public byte[] getRequestParams() { + int extendedBolusRate = (int) (extendedAmount / 100d); + + byte[] request = new byte[3]; + request[0] = (byte) (extendedBolusRate & 0xff); + request[1] = (byte) ((extendedBolusRate >>> 8) & 0xff); + request[2] = (byte) (extendedBolusDurationInHalfHours & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_EXTENDED_BOLUS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel.java new file mode 100644 index 0000000000..10aa5f4979 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel.java @@ -0,0 +1,35 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel.class); + + public DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_EXTENDED_BOLUS_CANCEL; + + if (Config.logDanaMessageDetail) + log.debug("Cancel extended bolus"); + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_EXTENDED_BOLUS_CANCEL"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Initial_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Initial_Bolus.java new file mode 100644 index 0000000000..a475e7675d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Initial_Bolus.java @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Bolus_Set_Initial_Bolus extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Initial_Bolus.class); + + private int bolusRate01; + private int bolusRate02; + private int bolusRate03; + private int bolusRate04; + + public DanaRS_Packet_Bolus_Set_Initial_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_BOLUS_RATE; + } + + public DanaRS_Packet_Bolus_Set_Initial_Bolus(double bolusRate01, double bolusRate02, double bolusRate03, double bolusRate04) { + this(); + this.bolusRate01 = (int) (bolusRate01 / 100d); + this.bolusRate02 = (int) (bolusRate02 / 100d); + this.bolusRate03 = (int) (bolusRate03 / 100d); + this.bolusRate04 = (int) (bolusRate04 / 100d); + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[8]; + request[0] = (byte) (bolusRate01 & 0xff); + request[1] = (byte) ((bolusRate01 >>> 8) & 0xff); + request[2] = (byte) (bolusRate02 & 0xff); + request[3] = (byte) ((bolusRate02 >>> 8) & 0xff); + request[4] = (byte) (bolusRate03 & 0xff); + request[5] = (byte) ((bolusRate03 >>> 8) & 0xff); + request[6] = (byte) (bolusRate04 & 0xff); + request[7] = (byte) ((bolusRate04 >>> 8) & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_BOLUS_RATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Start.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Start.java new file mode 100644 index 0000000000..be389c668c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Start.java @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.utils.HardLimits; + +public class DanaRS_Packet_Bolus_Set_Step_Bolus_Start extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Step_Bolus_Start.class); + + private double amount; + private int speed; + + public DanaRS_Packet_Bolus_Set_Step_Bolus_Start() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_START; + } + + // Speed 0 => 12 sec/U, 1 => 30 sec/U, 2 => 60 sec/U + public DanaRS_Packet_Bolus_Set_Step_Bolus_Start(double amount, int speed) { + this(); + + // HARDCODED LIMIT + amount = MainApp.getConfigBuilder().applyBolusConstraints(amount); + if (amount < 0) amount = 0d; + if (amount > HardLimits.maxBolus()) amount = HardLimits.maxBolus(); + + this.amount = amount; + this.speed = speed; + + if (Config.logDanaMessageDetail) + log.debug("Bolus start : " + amount + " speed: " + speed); + } + + @Override + public byte[] getRequestParams() { + int stepBolusRate = (int) (amount * 100); + byte[] request = new byte[3]; + request[0] = (byte) (stepBolusRate & 0xff); + request[1] = (byte) ((stepBolusRate >>> 8) & 0xff); + request[2] = (byte) (speed & 0xff); + return request; + } + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_STEP_BOLUS_START"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.java new file mode 100644 index 0000000000..1b52f36544 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.java @@ -0,0 +1,60 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; + +public class DanaRS_Packet_Bolus_Set_Step_Bolus_Stop extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.class); + private static Treatment t; + private static Double amount; + + public static boolean stopped = false; + public static boolean forced = false; + + public DanaRS_Packet_Bolus_Set_Step_Bolus_Stop() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BOLUS__SET_STEP_BOLUS_STOP; + } + + public DanaRS_Packet_Bolus_Set_Step_Bolus_Stop(Double amount, Treatment t) { + this(); + this.t = t; + this.amount = amount; + forced = false; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance(); + stopped = true; + if (!forced) { + t.insulin = amount; + bolusingEvent.status = MainApp.sResources.getString(R.string.overview_bolusprogress_delivered); + bolusingEvent.percent = 100; + } else { + bolusingEvent.status = MainApp.sResources.getString(R.string.overview_bolusprogress_stoped); + } + MainApp.bus().post(bolusingEvent); + } + + @Override + public String getFriendlyName() { + return "BOLUS__SET_STEP_BOLUS_STOP"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Keep_Connection.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Keep_Connection.java new file mode 100644 index 0000000000..d30be3abf8 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Keep_Connection.java @@ -0,0 +1,32 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Etc_Keep_Connection extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Etc_Keep_Connection.class); + + public DanaRS_Packet_Etc_Keep_Connection() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_ETC__KEEP_CONNECTION; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "ETC__KEEP_CONNECTION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Set_History_Save.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Set_History_Save.java new file mode 100644 index 0000000000..6538b77932 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Etc_Set_History_Save.java @@ -0,0 +1,71 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Etc_Set_History_Save extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Etc_Set_History_Save.class); + + private int historyType; + private int historyYear; + private int historyMonth; + private int historyDate; + private int historyHour; + private int historyMinute; + private int historySecond; + private int historyCode; + private int historyValue; + + public DanaRS_Packet_Etc_Set_History_Save() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_ETC__SET_HISTORY_SAVE; + } + + public DanaRS_Packet_Etc_Set_History_Save(int historyType, int historyYear, int historyMonth, int historyDate, int historyHour, int historyMinute, int historySecond, int historyCode, int historyValue) { + this(); + this.historyType = historyType; + this.historyYear = historyYear; + this.historyMonth = historyMonth; + this.historyDate = historyDate; + this.historyHour = historyHour; + this.historyMinute = historyMinute; + this.historySecond = historySecond; + this.historyCode = historyCode; + this.historyValue = historyValue; + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[10]; + request[0] = (byte) (historyType & 0xff); + request[1] = (byte) (historyYear & 0xff); + request[2] = (byte) (historyMonth & 0xff); + request[3] = (byte) (historyDate & 0xff); + request[4] = (byte) (historyHour & 0xff); + request[5] = (byte) (historyMinute & 0xff); + request[6] = (byte) (historySecond & 0xff); + request[7] = (byte) (historyCode & 0xff); + request[8] = (byte) (historyValue & 0xff); + request[9] = (byte) ((historyValue >>> 8) & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "ETC__SET_HISTORY_SAVE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Delivery_Status.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Delivery_Status.java new file mode 100644 index 0000000000..d9e2599eb2 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Delivery_Status.java @@ -0,0 +1,32 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_General_Delivery_Status extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Delivery_Status.class); + + public DanaRS_Packet_General_Delivery_Status() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__DELIVERY_STATUS; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Status: " + status); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__DELIVERY_STATUS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_More_Information.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_More_Information.java new file mode 100644 index 0000000000..cd2de4094f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_More_Information.java @@ -0,0 +1,70 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_General_Get_More_Information extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Get_More_Information.class); + + public DanaRS_Packet_General_Get_More_Information() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_MORE_INFORMATION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 2; + pump.iob = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.dailyTotalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + pump.isExtendedInProgress = byteArrayToInt(getBytes(data, dataIndex, dataSize)) == 0x01; + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusRemainingMinutes = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + double remainRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + Date lastBolusTime = new Date(); // it doesn't provide day only hour+min, workaround: expecting today + dataIndex += dataSize; + dataSize = 1; + lastBolusTime.setHours(byteArrayToInt(getBytes(data, dataIndex, dataSize))); + + dataIndex += dataSize; + dataSize = 1; + lastBolusTime.setMinutes(byteArrayToInt(getBytes(data, dataIndex, dataSize))); + + dataIndex += dataSize; + dataSize = 2; + pump.lastBolusAmount = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Daily total units: " + pump.dailyTotalUnits + " U"); + log.debug("Is extended in progress: " + pump.isExtendedInProgress); + log.debug("Extended bolus remaining minutes: " + pump.extendedBolusRemainingMinutes); + log.debug("Last bolus time: " + lastBolusTime.toLocaleString()); + log.debug("Last bolus amount: " + pump.lastBolusAmount); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__GET_MORE_INFORMATION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Password.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Password.java new file mode 100644 index 0000000000..0d250db919 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Password.java @@ -0,0 +1,36 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_General_Get_Password extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Get_Password.class); + + public DanaRS_Packet_General_Get_Password() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_PASSWORD; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int pass = ((data[DATA_START + 1] & 0x000000FF) << 8) + (data[DATA_START + 0] & 0x000000FF); + pass = pass ^ 3463; + pump.rs_password = Integer.toHexString(pass); + if (Config.logDanaMessageDetail) { + log.debug("Pump password: " + pump.rs_password); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__GET_PASSWORD"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Pump_Check.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Pump_Check.java new file mode 100644 index 0000000000..d82d6229b9 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Pump_Check.java @@ -0,0 +1,45 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_General_Get_Pump_Check extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Get_Pump_Check.class); + + public DanaRS_Packet_General_Get_Pump_Check() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_PUMP_CHECK; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + pump.model = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.protocol = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.productCode = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Model: " + String.format("%02X ", pump.model)); + log.debug("Protocol: " + String.format("%02X ", pump.protocol)); + log.debug("Product Code: " + String.format("%02X ", pump.productCode)); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__GET_PUMP_CHECK"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Shipping_Information.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Shipping_Information.java new file mode 100644 index 0000000000..2cf9b1f124 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Shipping_Information.java @@ -0,0 +1,46 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_General_Get_Shipping_Information extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.class); + + public DanaRS_Packet_General_Get_Shipping_Information() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_SHIPPING_INFORMATION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 10; + pump.serialNumber = stringFromBuff(data, dataIndex, dataSize); + + dataIndex += dataSize; + dataSize = 3; + pump.shippingDate = dateFromBuff(data, dataIndex); + + dataIndex += dataSize; + dataSize = 3; + pump.shippingCountry = asciiStringFromBuff(data, dataIndex, dataSize); + + if (Config.logDanaMessageDetail) { + log.debug("Serial number: " + pump.serialNumber); + log.debug("Shipping date: " + pump.shippingDate); + log.debug("Shipping country: " + pump.shippingCountry); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__GET_SHIPPING_INFORMATION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Today_Delivery_Total.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Today_Delivery_Total.java new file mode 100644 index 0000000000..a40d572611 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Today_Delivery_Total.java @@ -0,0 +1,47 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_General_Get_Today_Delivery_Total extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Get_Today_Delivery_Total.class); + + public DanaRS_Packet_General_Get_Today_Delivery_Total() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_TODAY_DELIVERY_TOTAL; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 2; + pump.dailyTotalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.dailyTotalBasalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.dailyTotalBolusUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (Config.logDanaMessageDetail) { + log.debug("Daily total: " + pump.dailyTotalUnits + " U"); + log.debug("Daily total bolus: " + pump.dailyTotalBolusUnits + " U"); + log.debug("Daily total basal: " + pump.dailyTotalBasalUnits + " U"); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__GET_TODAY_DELIVERY_TOTAL"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_User_Time_Change_Flag.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_User_Time_Change_Flag.java new file mode 100644 index 0000000000..695e3eace4 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_User_Time_Change_Flag.java @@ -0,0 +1,32 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_General_Get_User_Time_Change_Flag extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Get_User_Time_Change_Flag.class); + + public DanaRS_Packet_General_Get_User_Time_Change_Flag() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__GET_USER_TIME_CHANGE_FLAG; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int userTimeChangeFlag = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("UserTimeChangeFlag: " + userTimeChangeFlag); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__GET_USER_TIME_CHANGE_FLAG"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Initial_Screen_Information.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Initial_Screen_Information.java new file mode 100644 index 0000000000..a6145302ad --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Initial_Screen_Information.java @@ -0,0 +1,85 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_General_Initial_Screen_Information extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Bolus_Get_Step_Bolus_Information.class); + + public DanaRS_Packet_General_Initial_Screen_Information() { + super(); + type = BleCommandUtil.DANAR_PACKET__TYPE_RESPONSE; + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION; + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + pump.pumpSuspended = (status & 0x01) == 0x01; + pump.isTempBasalInProgress = (status & 0x10) == 0x10; + pump.isExtendedInProgress = (status & 0x04) == 0x04; + pump.isDualBolusInProgress = (status & 0x08) == 0x08; + + dataIndex += dataSize; + dataSize = 2; + pump.dailyTotalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.maxDailyTotalUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.reservoirRemainingUnits = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.currentBasal = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 1; + pump.tempBasalPercent = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.batteryRemaining = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.extendedBolusAbsoluteRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + pump.iob = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + if (Config.logDanaMessageDetail) { + log.debug("Pump suspended: " + pump.pumpSuspended); + log.debug("Temp basal in progress: " + pump.isTempBasalInProgress); + log.debug("Extended in progress: " + pump.isExtendedInProgress); + log.debug("Dual in progress: " + pump.isDualBolusInProgress); + log.debug("Daily units: " + pump.dailyTotalUnits); + log.debug("Max daily units: " + pump.maxDailyTotalUnits); + log.debug("Reservoir remaining units: " + pump.reservoirRemainingUnits); + log.debug("Battery: " + pump.batteryRemaining); + log.debug("Current basal: " + pump.currentBasal); + log.debug("Temp basal percent: " + pump.tempBasalPercent); + log.debug("Extended absolute rate: " + pump.extendedBolusAbsoluteRate); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__INITIAL_SCREEN_INFORMATION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_History_Upload_Mode.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_History_Upload_Mode.java new file mode 100644 index 0000000000..7d9ec07ff1 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_History_Upload_Mode.java @@ -0,0 +1,47 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_General_Set_History_Upload_Mode extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Set_History_Upload_Mode.class); + + private int mode; + + public DanaRS_Packet_General_Set_History_Upload_Mode() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SET_HISTORY_UPLOAD_MODE; + } + + public DanaRS_Packet_General_Set_History_Upload_Mode(int mode) { + this(); + this.mode = mode; + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[1]; + request[0] = (byte) (mode & 0xff); + return request; + } + + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__SET_HISTORY_UPLOAD_MODE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear.java new file mode 100644 index 0000000000..9cc6b7b2e0 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear.java @@ -0,0 +1,33 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear.class); + + public DanaRS_Packet_General_Set_User_Time_Change_Flag_Clear() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SET_USER_TIME_CHANGE_FLAG_CLEAR; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int status = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("Result: " + status); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__SET_USER_TIME_CHANGE_FLAG_CLEAR"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_.java new file mode 100644 index 0000000000..b449e489dd --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_.java @@ -0,0 +1,124 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import com.cozmo.danar.util.BleCommandUtil; + +public abstract class DanaRS_Packet_History_ extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_History_.class); + + private int year; + private int month; + private int day; + private int hour; + private int min; + private int sec; + + public boolean done; + public int totalCount; + + public DanaRS_Packet_History_() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BOLUS; + done = false; + totalCount = 0; + } + + public DanaRS_Packet_History_(Date from) { + this(); + GregorianCalendar cal = new GregorianCalendar(); + cal.setTime(from); + year = cal.get(Calendar.YEAR) - 1900 - 100; + month = cal.get(Calendar.MONTH) + 1; + day = cal.get(Calendar.DAY_OF_MONTH); + hour = cal.get(Calendar.HOUR_OF_DAY); + min = cal.get(Calendar.MINUTE); + sec = cal.get(Calendar.SECOND); + } + + public DanaRS_Packet_History_(int year, int month, int day, int hour, int min, int sec) { + this(); + this.year = year; + this.month = month; + this.day = day; + this.hour = hour; + this.min = min; + this.sec = sec; + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[6]; + request[0] = (byte) (year & 0xff); + request[1] = (byte) (month & 0xff); + request[2] = (byte) (day & 0xff); + request[3] = (byte) (hour & 0xff); + request[4] = (byte) (min & 0xff); + request[5] = (byte) (sec & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int error = 0x00; + totalCount = 0; + if (data.length == 3) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + done = error == 0x00; + } else if (data.length == 5) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + done = error == 0x00; + + dataIndex += dataSize; + dataSize = 2; + totalCount = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + } else { + int dataIndex = DATA_START; + int dataSize = 1; + int historyType = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int historyYear = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int historyMonth = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int historyDay = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int historyHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int historyMinute = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int historySecond = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + Date date = new Date(100 + historyYear, historyMonth - 1, historyDay, historyHour, historyMinute, historySecond); + + dataIndex += dataSize; + dataSize = 1; + int historyCode = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + int historyValue = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Alarm.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Alarm.java new file mode 100644 index 0000000000..5fe57fefe4 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Alarm.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Alarm extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Alarm() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__ALARM; + } + + public DanaRS_Packet_History_Alarm(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__ALARM; + } + + @Override + public String getFriendlyName() { + return "REVIEW__ALARM"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_All_History.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_All_History.java new file mode 100644 index 0000000000..a514d4eac7 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_All_History.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_All_History extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_All_History() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__ALL_HISTORY; + } + + public DanaRS_Packet_History_All_History(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__ALL_HISTORY; + } + + @Override + public String getFriendlyName() { + return "REVIEW__ALL_HISTORY"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Basal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Basal.java new file mode 100644 index 0000000000..4aec1d0352 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Basal.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Basal extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Basal() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BASAL; + } + + public DanaRS_Packet_History_Basal(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BASAL; + } + + @Override + public String getFriendlyName() { + return "REVIEW__BASAL"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Blood_Glucose.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Blood_Glucose.java new file mode 100644 index 0000000000..22bb3b5c2e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Blood_Glucose.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Blood_Glucose extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Blood_Glucose() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BLOOD_GLUCOSE; + } + + public DanaRS_Packet_History_Blood_Glucose(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BLOOD_GLUCOSE; + } + + @Override + public String getFriendlyName() { + return "REVIEW__BLOOD_GLUCOSE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Bolus.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Bolus.java new file mode 100644 index 0000000000..7451f921be --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Bolus.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Bolus extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Bolus() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BOLUS; + } + + public DanaRS_Packet_History_Bolus(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BOLUS; + } + + @Override + public String getFriendlyName() { + return "REVIEW__BOLUS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Carbohydrate.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Carbohydrate.java new file mode 100644 index 0000000000..df2f5c762d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Carbohydrate.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Carbohydrate extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Carbohydrate() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__CARBOHYDRATE; + } + + public DanaRS_Packet_History_Carbohydrate(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__CARBOHYDRATE; + } + + @Override + public String getFriendlyName() { + return "REVIEW__CARBOHYDRATE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Daily.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Daily.java new file mode 100644 index 0000000000..b55754ba2f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Daily.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Daily extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Daily() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__DAILY; + } + + public DanaRS_Packet_History_Daily(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__DAILY; + } + + @Override + public String getFriendlyName() { + return "REVIEW__DAILY"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Prime.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Prime.java new file mode 100644 index 0000000000..b5dbf7ff93 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Prime.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Prime extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Prime() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__PRIME; + } + + public DanaRS_Packet_History_Prime(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__PRIME; + } + + @Override + public String getFriendlyName() { + return "REVIEW__PRIME"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Refill.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Refill.java new file mode 100644 index 0000000000..66094e3fb6 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Refill.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Refill extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Refill() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__REFILL; + } + + public DanaRS_Packet_History_Refill(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__REFILL; + } + + @Override + public String getFriendlyName() { + return "REVIEW__REFILL"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Suspend.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Suspend.java new file mode 100644 index 0000000000..20f1c3d6ff --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Suspend.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Suspend extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Suspend() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SUSPEND; + } + + public DanaRS_Packet_History_Suspend(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__SUSPEND; + } + + @Override + public String getFriendlyName() { + return "REVIEW__SUSPEND"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Temporary.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Temporary.java new file mode 100644 index 0000000000..7d63e1bfff --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_Temporary.java @@ -0,0 +1,23 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import java.util.Date; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_History_Temporary extends DanaRS_Packet_History_ { + + public DanaRS_Packet_History_Temporary() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__TEMPORARY; + } + + public DanaRS_Packet_History_Temporary(Date from) { + super(from); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__TEMPORARY; + } + + @Override + public String getFriendlyName() { + return "REVIEW__TEMPORARY"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Alarm.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Alarm.java new file mode 100644 index 0000000000..88edd13a63 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Alarm.java @@ -0,0 +1,88 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.utils.NSUpload; + +public class DanaRS_Packet_Notify_Alarm extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Notify_Alarm.class); + + private int alarmCode; + + public DanaRS_Packet_Notify_Alarm() { + super(); + type = BleCommandUtil.DANAR_PACKET__TYPE_NOTIFY; + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__ALARM; + } + + @Override + public void handleMessage(byte[] data) { + alarmCode = byteArrayToInt(getBytes(data, DATA_START, 1)); + String errorString = ""; + + switch (alarmCode) { + case 0x01: + // Battery 0% Alarm + errorString = MainApp.sResources.getString(R.string.batterydischarged); + break; + case 0x02: + // Pump Error + errorString = MainApp.sResources.getString(R.string.pumperror) + " " + alarmCode; + break; + case 0x03: + // Occlusion + errorString = MainApp.sResources.getString(R.string.occlusion); + break; + case 0x04: + // LOW BATTERY + errorString = MainApp.sResources.getString(R.string.lowbattery); + break; + case 0x05: + // Shutdown + errorString = MainApp.sResources.getString(R.string.lowbattery); + break; + case 0x06: + // Basal Compare + errorString = "BasalCompare ????"; + break; + case 0x09: + // Empty Reservoir + errorString = MainApp.sResources.getString(R.string.emptyreservoir); + break; + + // BT + case 0x07: + case 0xFF: + // Blood sugar measurement alert + errorString = MainApp.sResources.getString(R.string.bloodsugarmeasurementalert); + break; + + case 0x08: + case 0xFE: + // Remaining insulin level + errorString = MainApp.sResources.getString(R.string.remaininsulinalert); + break; + + case 0xFD: + // Blood sugar check miss alarm + errorString = "Blood sugar check miss alarm ???"; + break; + } + + if (Config.logDanaMessageDetail) + log.debug("Error detected: " + errorString); + NSUpload.uploadError(errorString); + } + + @Override + public String getFriendlyName() { + return "NOTIFY__ALARM"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Complete.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Complete.java new file mode 100644 index 0000000000..88327e1201 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Complete.java @@ -0,0 +1,54 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; + +import com.cozmo.danar.util.BleCommandUtil; + +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; + +public class DanaRS_Packet_Notify_Delivery_Complete extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Notify_Delivery_Complete.class); + + private static Treatment t; + private static double amount; + + public DanaRS_Packet_Notify_Delivery_Complete() { + super(); + type = BleCommandUtil.DANAR_PACKET__TYPE_NOTIFY; + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__DELIVERY_COMPLETE; + } + + public DanaRS_Packet_Notify_Delivery_Complete(double amount, Treatment t) { + this(); + this.amount = amount; + this.t = t; + } + + @Override + public void handleMessage(byte[] data) { + double deliveredInsulin = byteArrayToInt(getBytes(data, DATA_START, 2)) / 100d; + + if (t != null) { + t.insulin = deliveredInsulin; + EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance(); + bolusingEvent.status = String.format(MainApp.sResources.getString(R.string.bolusdelivering), deliveredInsulin); + bolusingEvent.t = t; + bolusingEvent.percent = Math.min((int) (deliveredInsulin / amount * 100), 100); + MainApp.bus().post(bolusingEvent); + } + + if (Config.logDanaMessageDetail) + log.debug("Delivered insulin: " + deliveredInsulin); + } + + @Override + public String getFriendlyName() { + return "NOTIFY__DELIVERY_COMPLETE"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Rate_Display.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Rate_Display.java new file mode 100644 index 0000000000..26c12c27af --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Rate_Display.java @@ -0,0 +1,56 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; + +public class DanaRS_Packet_Notify_Delivery_Rate_Display extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Notify_Delivery_Rate_Display.class); + + private static Treatment t; + private static double amount; + + public static long lastReceive = 0; + + public DanaRS_Packet_Notify_Delivery_Rate_Display() { + super(); + type = BleCommandUtil.DANAR_PACKET__TYPE_NOTIFY; + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__DELIVERY_RATE_DISPLAY; + } + + public DanaRS_Packet_Notify_Delivery_Rate_Display(double amount, Treatment t) { + this(); + this.amount = amount; + this.t = t; + lastReceive = System.currentTimeMillis(); + } + + @Override + public void handleMessage(byte[] data) { + double deliveredInsulin = byteArrayToInt(getBytes(data, DATA_START, 2)) / 100d; + + if (t != null) { + lastReceive = System.currentTimeMillis(); + t.insulin = deliveredInsulin; + EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.getInstance(); + bolusingEvent.status = String.format(MainApp.sResources.getString(R.string.bolusdelivering), deliveredInsulin); + bolusingEvent.t = t; + bolusingEvent.percent = Math.min((int) (deliveredInsulin / amount * 100), 100); + MainApp.bus().post(bolusingEvent); + } + + if (Config.logDanaMessageDetail) + log.debug("Delivered insulin so far: " + deliveredInsulin); + } + + @Override + public String getFriendlyName() { + return "NOTIFY__DELIVERY_RATE_DISPLAY"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Missed_Bolus_Alarm.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Missed_Bolus_Alarm.java new file mode 100644 index 0000000000..3af0c209b5 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Missed_Bolus_Alarm.java @@ -0,0 +1,54 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Notify_Missed_Bolus_Alarm extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Notify_Missed_Bolus_Alarm.class); + + public DanaRS_Packet_Notify_Missed_Bolus_Alarm() { + super(); + type = BleCommandUtil.DANAR_PACKET__TYPE_NOTIFY; + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_NOTIFY__MISSED_BOLUS_ALARM; + } + + @Override + public void handleMessage(byte[] data) { + int startHour; + int startMin; + int endHour; + int endMin; + + int dataIndex = DATA_START; + int dataSize = 1; + startHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + startMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + endHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + endMin = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Start hour: " + startHour); + log.debug("Start min: " + startMin); + log.debug("End hour: " + endHour); + log.debug("End min: " + endMin); + } + } + + @Override + public String getFriendlyName() { + return "NOTIFY__MISSED_BOLUS_ALARM"; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_Pump_Time.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_Pump_Time.java new file mode 100644 index 0000000000..4bfebb5211 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_Pump_Time.java @@ -0,0 +1,61 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Option_Get_Pump_Time extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Option_Get_Pump_Time.class); + + public DanaRS_Packet_Option_Get_Pump_Time() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__GET_PUMP_TIME; + if (Config.logDanaMessageDetail) { + log.debug("Requesting pump time"); + } + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + int year = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int month = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int day = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int hour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int min = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int sec = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + Date time = new Date(100 + year, month - 1, day, hour, min, sec); + DanaRPump.getInstance().pumpTime = time; + + if (Config.logDanaMessageDetail) { + log.debug("Pump time " + time.toLocaleString()); + } + } + + @Override + public String getFriendlyName() { + return "OPTION__GET_PUMP_TIME"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_User_Option.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_User_Option.java new file mode 100644 index 0000000000..b4df373f9c --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Get_User_Option.java @@ -0,0 +1,114 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Option_Get_User_Option extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Option_Get_User_Option.class); + + + public DanaRS_Packet_Option_Get_User_Option() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__GET_USER_OPTION; + if (Config.logDanaMessageDetail) { + log.debug("Requesting user settings"); + } + } + + @Override + public void handleMessage(byte[] data) { + DanaRPump pump = DanaRPump.getInstance(); + + int dataIndex = DATA_START; + int dataSize = 1; + pump.timeDisplayType = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.buttonScrollOnOff = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.beepAndAlarm = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.lcdOnTimeSec = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.backlightOnTimeSec = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.selectedLanguage = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.units = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.shutdownHour = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + pump.lowReservoirRate = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.cannulaVolume = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 2; + pump.refillAmount = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int selectableLanguage1 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int selectableLanguage2 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int selectableLanguage3 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int selectableLanguage4 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + dataIndex += dataSize; + dataSize = 1; + int selectableLanguage5 = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + + if (Config.logDanaMessageDetail) { + log.debug("timeDisplayType: " + pump.timeDisplayType); + log.debug("buttonScrollOnOff: " + pump.buttonScrollOnOff); + log.debug("beepAndAlarm: " + pump.beepAndAlarm); + log.debug("lcdOnTimeSec: " + pump.lcdOnTimeSec); + log.debug("backlightOnTimeSec: " + pump.backlightOnTimeSec); + log.debug("selectedLanguage: " + pump.selectedLanguage); + log.debug("Pump units: " + (pump.units == DanaRPump.UNITS_MGDL ? "MGDL" : "MMOL")); + log.debug("shutdownHour: " + pump.shutdownHour); + log.debug("lowReservoirRate: " + pump.lowReservoirRate); + log.debug("refillAmount: " + pump.refillAmount); + log.debug("selectableLanguage1: " + selectableLanguage1); + log.debug("selectableLanguage2: " + selectableLanguage2); + log.debug("selectableLanguage3: " + selectableLanguage3); + log.debug("selectableLanguage4: " + selectableLanguage4); + log.debug("selectableLanguage5: " + selectableLanguage5); + } + } + + @Override + public String getFriendlyName() { + return "OPTION__GET_USER_OPTION"; + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_Pump_Time.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_Pump_Time.java new file mode 100644 index 0000000000..e93e18796d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_Pump_Time.java @@ -0,0 +1,56 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Option_Set_Pump_Time extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Option_Set_Pump_Time.class); + private Date date; + public int error; + + public DanaRS_Packet_Option_Set_Pump_Time() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__SET_PUMP_TIME; + } + + public DanaRS_Packet_Option_Set_Pump_Time(Date date) { + this(); + this.date = date; + if (Config.logDanaMessageDetail) { + log.debug("Setting pump time " + date.toLocaleString()); + } + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[6]; + request[0] = (byte) ((date.getYear() - 100) & 0xff); + request[1] = (byte) ((date.getMonth() + 1) & 0xff); + request[2] = (byte) (date.getDate() & 0xff); + request[3] = (byte) (date.getHours() & 0xff); + request[4] = (byte) (date.getMinutes() & 0xff); + request[5] = (byte) (date.getSeconds() & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "OPTION__SET_PUMP_TIME"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_User_Option.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_User_Option.java new file mode 100644 index 0000000000..49c6d35708 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Option_Set_User_Option.java @@ -0,0 +1,58 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import com.cozmo.danar.util.BleCommandUtil; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; + +public class DanaRS_Packet_Option_Set_User_Option extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Option_Set_User_Option.class); + + private int error; + + public DanaRS_Packet_Option_Set_User_Option() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_OPTION__SET_USER_OPTION; + if (Config.logDanaMessageDetail) { + log.debug("Setting user settings"); + } + } + + @Override + public byte[] getRequestParams() { + DanaRPump pump = DanaRPump.getInstance(); + + byte[] request = new byte[13]; + request[0] = (byte) (pump.timeDisplayType & 0xff); + request[1] = (byte) (pump.buttonScrollOnOff & 0xff); + request[2] = (byte) (pump.beepAndAlarm & 0xff); + request[3] = (byte) (pump.lcdOnTimeSec & 0xff); + request[4] = (byte) (pump.backlightOnTimeSec & 0xff); + request[5] = (byte) (pump.selectedLanguage & 0xff); + request[6] = (byte) (pump.units & 0xff); + request[7] = (byte) (pump.shutdownHour & 0xff); + request[8] = (byte) (pump.lowReservoirRate & 0xff); + request[9] = (byte) (pump.cannulaVolume & 0xff); + request[10] = (byte) ((pump.cannulaVolume >>> 8) & 0xff); + request[11] = (byte) (pump.refillAmount & 0xff); + request[12] = (byte) ((pump.refillAmount >>> 8) & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + if (Config.logDanaMessageDetail) { + log.debug("Result: " + error); + } + } + + @Override + public String getFriendlyName() { + return "OPTION__SET_USER_OPTION"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Review_Bolus_Avg.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Review_Bolus_Avg.java new file mode 100644 index 0000000000..e8440b12d2 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Review_Bolus_Avg.java @@ -0,0 +1,52 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +import com.cozmo.danar.util.BleCommandUtil; + +public class DanaRS_Packet_Review_Bolus_Avg extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Review_Bolus_Avg.class); + + public DanaRS_Packet_Review_Bolus_Avg() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_REVIEW__BOLUS_AVG; + } + + @Override + public void handleMessage(byte[] data) { + int dataIndex = DATA_START; + int dataSize = 2; + double bolusAvg03 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double bolusAvg07 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double bolusAvg14 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double bolusAvg21 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + + dataIndex += dataSize; + dataSize = 2; + double bolusAvg28 = byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d; + if (Config.logDanaMessageDetail) { + log.debug("Bolus average 3d: " + bolusAvg03 + " U"); + log.debug("Bolus average 7d: " + bolusAvg07 + " U"); + log.debug("Bolus average 14d: " + bolusAvg14 + " U"); + log.debug("Bolus average 21d: " + bolusAvg21 + " U"); + log.debug("Bolus average 28d: " + bolusAvg28 + " U"); + } + } + + @Override + public String getFriendlyName() { + return "REVIEW__BOLUS_AVG"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSConnection.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSConnection.java new file mode 100644 index 0000000000..5fd00402e0 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSConnection.java @@ -0,0 +1,21 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.events; + +import android.bluetooth.BluetoothDevice; + +/** + * Created by mike on 01.09.2017. + */ + +public class EventDanaRSConnection { + public EventDanaRSConnection(boolean isConnect, boolean isBusy, boolean isError, BluetoothDevice device) { + this.isConnect = isConnect; + this.isBusy = isBusy; + this.isError = isError; + this.device = device; + } + + public boolean isConnect; + public boolean isBusy; + public boolean isError; + public BluetoothDevice device; +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java new file mode 100644 index 0000000000..8ae02d47ff --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSDeviceChange.java @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.events; + +/** + * Created by mike on 05.09.2017. + */ + +public class EventDanaRSDeviceChange { +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java new file mode 100644 index 0000000000..5815399194 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPacket.java @@ -0,0 +1,15 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.events; + +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet; + +/** + * Created by mike on 01.09.2017. + */ + +public class EventDanaRSPacket { + public EventDanaRSPacket(DanaRS_Packet data) { + this.data = data; + } + + public DanaRS_Packet data; +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java new file mode 100644 index 0000000000..d50091de55 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/events/EventDanaRSPairingSuccess.java @@ -0,0 +1,8 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.events; + +/** + * Created by mike on 01.09.2017. + */ + +public class EventDanaRSPairingSuccess { +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java new file mode 100644 index 0000000000..e131c903f9 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java @@ -0,0 +1,671 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.services; + +import android.app.Service; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothGatt; +import android.bluetooth.BluetoothGattCallback; +import android.bluetooth.BluetoothGattCharacteristic; +import android.bluetooth.BluetoothGattService; +import android.bluetooth.BluetoothManager; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.os.PowerManager; + +import com.cozmo.danar.util.BleCommandUtil; +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRSMessageHashTable; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventAppExit; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.androidaps.plugins.PumpDanaRS.activities.PairingHelperActivity; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSConnection; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSPacket; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSPairingSuccess; +import info.nightscout.utils.SP; + +public class DanaRSService extends Service { + private static Logger log = LoggerFactory.getLogger(DanaRSService.class); + + private static final long WRITE_DELAY_MILLIS = 50; + + public static String UART_READ_UUID = "0000fff1-0000-1000-8000-00805f9b34fb"; + public static String UART_WRITE_UUID = "0000fff2-0000-1000-8000-00805f9b34fb"; + + private byte PACKET_START_BYTE = (byte) 0xA5; + private byte PACKET_END_BYTE = (byte) 0x5A; + + private BluetoothManager mBluetoothManager = null; + private BluetoothAdapter mBluetoothAdapter = null; + private BluetoothDevice mBluetoothDevice = null; + private String mBluetoothDeviceAddress = null; + private String mBluetoothDeviceName = null; + private BluetoothGatt mBluetoothGatt = null; + + private boolean isConnected = false; + private boolean isConnecting = false; + + private BluetoothGattCharacteristic UART_Read; + private BluetoothGattCharacteristic UART_Write; + + private PowerManager.WakeLock mWakeLock; + private IBinder mBinder = new LocalBinder(); + + private Handler mHandler = null; + + private DanaRS_Packet processsedMessage = null; + private ArrayList mSendQueue = new ArrayList<>(); + + + public DanaRSService() { + mHandler = new Handler(); + try { + MainApp.bus().unregister(this); + } catch (RuntimeException x) { + // Ignore + } + initialize(); + MainApp.bus().register(this); + } + + public boolean bolus(double insulin, int carbs, long l, Treatment t) { + return false; + } + + public void bolusStop() { + } + + public boolean tempBasal(Integer percent, int durationInHours) { + return false; + } + + public boolean highTempBasal(Integer percent) { + return false; + } + + public void tempBasalStop() { + } + + public boolean extendedBolus(Double insulin, int durationInHalfHours) { + return false; + } + + public void extendedBolusStop() { + } + + public boolean updateBasalsInPump(Profile profile) { + return false; + } + + public boolean loadHistory(byte type) { + return false; + } + + + public class LocalBinder extends Binder { + public DanaRSService getServiceInstance() { + return DanaRSService.this; + } + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return START_STICKY; + } + + @Subscribe + public void onStatusEvent(EventAppExit event) { + if (Config.logFunctionCalls) + log.debug("EventAppExit received"); + + stopSelf(); + if (Config.logFunctionCalls) + log.debug("EventAppExit finished"); + } + + private boolean initialize() { + log.debug("Initializing service."); + + if (mBluetoothManager == null) { + mBluetoothManager = ((BluetoothManager) MainApp.instance().getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE)); + if (mBluetoothManager == null) { + log.debug("Unable to initialize BluetoothManager."); + return false; + } + } + + mBluetoothAdapter = mBluetoothManager.getAdapter(); + if (mBluetoothAdapter == null) { + log.debug("Unable to obtain a BluetoothAdapter."); + return false; + } + + return true; + } + + public boolean isConnected() { + return isConnected; + } + + public boolean isConnecting() { + return isConnecting; + } + + public boolean connect(String from, String address) { + BluetoothManager tBluetoothManager = ((BluetoothManager) MainApp.instance().getApplicationContext().getSystemService(Context.BLUETOOTH_SERVICE)); + if (tBluetoothManager == null) { + return false; + } + + BluetoothAdapter tBluetoothAdapter = tBluetoothManager.getAdapter(); + if (tBluetoothAdapter == null) { + return false; + } + + if (mBluetoothAdapter == null) { + if (!initialize()) { + return false; + } + } + + if (address == null) { + log.debug("unspecified address."); + return false; + } + + isConnecting = true; + if ((mBluetoothDeviceAddress != null) && (address.equals(mBluetoothDeviceAddress)) && (mBluetoothGatt != null)) { + log.debug("Trying to use an existing mBluetoothGatt for connection."); + if (mBluetoothGatt.connect()) { + setCharacteristicNotification(getUARTReadBTGattChar(), true); + return true; + } + return false; + } + + BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + if (device == null) { + log.debug("Device not found. Unable to connect."); + return false; + } + + mBluetoothGatt = device.connectGatt(getApplicationContext(), false, mGattCallback); + setCharacteristicNotification(getUARTReadBTGattChar(), true); + log.debug("Trying to create a new connection."); + mBluetoothDevice = device; + mBluetoothDeviceAddress = address; + mBluetoothDeviceName = device.getName(); + return true; + } + + public void disconnect(String from) { + log.debug("disconnect from: " + from); + if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { + return; + } + setCharacteristicNotification(getUARTReadBTGattChar(), false); + mBluetoothGatt.disconnect(); + isConnected = false; + } + + public void close() { + log.debug("BluetoothAdapter close"); + if (mBluetoothGatt == null) { + return; + } + mBluetoothGatt.close(); + mBluetoothGatt = null; + } + + public BluetoothDevice getConnectDevice() { + return mBluetoothDevice; + } + + public String getConnectDeviceAddress() { + return mBluetoothDeviceAddress; + } + + public String getConnectDeviceName() { + return mBluetoothDeviceName; + } + + private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { + public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { + log.debug("onConnectionStateChange"); + + if (newState == BluetoothProfile.STATE_CONNECTED) { + mBluetoothGatt.discoverServices(); + } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { + close(); + isConnected = false; + sendBTConnect(false, false, false, null); + } + } + + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + log.debug("onServicesDiscovered"); + + isConnecting = false; + + if (status == BluetoothGatt.GATT_SUCCESS) { + findCharacteristic(); + } + + // 1st message sent to pump after connect + byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK, null, getConnectDeviceName()); + log.debug(">>>>> " + "ENCRYPTION__PUMP_CHECK (0x00)" + " " + DanaRS_Packet.toHexString(bytes)); + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); + } + + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + log.debug("onCharacteristicRead" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); + readDataParsing(characteristic.getValue()); + } + + public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { + log.debug("onCharacteristicChanged" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); + readDataParsing(characteristic.getValue()); + } + + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + log.debug("onCharacteristicWrite" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); + synchronized (mSendQueue) { + // after message sent, check if there is the rest of the message waiting and send it + if (mSendQueue.size() > 0) { + byte[] bytes = mSendQueue.get(0); + mSendQueue.remove(0); + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); + } + } + } + }; + + public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) { + log.debug("setCharacteristicNotification"); + if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { + log.debug("BluetoothAdapter not initialized_ERROR"); + return; + } + mBluetoothGatt.setCharacteristicNotification(characteristic, enabled); + } + + public void readCharacteristic(BluetoothGattCharacteristic characteristic) { + log.debug("readCharacteristic"); + if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { + log.debug("BluetoothAdapter not initialized_ERROR"); + return; + } + mBluetoothGatt.readCharacteristic(characteristic); + } + + public void writeCharacteristic_NO_RESPONSE(final BluetoothGattCharacteristic characteristic, final byte[] data) { + if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { + log.debug("BluetoothAdapter not initialized_ERROR"); + return; + } + + new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(WRITE_DELAY_MILLIS); + characteristic.setValue(data); + characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); + mBluetoothGatt.writeCharacteristic(characteristic); + //log.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data)); + } catch (Exception e) { + } + } + }).start(); + } + + public BluetoothGattCharacteristic getUARTReadBTGattChar() { + if (UART_Read == null) { + UART_Read = new BluetoothGattCharacteristic(UUID.fromString(UART_READ_UUID), BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_NOTIFY, 0); + } + return UART_Read; + } + + public BluetoothGattCharacteristic getUARTWriteBTGattChar() { + if (UART_Write == null) { + UART_Write = new BluetoothGattCharacteristic(UUID.fromString(UART_WRITE_UUID), BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, 0); + } + return UART_Write; + } + + public List getSupportedGattServices() { + log.debug("getSupportedGattServices"); + if ((mBluetoothAdapter == null) || (mBluetoothGatt == null)) { + log.debug("BluetoothAdapter not initialized_ERROR"); + return null; + } + + return mBluetoothGatt.getServices(); + } + + private void findCharacteristic() { + List gattServices = getSupportedGattServices(); + + if (gattServices == null) { + return; + } + String uuid = null; + + for (BluetoothGattService gattService : gattServices) { + List gattCharacteristics = gattService.getCharacteristics(); + for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) { + uuid = gattCharacteristic.getUuid().toString(); + if (UART_READ_UUID.equals(uuid)) { + UART_Read = gattCharacteristic; + setCharacteristicNotification(UART_Read, true); + } + if (UART_WRITE_UUID.equals(uuid)) { + UART_Write = gattCharacteristic; + } + } + } + } + + private byte[] readBuffer = new byte[1024]; + private int bufferLength = 0; + + private void readDataParsing(byte[] buffer) { + boolean startSignatureFound = false, packetIsValid = false; + boolean isProcessing; + + if (buffer == null || buffer.length == 0) { + return; + } + + // Append incomming data to input buffer + System.arraycopy(buffer, 0, readBuffer, bufferLength, buffer.length); + bufferLength += buffer.length; + + isProcessing = true; + + while (isProcessing) { + // Find packet start [A5 A5] + if (bufferLength >= 6) { + for (int idxStartByte = 0; idxStartByte < bufferLength - 2; idxStartByte++) { + if ((readBuffer[idxStartByte] == PACKET_START_BYTE) && (readBuffer[idxStartByte + 1] == PACKET_START_BYTE)) { + if (idxStartByte > 0) { + // if buffer doesn't start with signature remove the leading trash + log.debug("Shifting the input buffer by " + idxStartByte + " bytes"); + System.arraycopy(readBuffer, idxStartByte, readBuffer, 0, bufferLength - idxStartByte); + bufferLength -= idxStartByte; + } + startSignatureFound = true; + break; + } + } + } + // A5 A5 LEN TYPE CODE PARAMS CHECKSUM1 CHECKSUM2 5A 5A + // ^---- LEN -----^ + // total packet length 2 + 1 + readBuffer[2] + 2 + 2 + int length = 0; + if (startSignatureFound) { + length = readBuffer[2]; + // test if there is enough data loaded + if (length + 7 > bufferLength) + return; + // Verify packed end [5A 5A] + if ((readBuffer[length + 5] == PACKET_END_BYTE) && (readBuffer[length + 6] == PACKET_END_BYTE)) { + packetIsValid = true; + } + } + if (packetIsValid) { + // copy packet to input buffer + byte[] inputBuffer = new byte[length + 7]; + System.arraycopy(readBuffer, 0, inputBuffer, 0, length + 7); + // now we have encrypted packet in inputBuffer + try { + // decrypt the packet + inputBuffer = BleCommandUtil.getInstance().getDecryptedPacket(inputBuffer); + + switch (inputBuffer[0]) { + // initial handshake packet + case (byte) BleCommandUtil.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE: + switch (inputBuffer[1]) { + // 1st packet + case (byte) BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK: + if (inputBuffer.length == 4 && inputBuffer[2] == 'O' && inputBuffer[3] == 'K') { + log.debug("<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(inputBuffer)); + // Grab pairing key from preferences if exists + String pairingKey = SP.getString(R.string.key_danars_pairingkey, null); + log.debug("Using stored pairing key: " + pairingKey); + if (pairingKey != null) { + byte[] encodedPairingKey = DanaRS_Packet.hexToBytes(pairingKey); + byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY, encodedPairingKey, null); + log.debug(">>>>> " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(bytes)); + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); + } else { + // Stored pairing key does not exists, request pairing + SendPairingRequest(); + } + + } else if (inputBuffer.length == 6 && inputBuffer[2] == 'B' && inputBuffer[3] == 'U' && inputBuffer[4] == 'S' && inputBuffer[5] == 'Y') { + log.debug("<<<<< " + "ENCRYPTION__PUMP_CHECK (BUSY)" + " " + DanaRS_Packet.toHexString(inputBuffer)); + sendBTConnect(false, true, false, null); + } else { + log.debug("<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(inputBuffer)); + sendBTConnect(false, false, true, null); + } + break; + // 2nd packet, pairing key + case (byte) BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY: + log.debug("<<<<< " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(inputBuffer)); + if (inputBuffer[2] == (byte) 0x00) { + // Paring is not requested, sending time info + SendTimeInfo(); + } else { + // Pairing on pump is requested + SendPairingRequest(); + } + break; + case (byte) BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST: + log.debug("<<<<< " + "ENCRYPTION__PASSKEY_REQUEST " + DanaRS_Packet.toHexString(inputBuffer)); + if (inputBuffer[2] != (byte) 0x00) { + disconnect("passkey request failed"); + } + break; + // Paring response, OK button on pump pressed + case (byte) BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_RETURN: + log.debug("<<<<< " + "ENCRYPTION__PASSKEY_RETURN " + DanaRS_Packet.toHexString(inputBuffer)); + // Paring is successfull, sending time info + MainApp.bus().post(new EventDanaRSPairingSuccess()); + SendTimeInfo(); + byte[] pairingKey = {inputBuffer[2], inputBuffer[3]}; + // store pairing key to preferences + SP.putString(R.string.key_danars_pairingkey, DanaRS_Packet.bytesToHex(pairingKey)); + log.debug("Got pairing key: " + DanaRS_Packet.bytesToHex(pairingKey)); + break; + // time and user password information. last packet in handshake + case (byte) BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION: + log.debug("<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */ DanaRS_Packet.toHexString(inputBuffer)); + int size = inputBuffer.length; + int pass = ((inputBuffer[size - 1] & 0x000000FF) << 8) + ((inputBuffer[size - 2] & 0x000000FF)); + pass = pass ^ 3463; + DanaRPump.getInstance().rs_password = Integer.toHexString(pass); + log.debug("Pump user password: " + Integer.toHexString(pass)); + sendBTConnect(true, false, false, getConnectDevice()); + break; + } + break; + // common data packet + default: + DanaRS_Packet message; + // Retrieve message code from received buffer and last message sent + int originalCommand = processsedMessage != null ? processsedMessage.getCommand() : 0xFFFF; + int receivedCommand = DanaRS_Packet.getCommand(inputBuffer); + if (originalCommand == receivedCommand) { + // it's response to last message + message = processsedMessage; + } else { + // it's not response to last message, create new instance + message = DanaRSMessageHashTable.findMessage(receivedCommand); + } + if (message != null) { + log.debug("<<<<< " + message.getFriendlyName() + " " + DanaRS_Packet.toHexString(inputBuffer)); + // process received data + message.handleMessage(inputBuffer); + message.setReceived(); + synchronized (message) { + // notify to sendMessage + message.notify(); + } + MainApp.bus().post(new EventDanaRSPacket(message)); + } else { + log.error("Unknown message received " + DanaRS_Packet.toHexString(inputBuffer)); + } + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + // Cut off the message from readBuffer + System.arraycopy(readBuffer, length + 7, readBuffer, 0, bufferLength - (length + 7)); + bufferLength -= (length + 7); + startSignatureFound = false; + packetIsValid = false; + if (bufferLength < 6) { + // stop the loop + isProcessing = false; + } + } else { + // stop the loop + isProcessing = false; + } + } + } + + public void sendMessage(DanaRS_Packet message) { + processsedMessage = message; + if (message == null) + return; + + byte[] command = {(byte) message.getType(), (byte) message.getOpCode()}; + byte[] params = message.getRequestParams(); + log.debug(">>>>> " + message.getFriendlyName() + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params)); + byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(message.getOpCode(), params, null); + // If there is another message not completely sent, add to queue only + if (mSendQueue.size() > 0) { + // Split to parts per 20 bytes max + for (; ; ) { + if (bytes.length > 20) { + byte[] addBytes = new byte[20]; + System.arraycopy(bytes, 0, addBytes, 0, addBytes.length); + byte[] reBytes = new byte[bytes.length - addBytes.length]; + System.arraycopy(bytes, addBytes.length, reBytes, 0, reBytes.length); + bytes = reBytes; + synchronized (mSendQueue) { + mSendQueue.add(addBytes); + } + } else { + synchronized (mSendQueue) { + mSendQueue.add(bytes); + } + break; + } + } + + } else { + if (bytes.length > 20) { + // Cut first 20 bytes + byte[] sendBytes = new byte[20]; + System.arraycopy(bytes, 0, sendBytes, 0, sendBytes.length); + byte[] reBytes = new byte[bytes.length - sendBytes.length]; + System.arraycopy(bytes, sendBytes.length, reBytes, 0, reBytes.length); + bytes = reBytes; + // and send + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), sendBytes); + // The rest split to parts per 20 bytes max + for (; ; ) { + if (bytes.length > 20) { + byte[] addBytes = new byte[20]; + System.arraycopy(bytes, 0, addBytes, 0, addBytes.length); + reBytes = new byte[bytes.length - addBytes.length]; + System.arraycopy(bytes, addBytes.length, reBytes, 0, reBytes.length); + bytes = reBytes; + synchronized (mSendQueue) { + mSendQueue.add(addBytes); + } + } else { + synchronized (mSendQueue) { + mSendQueue.add(bytes); + } + break; + } + } + } else { + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); + } + } + // The rest from queue is send from onCharasteristicWrite (after sending 1st part) + synchronized (message) { + try { + message.wait(5000); + } catch (InterruptedException e) { + log.error("sendMessage InterruptedException", e); + e.printStackTrace(); + } + } + + try { + Thread.sleep(200); + } catch (InterruptedException e) { + } + if (!message.isReceived()) { + log.warn("Reply not received " + message.getFriendlyName()); + } + } + + private void SendPairingRequest() { + // Start activity which is waiting 20sec + // On pump pairing request is displayed and is waiting for conformation + Intent i = new Intent(); + i.setClass(MainApp.instance(), PairingHelperActivity.class); + i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + MainApp.instance().startActivity(i); + + byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST, null, null); + log.debug(">>>>> " + "ENCRYPTION__PASSKEY_REQUEST" + " " + DanaRS_Packet.toHexString(bytes)); + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); + } + + private void SendTimeInfo() { + byte[] bytes = BleCommandUtil.getInstance().getEncryptedPacket(BleCommandUtil.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, null, null); + log.debug(">>>>> " + "ENCRYPTION__TIME_INFORMATION" + " " + DanaRS_Packet.toHexString(bytes)); + writeCharacteristic_NO_RESPONSE(getUARTWriteBTGattChar(), bytes); + } + + private void sendBTConnect(boolean isConnected, boolean isBusy, boolean isError, BluetoothDevice device) { + if (isConnected) { + this.isConnected = true; + } else { + mSendQueue.clear(); + } + + MainApp.bus().post(new EventDanaRSConnection(isConnected, isBusy, isError, device)); + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java index 65d3917381..eb08a06b96 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/DanaRv2Plugin.java @@ -210,7 +210,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, @Override public boolean isInitialized() { - return pump.lastConnection.getTime() > 0 && pump.isExtendedBolusEnabled; + return pump.lastConnection.getTime() > 0; } @Override diff --git a/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so b/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so new file mode 100644 index 0000000000000000000000000000000000000000..69e283b5feb97bb8a055667ad99ef5a9da19f549 GIT binary patch literal 14000 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 literal 0 HcmV?d00001 diff --git a/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so new file mode 100644 index 0000000000000000000000000000000000000000..0c717bc3e836ca2b3bc7a546fa4d7779e1f52334 GIT binary patch literal 13728 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 a1zkzJ0ZhE85RTh`+WnyWD^+48PWL~3K&c}D literal 0 HcmV?d00001 diff --git a/app/src/main/jniLibs/armeabi/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi/libBleCommandUtil.so new file mode 100644 index 0000000000000000000000000000000000000000..a51a8c7d9a16654b7d0e34c9d6e15b1a866b74f9 GIT binary patch literal 13724 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 +TC{q;14 zGsZF4?`N(1ln2^NCvawb4SVSc*zA+=_rXT5#`*CCY&*i3^HtE5IAbiOpTdrh;SAY> zJYm@HvHg`a7Iy9TC+2?LgEr#@);U)OVZR^2neq+Wey`&*WtgH-==Jwt@BDA%y&Pvs zMQOyjGJrl|%$Wn$Spa9s@6`ockQwc-r*Z2J?se91>D+3^y9Lj8o(Id&PuAQn*Ir?5 z7jU9QpJV7JYqm?a_By(PHSE<)A9gtQY6t990`{s4_G-88zMm{A`Ob{JVzyjQtgN0G zS~Pb(JZ5yq++(()WXza5_rqoG+OnDUR_ULc6*$8`g0=RF{tUB@hGDzz!MFdbphqi| zMh-_$BJ8_26b*yxY1@{yXo&mbjJeGnTfgL+(2*$$J^)*V^&Q1|8sDAgO~`&{D7RZ| z6TbMHP?z&&5rtvpH=|{kZ|A(beBn2t9g6)H!*!f{51F*?A;E)Dundg4=Stg7OitS_ z>rJ7^_N!*pK3g?nZFc!P{X74H_eh13n4dc^Ka*ISDeL~GLRU}^{C8uG1hF<#Sepok zpTl{p2WvBdwfUTL#@dBEA?s{~H86d)!aNCKZDJoTU7J7uo!2JbnXb6OS(D{w2L8Ug z1~Ja)n|*)%O=pIgw$8l<%g+q_otZVr-)VE#pwnlr=iD{O^_=g_!1d0ovvJh53;Zgv z&gMEZ^kCf2cV>uLX9kt-+xf9M7Wy?^g?(!opTQ?;=ob@si<`cK@*7Cwkui@-ckf(4 zll6FO#9ik5AwCy0^E;(BsRr@>XYKJ%Vm-A?S#yu;tEaA7epfN6dyTEt0*_z7`DI>l^lWR^Peb zK5)MfbIR^Fzf*W{_j*q`d%B8!vH|40@BH5h z!loeKVU?c6nP(T?JdfebvtyjgC;j6nZ=aLqdy7Dx!zhQc+`b*wdC6t_jk5N^{_9sd zarjjed*X@wHDsWD%XAgt8oZZx`eTRq4SUlZj4I3CL68USK8A1en>Dwa->i9DV@0l` z0)BqSu7u`y>?&w}$L^Y=?sERfa~SV8R^8QLa}Rbz{?3JD;AM-)p!99`aqE2Ub>F%$Z=;8M%NnvU4`(-%zaf z<_e_}%pD{l;ML*Kf{_qz8MyNu;dwd~+izTmb2O!!(DXUw+p#e**o$d#3pm>$9dg z1^p@XS!nveG;0+6ZV#b9ni-=H_dI(*1;0ll{;@D<*rMVl{H_(|46a_ zAH&P9nuLpZQkp@XZUPLGlZxej)pnC1|d{~Y=V3Y$*&4D?oR z)R%Q=^BgWmi0^XP+EndaXVADQ$SKGqgxwM7B4pj#wbyFlbvJIfRBLX!rfHkDCUWJ~ zkt^3+rGTp zcnQZ=XN~#%{f{j|@!r8Lq%cTt1vO>*GTD)=(M?U?`F7{cO-6URr{Cz!P}4}N zH$B)hL`{Q3*;EtCG<9!D_b2}#ousBdBhyDs$?b!g?E|*Xj*ykdnJ=>fain2-aeivb zrnY6BZ)LJuy7@yxNh51eQ>riCGhz&+;(bXJa6{CT9!zKB#>j}Votkc9F%1TId3b3+sOIY z=CPbYUN$!z$9dTHwL{qcaU9!77PgJ9LlMh$;4j-PPGXzIaxMJa7IqxZavOy09Q)bU zv1sr^S@xa3%dQVn4dHxjb6J>!TOa3RhJOO#HgI{i4=h~_)p6Vhc6UJBd~DBHEF*2D z+WlqkE+^j_Xn%t(-{J(vaUCpw?r3gbC-Sjug5Py+KORH`=jVKfkcXv}BOK@E+mA5s zTg;mGEEYG7v%3BX_<0#}KHke%n1k!we1C@sX2Rb+i99SV_%6q><9uB1IE0(S_3^&I z;xec$O(?)Z?bz8@;>I36~Ld)+S&bZi?Fu(>SXLfzIWY1&~Co}1MRzcO#lD@ literal 0 HcmV?d00001 diff --git a/app/src/main/jniLibs/mips64/libBleCommandUtil.so b/app/src/main/jniLibs/mips64/libBleCommandUtil.so new file mode 100644 index 0000000000000000000000000000000000000000..a8a292ea13037eccfe791f25e6526e8947b64a24 GIT binary patch literal 14808 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 Vi@KXCds`=a1^r1Ij7tj2#yRgD^N4C`iP~ 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 + + + + + + + diff --git a/app/src/main/res/layout/danars_blescanner_item.xml b/app/src/main/res/layout/danars_blescanner_item.xml new file mode 100644 index 0000000000..2c620b532f --- /dev/null +++ b/app/src/main/res/layout/danars_blescanner_item.xml @@ -0,0 +1,33 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/danars_pairingprogressdialog.xml b/app/src/main/res/layout/danars_pairingprogressdialog.xml new file mode 100644 index 0000000000..fc8c97836f --- /dev/null +++ b/app/src/main/res/layout/danars_pairingprogressdialog.xml @@ -0,0 +1,41 @@ + + + + + + + + +