diff --git a/app/build.gradle b/app/build.gradle index 1742444504..30158bf591 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,10 +43,16 @@ android { applicationId "info.nightscout.androidaps" minSdkVersion 21 targetSdkVersion 23 + multiDexEnabled true versionCode 1500 version "1.54-dev" buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "BUILDVERSION", generateGitBuild() + + ndk { + abiFilters "armeabi-v7a", "x86", "armeabi", "mips" + moduleName "BleCommandUtil" + } } lintOptions { disable 'MissingTranslation' @@ -58,7 +64,7 @@ android { } } productFlavors { - flavorDimensions "standard", "wear" + flavorDimensions "standard" full { dimension "standard" resValue "string", "app_name", "AndroidAPS" @@ -107,22 +113,6 @@ android { buildConfigField "boolean", "NSCLIENTOLNY", "true" buildConfigField "boolean", "CLOSEDLOOP", "false" } - wear { - dimension "wear" - buildConfigField "boolean", "WEAR", "true" - buildConfigField "boolean", "WEAR_CONTROL", "false" - - } - wearcontrol { - dimension "wear" - buildConfigField "boolean", "WEAR", "true" - buildConfigField "boolean", "WEAR_CONTROL", "true" - } - nowear { - dimension "wear" - buildConfigField "boolean", "WEAR", "false" - buildConfigField "boolean", "WEAR_CONTROL", "false" - } } } @@ -136,8 +126,7 @@ allprojects { } dependencies { - wearWearApp project(path: ':wear', configuration: 'restrictedRelease') - wearcontrolWearApp project(path: ':wear', configuration: 'fullRelease') + wearApp project(':wear') compile fileTree(include: ['*.jar'], dir: 'libs') compile('com.crashlytics.sdk.android:crashlytics:2.6.7@aar') { diff --git a/app/libs/rhino-1.7.7.2.jar b/app/libs/rhino-1.7.7.2.jar new file mode 100644 index 0000000000..4a18d33609 Binary files /dev/null and b/app/libs/rhino-1.7.7.2.jar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7d792556b7..be3c0e5d80 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,6 +17,7 @@ + @@ -50,6 +51,13 @@ + + + + + + + + diff --git a/app/src/main/assets/OpenAPSAMA/loggerhelper.js b/app/src/main/assets/OpenAPSAMA/loggerhelper.js new file mode 100644 index 0000000000..e790f465c8 --- /dev/null +++ b/app/src/main/assets/OpenAPSAMA/loggerhelper.js @@ -0,0 +1,12 @@ +var console = { }; +console.error = function error(){ + for (var i = 0, len = arguments.length; i < len; i++) { + console2.log(arguments[i]); + } +}; + +console.log = function log(){ + for (var i = 0, len = arguments.length; i < len; i++) { + console2.log(arguments[i]); + } +}; 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..a417b379e8 --- /dev/null +++ b/app/src/main/java/com/cozmo/danar/util/BleCommandUtil.java @@ -0,0 +1,120 @@ +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_BASAL__APS_SET_TEMPORARY_BASAL = 0xC1; + public static final int DANAR_PACKET__OPCODE__APS_HISTORY_EVENTS = 0xC2; + public static final int DANAR_PACKET__OPCODE__APS_SET_EVENT_HISTORY = 0xC3; + + 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..abda0ca941 100644 --- a/app/src/main/java/info/nightscout/androidaps/Config.java +++ b/app/src/main/java/info/nightscout/androidaps/Config.java @@ -11,7 +11,6 @@ public class Config { // PLUGINS public static final boolean OPENAPSENABLED = APS; public static final boolean LOOPENABLED = APS; - public static final boolean WEAR = BuildConfig.WEAR; public static final boolean NSCLIENT = BuildConfig.NSCLIENTOLNY; @@ -40,10 +39,10 @@ public class Config { public static final boolean logNSUpload = true; public static final boolean logPumpActions = true; public static final boolean logCongigBuilderActions = true; - public static final boolean logAutosensData = true; + public static final boolean logAutosensData = false; // 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/Constants.java b/app/src/main/java/info/nightscout/androidaps/Constants.java index e361e4cc8c..e37a5b4b9f 100644 --- a/app/src/main/java/info/nightscout/androidaps/Constants.java +++ b/app/src/main/java/info/nightscout/androidaps/Constants.java @@ -32,6 +32,8 @@ public class Constants { // Circadian Percentage Profile public static final int CPP_MIN_PERCENTAGE = 50; public static final int CPP_MAX_PERCENTAGE = 200; + public static final int CPP_MIN_TIMESHIFT = -6; + public static final int CPP_MAX_TIMESHIFT = 23; // Very Hard Limits Ranges // First value is the Lowest and second value is the Highest a Limit can define diff --git a/app/src/main/java/info/nightscout/androidaps/MainActivity.java b/app/src/main/java/info/nightscout/androidaps/MainActivity.java index 68df307dbf..291cdd94ac 100644 --- a/app/src/main/java/info/nightscout/androidaps/MainActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/MainActivity.java @@ -58,8 +58,10 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe static final int CASE_STORAGE = 0x1; static final int CASE_SMS = 0x2; + static final int CASE_LOCATION = 0x3; private boolean askForSMS = false; + private boolean askForLocation = true; ImageButton menuButton; @@ -202,6 +204,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe protected void onResume() { super.onResume(); askForSMSPermissions(); + askForLocationPermissions(); } @Override @@ -256,6 +259,17 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe } } + private synchronized void askForLocationPermissions() { + if (askForLocation) { //only when settings were changed an MainActivity resumes. + askForLocation = false; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + askForPermission(new String[]{Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION}, CASE_LOCATION); + } + } + } + private void askForPermission(String[] permission, Integer requestCode) { boolean test = false; for (int i = 0; i < permission.length; i++) { @@ -279,6 +293,7 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe alert.setPositiveButton(R.string.ok, null); alert.show(); break; + case CASE_LOCATION: case CASE_SMS: break; } diff --git a/app/src/main/java/info/nightscout/androidaps/MainApp.java b/app/src/main/java/info/nightscout/androidaps/MainApp.java index 6ff48818c2..4398f80e75 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()); @@ -147,7 +150,7 @@ public class MainApp extends Application { pluginsList.add(SourceGlimpPlugin.getPlugin()); if (Config.SMSCOMMUNICATORENABLED) pluginsList.add(SmsCommunicatorPlugin.getPlugin()); - if (Config.WEAR) pluginsList.add(WearFragment.getPlugin(this)); + pluginsList.add(WearFragment.getPlugin(this)); pluginsList.add(StatuslinePlugin.getPlugin(this)); pluginsList.add(new PersistentNotificationPlugin(this)); pluginsList.add(NSClientInternalPlugin.getPlugin()); @@ -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 80cc0e65d9..d77338d36d 100644 --- a/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/PreferencesActivity.java @@ -21,6 +21,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; @@ -70,6 +71,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()); @@ -130,12 +133,19 @@ 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); - if (danaRPlugin.isEnabled(PluginBase.PUMP) || danaRKoreanPlugin.isEnabled(PluginBase.PUMP)) { + DanaRSPlugin danaRSPlugin = MainApp.getSpecificPlugin(DanaRSPlugin.class); + if (danaRPlugin.isEnabled(PluginBase.PUMP)) { addPreferencesFromResource(R.xml.pref_danar); } + if (danaRKoreanPlugin.isEnabled(PluginBase.PUMP)) { + addPreferencesFromResource(R.xml.pref_danarkorean); + } 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); } @@ -145,7 +155,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); } @@ -160,11 +170,9 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre } addPreferencesFromResource(R.xml.pref_advanced); - if (Config.WEAR) { - WearPlugin wearPlugin = MainApp.getSpecificPlugin(WearPlugin.class); - if (wearPlugin != null && wearPlugin.isEnabled(PluginBase.GENERAL)) { - addPreferencesFromResource(R.xml.pref_wear); - } + WearPlugin wearPlugin = MainApp.getSpecificPlugin(WearPlugin.class); + if (wearPlugin != null && wearPlugin.isEnabled(PluginBase.GENERAL)) { + addPreferencesFromResource(R.xml.pref_wear); } StatuslinePlugin statuslinePlugin = MainApp.getSpecificPlugin(StatuslinePlugin.class); diff --git a/app/src/main/java/info/nightscout/androidaps/data/Profile.java b/app/src/main/java/info/nightscout/androidaps/data/Profile.java index 09885448e2..1ec6f54b71 100644 --- a/app/src/main/java/info/nightscout/androidaps/data/Profile.java +++ b/app/src/main/java/info/nightscout/androidaps/data/Profile.java @@ -22,6 +22,7 @@ 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.utils.DecimalFormatter; +import info.nightscout.utils.SafeParse; import info.nightscout.utils.ToastUtils; public class Profile { @@ -38,10 +39,15 @@ public class Profile { JSONArray basal; private LongSparseArray basal_v = null; // oldest at index 0 JSONArray targetLow; + private LongSparseArray targetLow_v = null; // oldest at index 0 JSONArray targetHigh; + private LongSparseArray targetHigh_v = null; // oldest at index 0 + + int percentage = 100; + int timeshift = 0; public Profile(JSONObject json, String units) { - this(json); + this(json, 100, 0); if (this.units == null) { if (units != null) this.units = units; @@ -52,7 +58,9 @@ public class Profile { } } - public Profile(JSONObject json) { + public Profile(JSONObject json, int percentage, int timeshift) { + this.percentage = percentage; + this.timeshift = timeshift; this.json = json; try { if (json.has("units")) @@ -148,17 +156,25 @@ public class Profile { } private LongSparseArray convertToSparseArray(JSONArray array) { + double multiplier = getMultiplier(array); + LongSparseArray sparse = new LongSparseArray<>(); for (Integer index = 0; index < array.length(); index++) { try { JSONObject o = array.getJSONObject(index); - long tas = o.getLong("timeAsSeconds"); - Double value = o.getDouble("value"); + long tas = getShitfTimeSecs((int) o.getLong("timeAsSeconds")); + Double value = o.getDouble("value") * multiplier; sparse.put(tas, value); } catch (JSONException e) { log.error("Unhandled exception", e); } } + + // check if start is at 0 (midnight) + // and add last value before midnight if not + if (sparse.keyAt(0) != 0) { + sparse.put(0, sparse.valueAt(sparse.size() - 1)); + } return sparse; } @@ -182,7 +198,47 @@ public class Profile { return lastValue; } - private Double getValueToTime(LongSparseArray array, long timeAsSeconds) { + Integer getShitfTimeSecs(Integer originalTime) { + Integer shiftedTime = originalTime + timeshift * 60 * 60; + shiftedTime = (shiftedTime + 24 * 60 * 60) % (24 * 60 * 60); + if (timeshift != 0) + log.debug("(Sec) Original time: " + originalTime + " ShiftedTime: " + shiftedTime); + return shiftedTime; + } + + double getMultiplier(LongSparseArray array) { + double multiplier = 1d; + + if (array == isf_v) + multiplier = 100d / percentage; + else if (array == ic_v) + multiplier = 100d / percentage; + else if (array == basal_v) + multiplier = percentage / 100d; + else + log.error("Unknown array type"); + return multiplier; + } + + double getMultiplier(JSONArray array) { + double multiplier = 1d; + + if (array == isf) + multiplier = 100d / percentage; + else if (array == ic) + multiplier = 100d / percentage; + else if (array == basal) + multiplier = percentage / 100d; + else if (array == targetLow) + multiplier = 1d; + else if (array == targetHigh) + multiplier = 1d; + else + log.error("Unknown array type"); + return multiplier; + } + + private Double getValueToTime(LongSparseArray array, Integer timeAsSeconds) { Double lastValue = null; for (Integer index = 0; index < array.size(); index++) { @@ -197,26 +253,29 @@ public class Profile { return lastValue; } - private String getValuesList(JSONArray array, JSONArray array2, DecimalFormat format, String units) { + private String format_HH_MM(Integer timeAsSeconds) { + String time; + int hour = timeAsSeconds / 60 / 60; + int minutes = timeAsSeconds - hour * 60 * 60; + DecimalFormat df = new DecimalFormat("00"); + time = df.format(hour) + ":" + df.format(minutes); + return time; + } + + private String getValuesList(LongSparseArray array, LongSparseArray array2, DecimalFormat format, String units) { String retValue = ""; - for (Integer index = 0; index < array.length(); index++) { - try { - JSONObject o = array.getJSONObject(index); - retValue += o.getString("time"); - retValue += " "; - retValue += format.format(o.getDouble("value")); - if (array2 != null) { - JSONObject o2 = array2.getJSONObject(index); - retValue += " - "; - retValue += format.format(o2.getDouble("value")); - } - retValue += " " + units; - if (index + 1 < array.length()) - retValue += "\n"; - } catch (JSONException e) { - log.error("Unhandled exception", e); + for (Integer index = 0; index < array.size(); index++) { + retValue += format_HH_MM((int) array.keyAt(index)); + retValue += " "; + retValue += format.format(array.valueAt(index)); + if (array2 != null) { + retValue += " - "; + retValue += format.format(array2.valueAt(index)); } + retValue += " " + units; + if (index + 1 < array.size()) + retValue += "\n"; } return retValue; } @@ -236,7 +295,7 @@ public class Profile { } public String getIsfList() { - return getValuesList(isf, null, new DecimalFormat("0.0"), getUnits() + "/U"); + return getValuesList(isf_v, null, new DecimalFormat("0.0"), getUnits() + "/U"); } public Double getIc() { @@ -254,7 +313,7 @@ public class Profile { } public String getIcList() { - return getValuesList(ic, null, new DecimalFormat("0.0"), " g/U"); + return getValuesList(ic_v, null, new DecimalFormat("0.0"), " g/U"); } public Double getBasal() { @@ -272,7 +331,7 @@ public class Profile { } public String getBasalList() { - return getValuesList(basal, null, new DecimalFormat("0.00"), "U"); + return getValuesList(basal_v, null, new DecimalFormat("0.00"), "U"); } public class BasalValue { @@ -286,20 +345,14 @@ public class Profile { } public BasalValue[] getBasalValues() { - try { - BasalValue[] ret = new BasalValue[basal.length()]; + BasalValue[] ret = new BasalValue[basal_v.size()]; - for (Integer index = 0; index < basal.length(); index++) { - JSONObject o = basal.getJSONObject(index); - Integer tas = o.getInt("timeAsSeconds"); - Double value = o.getDouble("value"); - ret[index] = new BasalValue(tas, value); - } - return ret; - } catch (JSONException e) { - log.error("Unhandled exception", e); + for (Integer index = 0; index < basal_v.size(); index++) { + Integer tas = (int) basal_v.keyAt(index); + Double value = basal_v.valueAt(index); + ret[index] = new BasalValue(tas, value); } - return new BasalValue[0]; + return ret; } public Double getTargetLow() { @@ -311,7 +364,9 @@ public class Profile { } public Double getTargetLow(Integer timeAsSeconds) { - return getValueToTime(targetLow, timeAsSeconds); + if (targetLow_v == null) + targetLow_v = convertToSparseArray(targetLow); + return getValueToTime(targetLow_v, timeAsSeconds); } public Double getTargetHigh() { @@ -323,11 +378,13 @@ public class Profile { } public Double getTargetHigh(Integer timeAsSeconds) { - return getValueToTime(targetHigh, timeAsSeconds); + if (targetHigh_v == null) + targetHigh_v = convertToSparseArray(targetHigh); + return getValueToTime(targetHigh_v, timeAsSeconds); } public String getTargetList() { - return getValuesList(targetLow, targetHigh, new DecimalFormat("0.0"), getUnits()); + return getValuesList(targetLow_v, targetHigh_v, new DecimalFormat("0.0"), getUnits()); } public double getMaxDailyBasal() { @@ -350,18 +407,6 @@ public class Profile { return (int) (passed / 1000); } - public static Integer secondsFromMidnight(Date date) { - Calendar c = Calendar.getInstance(); - long now = date.getTime(); - c.setTime(date); - c.set(Calendar.HOUR_OF_DAY, 0); - c.set(Calendar.MINUTE, 0); - c.set(Calendar.SECOND, 0); - c.set(Calendar.MILLISECOND, 0); - long passed = now - c.getTimeInMillis(); - return (int) (passed / 1000); - } - public static Integer secondsFromMidnight(long date) { Calendar c = Calendar.getInstance(); c.setTimeInMillis(date); @@ -410,4 +455,29 @@ public class Profile { return toUnitsString(lowMgdl, lowMmol, units) + " - " + toUnitsString(highMgdl, highMmol, units); } + + public double percentageBasalSum() { + double result = 0d; + for (int i = 0; i < 24; i++) { + result += getBasal((Integer) (i * 60 * 60)); + } + return result; + } + + + public double baseBasalSum() { + double result = 0d; + for (int i = 0; i < 24; i++) { + result += getBasal((Integer) (i * 60 * 60)) / getMultiplier(basal_v); + } + return result; + } + + public int getPercentage() { + return percentage; + } + + public int getTimeshift() { + return timeshift; + } } diff --git a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java index 3a09cb2da4..2767f7611a 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java +++ b/app/src/main/java/info/nightscout/androidaps/db/DatabaseHelper.java @@ -1541,9 +1541,10 @@ public class DatabaseHelper extends OrmLiteSqliteOpenHelper { old = getDaoProfileSwitch().queryForId(profileSwitch.date); if (old != null) { if (!old.isEqual(profileSwitch)) { + profileSwitch.source = old.source; + profileSwitch.profileName = old.profileName; // preserver profileName to prevent multiple CPP extension getDaoProfileSwitch().delete(old); // need to delete/create because date may change too - old.copyFrom(profileSwitch); - getDaoProfileSwitch().create(old); + getDaoProfileSwitch().create(profileSwitch); log.debug("PROFILESWITCH: Updating record by date from: " + Source.getString(profileSwitch.source) + " " + old.toString()); scheduleProfileSwitchChange(); return true; diff --git a/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java b/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java index cd5efc7465..8bcd192d59 100644 --- a/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java +++ b/app/src/main/java/info/nightscout/androidaps/db/ProfileSwitch.java @@ -10,14 +10,15 @@ import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Date; import java.util.Objects; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.interfaces.Interval; import info.nightscout.androidaps.plugins.Overview.graphExtensions.DataPointWithLabelInterface; import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; +import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin; import info.nightscout.utils.DateUtil; +import info.nightscout.utils.DecimalFormatter; @DatabaseTable(tableName = DatabaseHelper.DATABASE_PROFILESWITCHES) public class ProfileSwitch implements Interval, DataPointWithLabelInterface { @@ -58,13 +59,24 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface { public Profile getProfileObject() { if (profile == null) try { - profile = new Profile(new JSONObject(profileJson)); + profile = new Profile(new JSONObject(profileJson), percentage, timeshift); } catch (JSONException e) { log.error("Unhandled exception", e); } return profile; } + public String getCustomizedName() { + String name = profileName; + if(LocalProfilePlugin.LOCAL_PROFILE.equals(name)){ + name = DecimalFormatter.to2Decimal(getProfileObject().percentageBasalSum()) + "U "; + } + if (isCPP) { + name += "(" + percentage + "%," + timeshift + "h)"; + } + return name; + } + public boolean isEqual(ProfileSwitch other) { if (date != other.date) { return false; @@ -179,7 +191,7 @@ public class ProfileSwitch implements Interval, DataPointWithLabelInterface { @Override public String getLabel() { - return profileName; + return getCustomizedName(); } @Override diff --git a/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java b/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java index ab697e4840..3cfe7cc6a7 100644 --- a/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java +++ b/app/src/main/java/info/nightscout/androidaps/events/EventPumpStatusChanged.java @@ -18,14 +18,24 @@ public class EventPumpStatusChanged { public int sSecondsElapsed = 0; public String sPerfomingAction = ""; + public static String error = ""; + public EventPumpStatusChanged(int status) { sStatus = status; sSecondsElapsed = 0; + error = ""; } public EventPumpStatusChanged(int status, int secondsElapsed) { sStatus = status; sSecondsElapsed = secondsElapsed; + error = ""; + } + + public EventPumpStatusChanged(int status, String error) { + sStatus = status; + sSecondsElapsed = 0; + this.error = error; } public EventPumpStatusChanged(String action) { diff --git a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java index 2db7564de7..9da9cb0dd0 100644 --- a/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java +++ b/app/src/main/java/info/nightscout/androidaps/interfaces/PumpInterface.java @@ -31,7 +31,7 @@ public interface PumpInterface { PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo); void stopBolusDelivering(); - PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force); + PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew); PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes); PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes); //some pumps might set a very short temp close to 100% as cancelling a temp can be noisy diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java index ade5e074ba..fdb1953531 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/ActionsFragment.java @@ -194,14 +194,14 @@ public class ActionsFragment extends SubscriberFragment implements View.OnClickL switch (view.getId()) { case R.id.actions_profileswitch: NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); - final OptionsToShow profileswitch = CareportalFragment.profileswitch; + final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCH; profileswitch.executeProfileSwitch = true; newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); newDialog.show(manager, "NewNSTreatmentDialog"); break; case R.id.actions_temptarget: NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog(); - final OptionsToShow temptarget = CareportalFragment.temptarget; + final OptionsToShow temptarget = CareportalFragment.TEMPTARGET; temptarget.executeTempTarget = true; newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget); newTTDialog.show(manager, "NewNSTreatmentDialog"); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java index f6e043d3b6..f6c9d4c3d6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/FillDialog.java @@ -2,11 +2,9 @@ package info.nightscout.androidaps.plugins.Actions.dialogs; import android.content.Context; import android.content.DialogInterface; -import android.content.SharedPreferences; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; -import android.preference.PreferenceManager; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; import android.view.LayoutInflater; @@ -16,7 +14,6 @@ import android.view.ViewGroup; import android.view.Window; import android.view.WindowManager; import android.widget.Button; -import android.widget.TextView; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; @@ -32,12 +29,11 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.Source; -import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; import info.nightscout.androidaps.plugins.Overview.Notification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.utils.DecimalFormatter; -import info.nightscout.utils.PlusMinusEditText; +import info.nightscout.utils.NumberPicker; import info.nightscout.utils.SP; import info.nightscout.utils.SafeParse; @@ -45,13 +41,12 @@ public class FillDialog extends DialogFragment implements OnClickListener { private static Logger log = LoggerFactory.getLogger(FillDialog.class); Button deliverButton; - TextView insulin; double amount1 = 0d; double amount2 = 0d; double amount3 = 0d; - PlusMinusEditText editInsulin; + NumberPicker editInsulin; Handler mHandler; public static HandlerThread mHandlerThread; @@ -73,10 +68,10 @@ public class FillDialog extends DialogFragment implements OnClickListener { getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - insulin = (TextView) view.findViewById(R.id.treatments_newtreatment_insulinamount); Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); double bolusstep = MainApp.getConfigBuilder().getPumpDescription().bolusStep; - editInsulin = new PlusMinusEditText(view, R.id.treatments_newtreatment_insulinamount, R.id.treatments_newtreatment_insulinamount_plus, R.id.treatments_newtreatment_insulinamount_minus, 0d, 0d, maxInsulin, bolusstep, new DecimalFormat("0.00"), false); + editInsulin = (NumberPicker) view.findViewById(R.id.treatments_newtreatment_insulinamount); + editInsulin.setParams(0d, 0d, maxInsulin, bolusstep, new DecimalFormat("0.00"), false); //setup preset buttons Button button1 = (Button) view.findViewById(R.id.fill_preset_button1); @@ -88,21 +83,21 @@ public class FillDialog extends DialogFragment implements OnClickListener { amount2 = SP.getDouble("fill_button2", 0d); amount3 = SP.getDouble("fill_button3", 0d); - if(amount1 >0) { + if (amount1 > 0) { button1.setVisibility(View.VISIBLE); button1.setText(DecimalFormatter.to2Decimal(amount1) + "U"); button1.setOnClickListener(this); } else { button1.setVisibility(View.GONE); } - if(amount2 >0) { + if (amount2 > 0) { button2.setVisibility(View.VISIBLE); button2.setText(DecimalFormatter.to2Decimal(amount2) + "U"); button2.setOnClickListener(this); } else { button2.setVisibility(View.GONE); } - if(amount3 >0) { + if (amount3 > 0) { button3.setVisibility(View.VISIBLE); button3.setText(DecimalFormatter.to2Decimal(amount3) + "U"); button3.setOnClickListener(this); @@ -110,7 +105,7 @@ public class FillDialog extends DialogFragment implements OnClickListener { button3.setVisibility(View.GONE); } - if (button1.getVisibility() == View.GONE && button2.getVisibility() == View.GONE && button3.getVisibility() == View.GONE ) { + if (button1.getVisibility() == View.GONE && button2.getVisibility() == View.GONE && button3.getVisibility() == View.GONE) { divider.setVisibility(View.GONE); } return view; @@ -127,7 +122,7 @@ public class FillDialog extends DialogFragment implements OnClickListener { public void onClick(View view) { switch (view.getId()) { case R.id.treatments_newtreatment_deliverbutton: - Double insulin = SafeParse.stringToDouble(this.insulin.getText().toString()); + Double insulin = SafeParse.stringToDouble(editInsulin.getText().toString()); confirmAndDeliver(insulin); break; case R.id.fill_preset_button1: diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java index be635e76b6..0b7445e9e7 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewExtendedBolusDialog.java @@ -11,9 +11,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import android.widget.Button; -import android.widget.EditText; -import android.widget.RadioButton; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; @@ -30,14 +27,14 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Overview.Notification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; -import info.nightscout.utils.PlusMinusEditText; +import info.nightscout.utils.NumberPicker; import info.nightscout.utils.SafeParse; public class NewExtendedBolusDialog extends DialogFragment implements View.OnClickListener { private static Logger log = LoggerFactory.getLogger(NewExtendedBolusDialog.class); - PlusMinusEditText editInsulin; - PlusMinusEditText editDuration; + NumberPicker editInsulin; + NumberPicker editDuration; Handler mHandler; public static HandlerThread mHandlerThread; @@ -56,11 +53,13 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli View view = inflater.inflate(R.layout.overview_newextendedbolus_dialog, container, false); Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); - editInsulin = new PlusMinusEditText(view, R.id.overview_newextendedbolus_insulin, R.id.overview_newextendedbolus_insulin_plus, R.id.overview_newextendedbolus_insulin_minus, 0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false); + editInsulin = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_insulin); + editInsulin.setParams(0d, 0d, maxInsulin, 0.1d, new DecimalFormat("0.00"), false); double extendedDurationStep = MainApp.getConfigBuilder().getPumpDescription().extendedBolusDurationStep; double extendedMaxDuration = MainApp.getConfigBuilder().getPumpDescription().extendedBolusMaxDuration; - editDuration = new PlusMinusEditText(view, R.id.overview_newextendedbolus_duration, R.id.overview_newextendedbolus_duration_plus, R.id.overview_newextendedbolus_duration_minus, extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false); + editDuration = (NumberPicker) view.findViewById(R.id.overview_newextendedbolus_duration); + editDuration.setParams(extendedDurationStep, extendedDurationStep, extendedMaxDuration, extendedDurationStep, new DecimalFormat("0"), false); view.findViewById(R.id.ok).setOnClickListener(this); view.findViewById(R.id.cancel).setOnClickListener(this); @@ -107,11 +106,11 @@ public class NewExtendedBolusDialog extends DialogFragment implements View.OnCli PumpEnactResult result = pump.setExtendedBolus(finalInsulin, finalDurationInMinutes); if (!result.success) { try { - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(context.getString(R.string.treatmentdeliveryerror)); - builder.setMessage(result.comment); - builder.setPositiveButton(context.getString(R.string.ok), null); - builder.show(); + AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(context.getString(R.string.treatmentdeliveryerror)); + builder.setMessage(result.comment); + builder.setPositiveButton(context.getString(R.string.ok), null); + builder.show(); } catch (WindowManager.BadTokenException | NullPointerException e) { // window has been destroyed Notification notification = new Notification(Notification.BOLUS_DELIVERY_ERROR, MainApp.sResources.getString(R.string.treatmentdeliveryerror), Notification.URGENT); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java index 9bd6cd26c9..68652b0a8b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Actions/dialogs/NewTempBasalDialog.java @@ -14,7 +14,6 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import android.widget.RadioButton; import android.widget.RadioGroup; -import android.widget.RelativeLayout; import com.crashlytics.android.answers.Answers; import com.crashlytics.android.answers.CustomEvent; @@ -26,12 +25,11 @@ import java.text.DecimalFormat; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpInterface; -import info.nightscout.androidaps.data.Profile; import info.nightscout.utils.NumberPicker; -import info.nightscout.utils.PlusMinusEditText; import info.nightscout.utils.SafeParse; public class NewTempBasalDialog extends DialogFragment implements View.OnClickListener, RadioGroup.OnCheckedChangeListener { @@ -74,7 +72,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi PumpDescription pumpDescription = MainApp.getConfigBuilder().getPumpDescription(); - basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput); + basalPercent = (NumberPicker) view.findViewById(R.id.overview_newtempbasal_basalpercentinput); double maxTempPercent = pumpDescription.maxTempPercent; double tempPercentStep = pumpDescription.tempPercentStep; basalPercent.setParams(100d, 0d, maxTempPercent, tempPercentStep, new DecimalFormat("0"), true); @@ -159,7 +157,7 @@ public class NewTempBasalDialog extends DialogFragment implements View.OnClickLi if (setAsPercent) { result = pump.setTempBasalPercent(finalBasalPercent, finalDurationInMinutes); } else { - result = pump.setTempBasalAbsolute(finalBasal, finalDurationInMinutes, false); + result = pump.setTempBasalAbsolute(finalBasal, finalDurationInMinutes, true); } if (!result.success) { if (context instanceof Activity) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java index 6550959867..d832d2aab0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/CareportalFragment.java @@ -3,9 +3,7 @@ package info.nightscout.androidaps.plugins.Careportal; import android.app.Activity; import android.os.Bundle; -import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; -import android.text.Layout; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -18,7 +16,6 @@ import com.squareup.otto.Subscribe; import info.nightscout.androidaps.BuildConfig; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; -import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.db.CareportalEvent; import info.nightscout.androidaps.events.EventCareportalEventChange; @@ -47,27 +44,28 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli return careportalPlugin; } - // bg,insulin,carbs,prebolus,duration,percent,absolute,profile,split,temptarget - public static final OptionsToShow bgcheck = new OptionsToShow(R.id.careportal_bgcheck, R.string.careportal_bgcheck, true, true, true, false, false, false, false, false, false, false); - public static final OptionsToShow snackbolus = new OptionsToShow(R.id.careportal_snackbolus, R.string.careportal_snackbolus, true, true, true, true, false, false, false, false, false, false); - public static final OptionsToShow mealbolus = new OptionsToShow(R.id.careportal_mealbolus, R.string.careportal_mealbolus, true, true, true, true, false, false, false, false, false, false); - public static final OptionsToShow correctionbolus = new OptionsToShow(R.id.careportal_correctionbolus, R.string.careportal_correctionbolus, true, true, true, true, false, false, false, false, false, false); - public static final OptionsToShow carbcorrection = new OptionsToShow(R.id.careportal_carbscorrection, R.string.careportal_carbscorrection, true, false, true, false, false, false, false, false, false, false); - public static final OptionsToShow combobolus = new OptionsToShow(R.id.careportal_combobolus, R.string.careportal_combobolus, true, true, true, true, true, false, false, false, true, false); - public static final OptionsToShow announcement = new OptionsToShow(R.id.careportal_announcement, R.string.careportal_announcement, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow note = new OptionsToShow(R.id.careportal_note, R.string.careportal_note, true, false, false, false, true, false, false, false, false, false); - public static final OptionsToShow question = new OptionsToShow(R.id.careportal_question, R.string.careportal_question, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow exercise = new OptionsToShow(R.id.careportal_exercise, R.string.careportal_exercise, false, false, false, false, true, false, false, false, false, false); - public static final OptionsToShow sitechange = new OptionsToShow(R.id.careportal_pumpsitechange, R.string.careportal_pumpsitechange, true, true, false, false, false, false, false, false, false, false); - public static final OptionsToShow sensorstart = new OptionsToShow(R.id.careportal_cgmsensorstart, R.string.careportal_cgmsensorstart, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow sensorchange = new OptionsToShow(R.id.careportal_cgmsensorinsert, R.string.careportal_cgmsensorinsert, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow insulinchange = new OptionsToShow(R.id.careportal_insulincartridgechange, R.string.careportal_insulincartridgechange, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow pumpbatterychange = new OptionsToShow(R.id.careportal_pumpbatterychange, R.string.careportal_pumpbatterychange, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow tempbasalstart = new OptionsToShow(R.id.careportal_tempbasalstart, R.string.careportal_tempbasalstart, true, false, false, false, true, true, true, false, false, false); - public static final OptionsToShow tempbasalend = new OptionsToShow(R.id.careportal_tempbasalend, R.string.careportal_tempbasalend, true, false, false, false, false, false, false, false, false, false); - public static final OptionsToShow profileswitch = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch, true, false, false, false, true, false, false, true, false, false); - public static final OptionsToShow openapsoffline = new OptionsToShow(R.id.careportal_openapsoffline, R.string.careportal_openapsoffline, false, false, false, false, true, false, false, false, false, false); - public static final OptionsToShow temptarget = new OptionsToShow(R.id.careportal_temporarytarget, R.string.careportal_temporarytarget, false, false, false, false, true, false, false, false, false, true); + // date,bg,insulin,carbs,prebolus,duration,percent,absolute,profile,split,temptarget + public static final OptionsToShow BGCHECK = new OptionsToShow(R.id.careportal_bgcheck, R.string.careportal_bgcheck).date().bg(); + public static final OptionsToShow SNACKBOLUS = new OptionsToShow(R.id.careportal_snackbolus, R.string.careportal_snackbolus).date().bg().insulin().carbs().prebolus(); + public static final OptionsToShow MEALBOLUS = new OptionsToShow(R.id.careportal_mealbolus, R.string.careportal_mealbolus).date().bg().insulin().carbs().prebolus(); + public static final OptionsToShow CORRECTIONBOLUS = new OptionsToShow(R.id.careportal_correctionbolus, R.string.careportal_correctionbolus).date().bg().insulin().carbs().prebolus(); + public static final OptionsToShow CARBCORRECTION = new OptionsToShow(R.id.careportal_carbscorrection, R.string.careportal_carbscorrection).date().bg().carbs(); + public static final OptionsToShow COMBOBOLUS = new OptionsToShow(R.id.careportal_combobolus, R.string.careportal_combobolus).date().bg().insulin().carbs().prebolus().duration().split(); + public static final OptionsToShow ANNOUNCEMENT = new OptionsToShow(R.id.careportal_announcement, R.string.careportal_announcement).date().bg(); + public static final OptionsToShow NOTE = new OptionsToShow(R.id.careportal_note, R.string.careportal_note).date().bg().duration(); + public static final OptionsToShow QUESTION = new OptionsToShow(R.id.careportal_question, R.string.careportal_question).date().bg(); + public static final OptionsToShow EXERCISE = new OptionsToShow(R.id.careportal_exercise, R.string.careportal_exercise).date().duration(); + public static final OptionsToShow SITECHANGE = new OptionsToShow(R.id.careportal_pumpsitechange, R.string.careportal_pumpsitechange).date().bg(); + public static final OptionsToShow SENSORSTART = new OptionsToShow(R.id.careportal_cgmsensorstart, R.string.careportal_cgmsensorstart).date().bg(); + public static final OptionsToShow SENSORCHANGE = new OptionsToShow(R.id.careportal_cgmsensorinsert, R.string.careportal_cgmsensorinsert).date().bg(); + public static final OptionsToShow INSULINCHANGE = new OptionsToShow(R.id.careportal_insulincartridgechange, R.string.careportal_insulincartridgechange).date().bg(); + public static final OptionsToShow PUMPBATTERYCHANGE = new OptionsToShow(R.id.careportal_pumpbatterychange, R.string.careportal_pumpbatterychange).date().bg(); + public static final OptionsToShow TEMPBASALSTART = new OptionsToShow(R.id.careportal_tempbasalstart, R.string.careportal_tempbasalstart).date().bg().duration().percent().absolute(); + public static final OptionsToShow TEMPBASALEND = new OptionsToShow(R.id.careportal_tempbasalend, R.string.careportal_tempbasalend).date().bg(); + public static final OptionsToShow PROFILESWITCH = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch).date().duration().profile(); + public static final OptionsToShow PROFILESWITCHDIRECT = new OptionsToShow(R.id.careportal_profileswitch, R.string.careportal_profileswitch).duration().profile(); + public static final OptionsToShow OPENAPSOFFLINE = new OptionsToShow(R.id.careportal_openapsoffline, R.string.careportal_openapsoffline).date().duration(); + public static final OptionsToShow TEMPTARGET = new OptionsToShow(R.id.careportal_temporarytarget, R.string.careportal_temporarytarget).date().duration().tempTarget(); @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -136,66 +134,66 @@ public class CareportalFragment extends SubscriberFragment implements View.OnCli NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); switch (id) { case R.id.careportal_bgcheck: - newDialog.setOptions(bgcheck, R.string.careportal_bgcheck); + newDialog.setOptions(BGCHECK, R.string.careportal_bgcheck); break; case R.id.careportal_announcement: - newDialog.setOptions(announcement, R.string.careportal_announcement); + newDialog.setOptions(ANNOUNCEMENT, R.string.careportal_announcement); break; case R.id.careportal_cgmsensorinsert: - newDialog.setOptions(sensorchange, R.string.careportal_cgmsensorinsert); + newDialog.setOptions(SENSORCHANGE, R.string.careportal_cgmsensorinsert); break; case R.id.careportal_cgmsensorstart: - newDialog.setOptions(sensorstart, R.string.careportal_cgmsensorstart); + newDialog.setOptions(SENSORSTART, R.string.careportal_cgmsensorstart); break; case R.id.careportal_combobolus: - newDialog.setOptions(combobolus, R.string.careportal_combobolus); + newDialog.setOptions(COMBOBOLUS, R.string.careportal_combobolus); break; case R.id.careportal_correctionbolus: - newDialog.setOptions(correctionbolus, R.string.careportal_correctionbolus); + newDialog.setOptions(CORRECTIONBOLUS, R.string.careportal_correctionbolus); break; case R.id.careportal_carbscorrection: - newDialog.setOptions(carbcorrection, R.string.careportal_carbscorrection); + newDialog.setOptions(CARBCORRECTION, R.string.careportal_carbscorrection); break; case R.id.careportal_exercise: - newDialog.setOptions(exercise, R.string.careportal_exercise); + newDialog.setOptions(EXERCISE, R.string.careportal_exercise); break; case R.id.careportal_insulincartridgechange: - newDialog.setOptions(insulinchange, R.string.careportal_insulincartridgechange); + newDialog.setOptions(INSULINCHANGE, R.string.careportal_insulincartridgechange); break; case R.id.careportal_pumpbatterychange: - newDialog.setOptions(pumpbatterychange, R.string.careportal_pumpbatterychange); + newDialog.setOptions(PUMPBATTERYCHANGE, R.string.careportal_pumpbatterychange); break; case R.id.careportal_mealbolus: - newDialog.setOptions(mealbolus, R.string.careportal_mealbolus); + newDialog.setOptions(MEALBOLUS, R.string.careportal_mealbolus); break; case R.id.careportal_note: - newDialog.setOptions(note, R.string.careportal_note); + newDialog.setOptions(NOTE, R.string.careportal_note); break; case R.id.careportal_profileswitch: - profileswitch.executeProfileSwitch = false; - newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); + PROFILESWITCH.executeProfileSwitch = false; + newDialog.setOptions(PROFILESWITCH, R.string.careportal_profileswitch); break; case R.id.careportal_pumpsitechange: - newDialog.setOptions(sitechange, R.string.careportal_pumpsitechange); + newDialog.setOptions(SITECHANGE, R.string.careportal_pumpsitechange); break; case R.id.careportal_question: - newDialog.setOptions(question, R.string.careportal_question); + newDialog.setOptions(QUESTION, R.string.careportal_question); break; case R.id.careportal_snackbolus: - newDialog.setOptions(snackbolus, R.string.careportal_snackbolus); + newDialog.setOptions(SNACKBOLUS, R.string.careportal_snackbolus); break; case R.id.careportal_tempbasalstart: - newDialog.setOptions(tempbasalstart, R.string.careportal_tempbasalstart); + newDialog.setOptions(TEMPBASALSTART, R.string.careportal_tempbasalstart); break; case R.id.careportal_tempbasalend: - newDialog.setOptions(tempbasalend, R.string.careportal_tempbasalend); + newDialog.setOptions(TEMPBASALEND, R.string.careportal_tempbasalend); break; case R.id.careportal_openapsoffline: - newDialog.setOptions(openapsoffline, R.string.careportal_openapsoffline); + newDialog.setOptions(OPENAPSOFFLINE, R.string.careportal_openapsoffline); break; case R.id.careportal_temporarytarget: - temptarget.executeTempTarget = false; - newDialog.setOptions(temptarget, R.string.careportal_temporarytarget); + TEMPTARGET.executeTempTarget = false; + newDialog.setOptions(TEMPTARGET, R.string.careportal_temporarytarget); break; default: newDialog = null; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java index ec5a267dcc..1b976195ae 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/Dialogs/NewNSTreatmentDialog.java @@ -16,6 +16,7 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Button; import android.widget.CompoundButton; import android.widget.EditText; import android.widget.LinearLayout; @@ -53,7 +54,6 @@ import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfilePlugin; import info.nightscout.utils.DateUtil; import info.nightscout.utils.NSUpload; import info.nightscout.utils.NumberPicker; @@ -74,17 +74,11 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick String units; TextView eventTypeText; - LinearLayout layoutBg; - LinearLayout layoutBgSource; - LinearLayout layoutInsulin; - LinearLayout layoutCarbs; - LinearLayout layoutSplit; - LinearLayout layoutDuration; LinearLayout layoutPercent; LinearLayout layoutAbsolute; - LinearLayout layoutCarbTime; - LinearLayout layoutProfile; - LinearLayout layoutTempTarget; + LinearLayout layoutReuse; + + TextView dateButton; TextView timeButton; @@ -95,6 +89,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick EditText notesEdit; Spinner profileSpinner; Spinner reasonSpinner; + Button reuseButton; NumberPicker editBg; NumberPicker editCarbs; @@ -105,6 +100,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick NumberPicker editAbsolute; NumberPicker editCarbTime; NumberPicker editTemptarget; + NumberPicker editPercentage; + NumberPicker editTimeshift; Date eventTime; @@ -145,17 +142,10 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick setStyle(DialogFragment.STYLE_NORMAL, getTheme()); View view = inflater.inflate(R.layout.careportal_newnstreatment_dialog, container, false); - layoutBg = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_bg_layout); - layoutBgSource = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_bgsource_layout); - layoutInsulin = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_insulin_layout); - layoutCarbs = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_carbs_layout); - layoutSplit = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_split_layout); - layoutDuration = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_duration_layout); layoutPercent = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_percent_layout); layoutAbsolute = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_absolute_layout); - layoutCarbTime = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_carbtime_layout); - layoutProfile = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_profile_layout); - layoutTempTarget = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_temptarget_layout); + + layoutReuse = (LinearLayout) view.findViewById(R.id.careportal_newnstreatment_reuse_layout); eventTypeText = (TextView) view.findViewById(R.id.careportal_newnstreatment_eventtype); eventTypeText.setText(event); @@ -165,6 +155,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick otherRadioButton = (RadioButton) view.findViewById(R.id.careportal_newnstreatment_other); profileSpinner = (Spinner) view.findViewById(R.id.careportal_newnstreatment_profile); + reuseButton = (Button) view.findViewById(R.id.careportal_newnstreatment_reusebutton); + notesEdit = (EditText) view.findViewById(R.id.careportal_newnstreatment_notes); reasonSpinner = (Spinner) view.findViewById(R.id.careportal_newnstreatment_temptarget_reason); @@ -244,19 +236,8 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick // bg bgUnitsView.setText(units); - editBg = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_bginput); - editTemptarget = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_temptarget); - if (profile == null) { - editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false); - editTemptarget.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false); - } else if (profile.getUnits().equals(Constants.MMOL)) { - editBg.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false); - editTemptarget.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false); - } else { - editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false); - editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false); - } - editBg.addTextChangedListener(new TextWatcher() { + TextWatcher bgTextWatcher = new TextWatcher() { + public void afterTextChanged(Editable s) { } @@ -266,8 +247,20 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick public void onTextChanged(CharSequence s, int start, int before, int count) { if (sensorRadioButton.isChecked()) meterRadioButton.setChecked(true); } - }); + }; + editBg = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_bginput); + editTemptarget = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_temptarget); + if (profile == null) { + editBg.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher); + editTemptarget.setParams(bg, 0d, 500d, 0.1d, new DecimalFormat("0.0"), false); + } else if (profile.getUnits().equals(Constants.MMOL)) { + editBg.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false, bgTextWatcher); + editTemptarget.setParams(bg, 0d, 30d, 0.1d, new DecimalFormat("0.0"), false); + } else { + editBg.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false, bgTextWatcher); + editTemptarget.setParams(bg, 0d, 500d, 1d, new DecimalFormat("0"), false); + } sensorRadioButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { @@ -289,10 +282,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick editDuration = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_durationinput); editDuration.setParams(0d, 0d, 24 * 60d, 10d, new DecimalFormat("0"), false); - Integer maxPercent = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalPercentOnlyForCheckLimit); - editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput); - editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true); - editPercent.addTextChangedListener(new TextWatcher() { + TextWatcher percentTextWatcher = new TextWatcher() { @Override public void afterTextChanged(Editable s) { } @@ -308,12 +298,13 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick layoutPercent.setVisibility(View.VISIBLE); layoutAbsolute.setVisibility(View.GONE); } - }); + }; - Double maxAbsolute = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit); - editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput); - editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true); - editAbsolute.addTextChangedListener(new TextWatcher() { + Integer maxPercent = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalPercentOnlyForCheckLimit); + editPercent = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentinput); + editPercent.setParams(0d, 0d, (double) maxPercent, 5d, new DecimalFormat("0"), true, percentTextWatcher); + + TextWatcher absoluteTextWatcher = new TextWatcher() { @Override public void afterTextChanged(Editable s) { } @@ -329,23 +320,50 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick layoutPercent.setVisibility(View.GONE); layoutAbsolute.setVisibility(View.VISIBLE); } - }); + }; + + Double maxAbsolute = MainApp.getConfigBuilder().applyBasalConstraints(Constants.basalAbsoluteOnlyForCheckLimit); + editAbsolute = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_absoluteinput); + editAbsolute.setParams(0d, 0d, maxAbsolute, 0.05d, new DecimalFormat("0.00"), true, absoluteTextWatcher); editCarbTime = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_carbtimeinput); editCarbTime.setParams(0d, -60d, 60d, 5d, new DecimalFormat("0"), false); + editPercentage = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_percentage); + editPercentage.setParams(100d, (double) Constants.CPP_MIN_PERCENTAGE, (double) Constants.CPP_MAX_PERCENTAGE, 1d, new DecimalFormat("0"), false); - showOrHide(layoutBg, options.bg); - showOrHide(layoutBgSource, options.bg); - showOrHide(layoutInsulin, options.insulin); - showOrHide(layoutCarbs, options.carbs); - showOrHide(layoutSplit, options.split); - showOrHide(layoutDuration, options.duration); + editTimeshift = (NumberPicker) view.findViewById(R.id.careportal_newnstreatment_timeshift); + editTimeshift.setParams(0d, (double) Constants.CPP_MIN_TIMESHIFT, (double) Constants.CPP_MAX_TIMESHIFT, 1d, new DecimalFormat("0"), false); + + ProfileSwitch ps = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); + if(ps!=null && ps.isCPP){ + final int percentage = ps.percentage; + final int timeshift = ps.timeshift; + reuseButton.setText(reuseButton.getText() + " " + percentage + "% " + timeshift +"h"); + reuseButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + editPercentage.setValue((double)percentage); + editTimeshift.setValue((double)timeshift); + } + }); + } + + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_eventtime_layout), options.date); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_bg_layout), options.bg); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_bgsource_layout), options.bg); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_insulin_layout), options.insulin); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_carbs_layout), options.carbs); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_split_layout), options.split); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_duration_layout), options.duration); showOrHide(layoutPercent, options.percent); showOrHide(layoutAbsolute, options.absolute); - showOrHide(layoutCarbTime, options.prebolus); - showOrHide(layoutProfile, options.profile); - showOrHide(layoutTempTarget, options.tempTarget); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_carbtime_layout), options.prebolus); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_profile_layout), options.profile); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_percentage_layout), options.profile); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_timeshift_layout), options.profile); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_reuse_layout), options.profile && ps!=null && ps.isCPP); + showOrHide((ViewGroup) view.findViewById(R.id.careportal_newnstreatment_temptarget_layout), options.tempTarget); return view; } @@ -488,7 +506,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick allowZeroDuration = true; break; } - if (SafeParse.stringToDouble(editBg.getText()) != 0d) { + if (options.bg && SafeParse.stringToDouble(editBg.getText()) != 0d) { data.put("glucose", SafeParse.stringToDouble(editBg.getText())); if (meterRadioButton.isChecked()) data.put("glucoseType", "Finger"); if (sensorRadioButton.isChecked()) data.put("glucoseType", "Sensor"); @@ -506,6 +524,10 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick data.put("absolute", SafeParse.stringToDouble(editAbsolute.getText())); if (options.profile && profileSpinner.getSelectedItem() != null) data.put("profile", profileSpinner.getSelectedItem().toString()); + if (options.profile) + data.put("percentage", SafeParse.stringToInt(editPercentage.getText())); + if (options.profile) + data.put("timeshift", SafeParse.stringToInt(editTimeshift.getText())); if (SafeParse.stringToDouble(editCarbTime.getText()) != 0d) data.put("preBolus", SafeParse.stringToDouble(editCarbTime.getText())); if (!notesEdit.getText().toString().equals("")) @@ -593,6 +615,18 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick ret += data.get("profile"); ret += "\n"; } + if (data.has("percentage")) { + ret += getString(R.string.careportal_newnstreatment_percentage_label); + ret += ": "; + ret += data.get("percentage"); + ret += " %\n"; + } + if (data.has("timeshift")) { + ret += getString(R.string.careportal_newnstreatment_timeshift_label); + ret += ": "; + ret += data.get("timeshift"); + ret += " h\n"; + } if (data.has("targetBottom") && data.has("targetTop")) { ret += getString(R.string.target_range); ret += " "; @@ -631,7 +665,7 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick if (options.executeProfileSwitch) { if (data.has("profile")) { try { - doProfileSwitch(profileStore, data.getString("profile"), data.getInt("duration")); + doProfileSwitch(profileStore, data.getString("profile"), data.getInt("duration"), data.getInt("percentage"), data.getInt("timeshift")); } catch (JSONException e) { log.error("Unhandled exception", e); } @@ -678,33 +712,63 @@ public class NewNSTreatmentDialog extends DialogFragment implements View.OnClick builder.show(); } - public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration) { + public static void doProfileSwitch(final ProfileStore profileStore, final String profileName, final int duration, final int percentage, final int timeshift) { sHandler.post(new Runnable() { @Override public void run() { - ProfileSwitch profileSwitch = new ProfileSwitch(); + ProfileSwitch profileSwitch = new ProfileSwitch(); + profileSwitch.date = System.currentTimeMillis(); + profileSwitch.source = Source.USER; + profileSwitch.profileName = profileName; + profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString(); + profileSwitch.profilePlugin = ConfigBuilderPlugin.getActiveProfileInterface().getClass().getName(); + profileSwitch.durationInMinutes = duration; + profileSwitch.isCPP = percentage != 100 || timeshift != 0; + profileSwitch.timeshift = timeshift; + profileSwitch.percentage = percentage; + MainApp.getConfigBuilder().addToHistoryProfileSwitch(profileSwitch); + + PumpInterface pump = MainApp.getConfigBuilder(); + if (pump != null) { + pump.setNewBasalProfile(profileSwitch.getProfileObject()); + MainApp.bus().post(new EventNewBasalProfile()); + } else { + log.error("No active pump selected"); + } + Answers.getInstance().logCustom(new CustomEvent("ProfileSwitch")); + } + }); + } + + public static void doProfileSwitch(final int duration, final int percentage, final int timeshift) { + sHandler.post(new Runnable() { + @Override + public void run() { + ProfileSwitch profileSwitch = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); + if (profileSwitch != null) { + profileSwitch = new ProfileSwitch(); profileSwitch.date = System.currentTimeMillis(); profileSwitch.source = Source.USER; - profileSwitch.profileName = profileName; - profileSwitch.profileJson = profileStore.getSpecificProfile(profileName).getData().toString(); + profileSwitch.profileName = MainApp.getConfigBuilder().getProfileName(System.currentTimeMillis(), false); + profileSwitch.profileJson = MainApp.getConfigBuilder().getProfile().getData().toString(); profileSwitch.profilePlugin = ConfigBuilderPlugin.getActiveProfileInterface().getClass().getName(); profileSwitch.durationInMinutes = duration; - if (ConfigBuilderPlugin.getActiveProfileInterface() instanceof CircadianPercentageProfilePlugin) { - CircadianPercentageProfilePlugin cpp = (CircadianPercentageProfilePlugin) ConfigBuilderPlugin.getActiveProfileInterface(); - profileSwitch.isCPP = true; - profileSwitch.timeshift = cpp.timeshift; - profileSwitch.percentage = cpp.percentage; - } + profileSwitch.isCPP = percentage != 100 || timeshift != 0; + profileSwitch.timeshift = timeshift; + profileSwitch.percentage = percentage; MainApp.getConfigBuilder().addToHistoryProfileSwitch(profileSwitch); PumpInterface pump = MainApp.getConfigBuilder(); if (pump != null) { - pump.setNewBasalProfile(profileStore.getSpecificProfile(profileName)); + pump.setNewBasalProfile(profileSwitch.getProfileObject()); MainApp.bus().post(new EventNewBasalProfile()); } else { log.error("No active pump selected"); } Answers.getInstance().logCustom(new CustomEvent("ProfileSwitch")); + } else { + log.error("No profile switch existing"); + } } }); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/OptionsToShow.java b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/OptionsToShow.java index 23ce1dbcde..cbdbe38940 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/OptionsToShow.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Careportal/OptionsToShow.java @@ -7,6 +7,7 @@ package info.nightscout.androidaps.plugins.Careportal; public class OptionsToShow { public int eventType; public int eventName; + public boolean date; public boolean bg; public boolean insulin; public boolean carbs; @@ -22,29 +23,63 @@ public class OptionsToShow { public boolean executeProfileSwitch = false; public boolean executeTempTarget = false; - public OptionsToShow(int eventType, - int eventName, - boolean bg, - boolean insulin, - boolean carbs, - boolean prebolus, - boolean duration, - boolean percent, - boolean absolute, - boolean profile, - boolean split, - boolean tempTarget) { + public OptionsToShow(int eventType, int eventName) { this.eventType = eventType; this.eventName = eventName; - this.bg = bg; - this.insulin = insulin; - this.carbs = carbs; - this.prebolus = prebolus; - this.duration = duration; - this.percent = percent; - this.absolute = absolute; - this.profile = profile; - this.split = split; - this.tempTarget = tempTarget; + } + + public OptionsToShow date() { + date = true; + return this; + } + + public OptionsToShow bg() { + bg = true; + return this; + } + + public OptionsToShow insulin() { + insulin = true; + return this; + } + + public OptionsToShow carbs() { + carbs = true; + return this; + } + + public OptionsToShow prebolus() { + prebolus = true; + return this; + } + + public OptionsToShow duration() { + duration = true; + return this; + } + + public OptionsToShow percent() { + percent = true; + return this; + } + + public OptionsToShow absolute() { + absolute = true; + return this; + } + + public OptionsToShow profile() { + profile = true; + return this; + } + + public OptionsToShow split() { + split = true; + return this; + } + + public OptionsToShow tempTarget() { + tempTarget = true; + return this; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java index ffc5c3426f..b60ab20d88 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ConfigBuilder/ConfigBuilderPlugin.java @@ -216,7 +216,7 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain return activePump; } - public static SensitivityInterface getActiveSensitivity() { + public static SensitivityInterface getActiveSensitivity() { return activeSensitivity; } @@ -574,7 +574,7 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain if (Config.logCongigBuilderActions) log.debug("applyAPSRequest: Basal set correctly"); } - } else if (isTempBasalInProgress() && Math.abs(request.rate - getTempBasalAbsoluteRateHistory()) < 0.05) { + } else if (isTempBasalInProgress() && Math.abs(request.rate - getTempBasalAbsoluteRateHistory()) < getPumpDescription().basalStep) { result = new PumpEnactResult(); result.absolute = getTempBasalAbsoluteRateHistory(); result.duration = getTempBasalFromHistory(System.currentTimeMillis()).getPlannedRemainingMinutes(); @@ -934,10 +934,14 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain } public String getProfileName(long time) { + return getProfileName(time, true); + } + + public String getProfileName(long time, boolean customized) { ProfileSwitch profileSwitch = getProfileSwitchFromHistory(time); if (profileSwitch != null) { if (profileSwitch.profileJson != null) { - return profileSwitch.profileName; + return customized ? profileSwitch.getCustomizedName() : profileSwitch.profileName; } else { Profile profile = activeProfile.getProfile().getSpecificProfile(profileSwitch.profileName); if (profile != null) @@ -993,7 +997,7 @@ public class ConfigBuilderPlugin implements PluginBase, PumpInterface, Constrain MainApp.bus().post(new EventNewNotification(nobasal)); Notification notarget = new Notification(Notification.TARGET_MISSING, MainApp.sResources.getString(R.string.targetmissing), Notification.URGENT); MainApp.bus().post(new EventNewNotification(notarget)); - return new Profile(new JSONObject("{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"20\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"20\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"6\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"8\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}}")); + return new Profile(new JSONObject("{\"dia\":\"3\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"20\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"20\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"0.1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"6\"}],\"target_high\":[{\"time\":\"00:00\",\"value\":\"8\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}}"), 100, 0); } catch (JSONException e) { log.error("Unhandled exception", e); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/broadcasts/BroadcastSgvs.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/broadcasts/BroadcastSgvs.java index d4193f3cb7..65a90f3b74 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/broadcasts/BroadcastSgvs.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/broadcasts/BroadcastSgvs.java @@ -46,22 +46,28 @@ public class BroadcastSgvs { } public static void handleNewSgv(JSONArray sgvs, Context context, boolean isDelta) { - Bundle bundle = new Bundle(); - bundle.putString("sgvs", sgvs.toString()); - bundle.putBoolean("delta", isDelta); - Intent intent = new Intent(Intents.ACTION_NEW_SGV); - intent.putExtras(bundle); - intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - LocalBroadcastManager.getInstance(MainApp.instance()).sendBroadcast(intent); - if(SP.getBoolean(R.string.key_nsclient_localbroadcasts, true)) { - bundle = new Bundle(); - bundle.putString("sgvs", sgvs.toString()); + List splitted = BroadcastTreatment.splitArray(sgvs); + for (JSONArray part : splitted) { + Bundle bundle = new Bundle(); + bundle.putString("sgvs", part.toString()); bundle.putBoolean("delta", isDelta); - intent = new Intent(Intents.ACTION_NEW_SGV); + Intent intent = new Intent(Intents.ACTION_NEW_SGV); intent.putExtras(bundle); intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); - context.sendBroadcast(intent); + LocalBroadcastManager.getInstance(MainApp.instance()).sendBroadcast(intent); + } + + if(SP.getBoolean(R.string.key_nsclient_localbroadcasts, true)) { + for (JSONArray part : splitted) { + Bundle bundle = new Bundle(); + bundle.putString("sgvs", part.toString()); + bundle.putBoolean("delta", isDelta); + Intent intent = new Intent(Intents.ACTION_NEW_SGV); + intent.putExtras(bundle); + intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); + context.sendBroadcast(intent); + } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/services/NSClientService.java b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/services/NSClientService.java index 3fd608475f..d3d17b510b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/services/NSClientService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/NSClientInternal/services/NSClientService.java @@ -9,6 +9,7 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.PowerManager; +import com.crashlytics.android.Crashlytics; import com.google.common.base.Charsets; import com.google.common.hash.Hashing; import com.j256.ormlite.dao.CloseableIterator; @@ -322,12 +323,18 @@ public class NSClientService extends Service { */ @Override public void call(final Object... args) { - JSONObject data = (JSONObject) args[0]; + JSONObject data; + try { + data = (JSONObject) args[0]; + } catch (Exception e) { + Crashlytics.log("Wrong Announcement from NS: " + args[0]); + return; + } if (Config.detailedLog) try { MainApp.bus().post(new EventNSClientNewLog("ANNOUNCEMENT", data.has("message") ? data.getString("message") : "received")); - } catch (JSONException e) { - log.error("Unhandled exception", e); + } catch (Exception e) { + Crashlytics.logException(e); } BroadcastAnnouncement.handleAnnouncement(data, getApplicationContext()); log.debug(data.toString()); @@ -352,7 +359,13 @@ public class NSClientService extends Service { public void call(final Object... args) { if (Config.detailedLog) MainApp.bus().post(new EventNSClientNewLog("ALARM", "received")); - JSONObject data = (JSONObject) args[0]; + JSONObject data; + try { + data = (JSONObject) args[0]; + } catch (Exception e) { + Crashlytics.log("Wrong alarm from NS: " + args[0]); + return; + } BroadcastAlarm.handleAlarm(data, getApplicationContext()); log.debug(data.toString()); } @@ -374,7 +387,13 @@ public class NSClientService extends Service { */ @Override public void call(final Object... args) { - JSONObject data = (JSONObject) args[0]; + JSONObject data; + try { + data = (JSONObject) args[0]; + } catch (Exception e) { + Crashlytics.log("Wrong Urgent alarm from NS: " + args[0]); + return; + } if (Config.detailedLog) MainApp.bus().post(new EventNSClientNewLog("URGENTALARM", "received")); BroadcastUrgentAlarm.handleUrgentAlarm(data, getApplicationContext()); @@ -393,9 +412,15 @@ public class NSClientService extends Service { */ @Override public void call(final Object... args) { + JSONObject data; + try { + data = (JSONObject) args[0]; + } catch (Exception e) { + Crashlytics.log("Wrong Urgent alarm from NS: " + args[0]); + return; + } if (Config.detailedLog) MainApp.bus().post(new EventNSClientNewLog("CLEARALARM", "received")); - JSONObject data = (JSONObject) args[0]; BroadcastClearAlarm.handleClearAlarm(data, getApplicationContext()); log.debug(data.toString()); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java index 44ab8ecb14..3102ac95d6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalAdapterAMAJS.java @@ -1,16 +1,22 @@ package info.nightscout.androidaps.plugins.OpenAPSAMA; -import com.eclipsesource.v8.JavaVoidCallback; -import com.eclipsesource.v8.V8; -import com.eclipsesource.v8.V8Array; -import com.eclipsesource.v8.V8Object; - +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.javascript.Callable; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.NativeJSON; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.RhinoException; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; +import org.mozilla.javascript.Undefined; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import java.util.Date; import info.nightscout.androidaps.Config; @@ -24,6 +30,7 @@ import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.IobCobCalculator.IobCobCalculatorPlugin; import info.nightscout.androidaps.plugins.Loop.ScriptReader; import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.plugins.OpenAPSMA.LoggerCallback; import info.nightscout.utils.SP; public class DetermineBasalAdapterAMAJS { @@ -31,20 +38,13 @@ public class DetermineBasalAdapterAMAJS { private ScriptReader mScriptReader = null; - V8 mV8rt; - private V8Object mProfile; - private V8Object mGlucoseStatus; - private V8Array mIobData; - private V8Object mMealData; - private V8Object mCurrentTemp; - private V8Object mAutosensData = null; - private final String PARAM_currentTemp = "currentTemp"; - private final String PARAM_iobData = "iobData"; - private final String PARAM_glucoseStatus = "glucose_status"; - private final String PARAM_profile = "profile"; - private final String PARAM_meal_data = "meal_data"; - private final String PARAM_autosens_data = "autosens_data"; + private JSONObject mProfile; + private JSONObject mGlucoseStatus; + private JSONArray mIobData; + private JSONObject mMealData; + private JSONObject mCurrentTemp; + private JSONObject mAutosensData = null; private String storedCurrentTemp = null; private String storedIobData = null; @@ -55,58 +55,101 @@ public class DetermineBasalAdapterAMAJS { private String scriptDebug = ""; - /** - * Main code - */ - public DetermineBasalAdapterAMAJS(ScriptReader scriptReader) throws IOException { - mV8rt = V8.createV8Runtime(); mScriptReader = scriptReader; - - initLogCallback(); - initProcessExitCallback(); - initModuleParent(); - loadScript(); } public DetermineBasalResultAMA invoke() { + log.debug(">>> Invoking detemine_basal <<<"); - log.debug("Glucose status: " + (storedGlucoseStatus = mV8rt.executeStringScript("JSON.stringify(" + PARAM_glucoseStatus + ");"))); - log.debug("IOB data: " + (storedIobData = mV8rt.executeStringScript("JSON.stringify(" + PARAM_iobData + ");"))); - log.debug("Current temp: " + (storedCurrentTemp = mV8rt.executeStringScript("JSON.stringify(" + PARAM_currentTemp + ");"))); - log.debug("Profile: " + (storedProfile = mV8rt.executeStringScript("JSON.stringify(" + PARAM_profile + ");"))); - log.debug("Meal data: " + (storedMeal_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_meal_data + ");"))); + log.debug("Glucose status: " + (storedGlucoseStatus = mGlucoseStatus.toString())); + log.debug("IOB data: " + (storedIobData = mIobData.toString())); + log.debug("Current temp: " + (storedCurrentTemp = mCurrentTemp.toString())); + log.debug("Profile: " + (storedProfile = mProfile.toString())); + log.debug("Meal data: " + (storedMeal_data = mMealData.toString())); if (mAutosensData != null) - log.debug("Autosens data: " + (storedAutosens_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_autosens_data + ");"))); + log.debug("Autosens data: " + (storedAutosens_data = mAutosensData.toString())); else log.debug("Autosens data: " + (storedAutosens_data = "undefined")); - mV8rt.executeVoidScript( - "var rT = determine_basal(" + - PARAM_glucoseStatus + ", " + - PARAM_currentTemp + ", " + - PARAM_iobData + ", " + - PARAM_profile + ", " + - PARAM_autosens_data + ", " + - PARAM_meal_data + ", " + - "tempBasalFunctions" + - ");"); + DetermineBasalResultAMA determineBasalResultAMA = null; + Context rhino = Context.enter(); + Scriptable scope = rhino.initStandardObjects(); + // Turn off optimization to make Rhino Android compatible + rhino.setOptimizationLevel(-1); - String ret = mV8rt.executeStringScript("JSON.stringify(rT);"); - log.debug("Result: " + ret); - - V8Object v8ObjectReuslt = mV8rt.getObject("rT"); - - DetermineBasalResultAMA result = null; try { - result = new DetermineBasalResultAMA(v8ObjectReuslt, new JSONObject(ret)); - } catch (JSONException e) { - log.error("Unhandled exception", e); + + //register logger callback for console.log and console.error + ScriptableObject.defineClass(scope, LoggerCallback.class); + Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null); + scope.put("console2", scope, myLogger); + rhino.evaluateString(scope, readFile("OpenAPSAMA/loggerhelper.js"), "JavaScript", 0, null); + + //set module parent + rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null); + rhino.evaluateString(scope, "var round_basal = function round_basal(basal, profile) { return basal; };", "JavaScript", 0, null); + rhino.evaluateString(scope, "require = function() {return round_basal;};", "JavaScript", 0, null); + + //generate functions "determine_basal" and "setTempBasal" + rhino.evaluateString(scope, readFile("OpenAPSAMA/determine-basal.js"), "JavaScript", 0, null); + rhino.evaluateString(scope, readFile("OpenAPSAMA/basal-set-temp.js"), "setTempBasal.js", 0, null); + Object determineBasalObj = scope.get("determine_basal", scope); + Object setTempBasalFunctionsObj = scope.get("tempBasalFunctions", scope); + + //call determine-basal + if (determineBasalObj instanceof Function && setTempBasalFunctionsObj instanceof NativeObject) { + Function determineBasalJS = (Function) determineBasalObj; + + //prepare parameters + Object[] params = new Object[]{ + makeParam(mGlucoseStatus, rhino, scope), + makeParam(mCurrentTemp, rhino, scope), + makeParamArray(mIobData, rhino, scope), + makeParam(mProfile, rhino, scope), + makeParam(mAutosensData, rhino, scope), + makeParam(mMealData, rhino, scope), + setTempBasalFunctionsObj}; + + NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params); + scriptDebug = LoggerCallback.getScriptDebug(); + + // Parse the jsResult object to a JSON-String + String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString(); + if (Config.logAPSResult) + log.debug("Result: " + result); + try { + determineBasalResultAMA = new DetermineBasalResultAMA(jsResult, new JSONObject(result)); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + } else { + log.debug("Problem loading JS Functions"); + } + } catch (IOException e) { + log.debug("IOException"); + } catch (RhinoException e) { + log.error("RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString()); + } catch (IllegalAccessException e) { + log.error(e.toString()); + } catch (InstantiationException e) { + log.error(e.toString()); + } catch (InvocationTargetException e) { + log.error(e.toString()); + } finally { + Context.exit(); } - return result; + storedGlucoseStatus = mGlucoseStatus.toString(); + storedIobData = mIobData.toString(); + storedCurrentTemp = mCurrentTemp.toString(); + storedProfile = mProfile.toString(); + storedMeal_data = mMealData.toString(); + + return determineBasalResultAMA; + } String getGlucoseStatusParam() { @@ -137,60 +180,6 @@ public class DetermineBasalAdapterAMAJS { return scriptDebug; } - private void loadScript() throws IOException { - mV8rt.executeVoidScript("var round_basal = function round_basal(basal, profile) { return basal; };"); - mV8rt.executeVoidScript("require = function() {return round_basal;};"); - - mV8rt.executeVoidScript(readFile("OpenAPSAMA/basal-set-temp.js"), "OpenAPSAMA/basal-set-temp.js ", 0); - mV8rt.executeVoidScript("var tempBasalFunctions = module.exports;"); - - mV8rt.executeVoidScript( - readFile("OpenAPSAMA/determine-basal.js"), - "OpenAPSAMA/determine-basal.js", - 0); - mV8rt.executeVoidScript("var determine_basal = module.exports;"); - } - - private void initModuleParent() { - mV8rt.executeVoidScript("var module = {\"parent\":Boolean(1)};"); - } - - private void initProcessExitCallback() { - JavaVoidCallback callbackProccessExit = new JavaVoidCallback() { - @Override - public void invoke(V8Object arg0, V8Array parameters) { - if (parameters.length() > 0) { - Object arg1 = parameters.get(0); - log.error("ProccessExit " + arg1); - } - } - }; - mV8rt.registerJavaMethod(callbackProccessExit, "proccessExit"); - mV8rt.executeVoidScript("var process = {\"exit\": function () { proccessExit(); } };"); - } - - private void initLogCallback() { - JavaVoidCallback callbackLog = new JavaVoidCallback() { - @Override - public void invoke(V8Object arg0, V8Array parameters) { - int i = 0; - String s = ""; - while (i < parameters.length()) { - Object arg = parameters.get(i); - s += arg + " "; - i++; - } - if (!s.equals("") && Config.logAPSResult) { - log.debug("Script debug: " + s); - scriptDebug += s + "\n"; - } - } - }; - mV8rt.registerJavaMethod(callbackLog, "log"); - mV8rt.executeVoidScript("var console = {\"log\":log, \"error\":log};"); - } - - public void setData(Profile profile, double maxIob, double maxBasal, @@ -203,89 +192,94 @@ public class DetermineBasalAdapterAMAJS { MealData mealData, double autosensDataRatio, boolean tempTargetSet, - double min_5m_carbimpact) { + double min_5m_carbimpact) throws JSONException { String units = profile.getUnits(); - mProfile = new V8Object(mV8rt); - mProfile.add("max_iob", maxIob); - mProfile.add("dia", Math.min(profile.getDia(), 3d)); - mProfile.add("type", "current"); - mProfile.add("max_daily_basal", profile.getMaxDailyBasal()); - mProfile.add("max_basal", maxBasal); - mProfile.add("min_bg", minBg); - mProfile.add("max_bg", maxBg); - mProfile.add("target_bg", targetBg); - mProfile.add("carb_ratio", profile.getIc()); - mProfile.add("sens", Profile.toMgdl(profile.getIsf().doubleValue(), units)); - mProfile.add("max_daily_safety_multiplier", SP.getInt("openapsama_max_daily_safety_multiplier", 3)); - mProfile.add("current_basal_safety_multiplier", SP.getInt("openapsama_current_basal_safety_multiplier", 4)); - mProfile.add("skip_neutral_temps", true); - mProfile.add("current_basal", pump.getBaseBasalRate()); - mProfile.add("temptargetSet", tempTargetSet); - mProfile.add("autosens_adjust_targets", SP.getBoolean("openapsama_autosens_adjusttargets", true)); - mProfile.add("min_5m_carbimpact", SP.getDouble("openapsama_min_5m_carbimpact", 3d)); + mProfile = new JSONObject(); + mProfile.put("max_iob", maxIob); + mProfile.put("dia", Math.min(profile.getDia(), 3d)); + mProfile.put("type", "current"); + mProfile.put("max_daily_basal", profile.getMaxDailyBasal()); + mProfile.put("max_basal", maxBasal); + mProfile.put("min_bg", minBg); + mProfile.put("max_bg", maxBg); + mProfile.put("target_bg", targetBg); + mProfile.put("carb_ratio", profile.getIc()); + mProfile.put("sens", Profile.toMgdl(profile.getIsf().doubleValue(), units)); + mProfile.put("max_daily_safety_multiplier", SP.getInt("openapsama_max_daily_safety_multiplier", 3)); + mProfile.put("current_basal_safety_multiplier", SP.getInt("openapsama_current_basal_safety_multiplier", 4)); + mProfile.put("skip_neutral_temps", true); + mProfile.put("current_basal", pump.getBaseBasalRate()); + mProfile.put("temptargetSet", tempTargetSet); + mProfile.put("autosens_adjust_targets", SP.getBoolean("openapsama_autosens_adjusttargets", true)); + mProfile.put("min_5m_carbimpact", SP.getDouble("openapsama_min_5m_carbimpact", 3d)); if (units.equals(Constants.MMOL)) { - mProfile.add("out_units", "mmol/L"); + mProfile.put("out_units", "mmol/L"); } - mV8rt.add(PARAM_profile, mProfile); - mCurrentTemp = new V8Object(mV8rt); - mCurrentTemp.add("temp", "absolute"); - mCurrentTemp.add("duration", MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory()); - mCurrentTemp.add("rate", MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()); + mCurrentTemp = new JSONObject(); + mCurrentTemp.put("temp", "absolute"); + mCurrentTemp.put("duration", MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory()); + mCurrentTemp.put("rate", MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()); // as we have non default temps longer than 30 mintues TemporaryBasal tempBasal = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); if (tempBasal != null) { - mCurrentTemp.add("minutesrunning", tempBasal.getRealDuration()); + mCurrentTemp.put("minutesrunning", tempBasal.getRealDuration()); } - mV8rt.add(PARAM_currentTemp, mCurrentTemp); + mIobData = IobCobCalculatorPlugin.convertToJSONArray(iobArray); - mIobData = mV8rt.executeArrayScript(IobCobCalculatorPlugin.convertToJSONArray(iobArray).toString()); - mV8rt.add(PARAM_iobData, mIobData); - - mGlucoseStatus = new V8Object(mV8rt); - mGlucoseStatus.add("glucose", glucoseStatus.glucose); + mGlucoseStatus = new JSONObject(); + mGlucoseStatus.put("glucose", glucoseStatus.glucose); if (SP.getBoolean("always_use_shortavg", false)) { - mGlucoseStatus.add("delta", glucoseStatus.short_avgdelta); + mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta); } else { - mGlucoseStatus.add("delta", glucoseStatus.delta); + mGlucoseStatus.put("delta", glucoseStatus.delta); } - mGlucoseStatus.add("short_avgdelta", glucoseStatus.short_avgdelta); - mGlucoseStatus.add("long_avgdelta", glucoseStatus.long_avgdelta); - mV8rt.add(PARAM_glucoseStatus, mGlucoseStatus); + mGlucoseStatus.put("short_avgdelta", glucoseStatus.short_avgdelta); + mGlucoseStatus.put("long_avgdelta", glucoseStatus.long_avgdelta); - mMealData = new V8Object(mV8rt); - mMealData.add("carbs", mealData.carbs); - mMealData.add("boluses", mealData.boluses); - mMealData.add("mealCOB", mealData.mealCOB); - mV8rt.add(PARAM_meal_data, mMealData); + mMealData = new JSONObject(); + mMealData.put("carbs", mealData.carbs); + mMealData.put("boluses", mealData.boluses); + mMealData.put("mealCOB", mealData.mealCOB); if (MainApp.getConfigBuilder().isAMAModeEnabled()) { - mAutosensData = new V8Object(mV8rt); - mAutosensData.add("ratio", autosensDataRatio); - mV8rt.add(PARAM_autosens_data, mAutosensData); + mAutosensData = new JSONObject(); + mAutosensData.put("ratio", autosensDataRatio); } else { - mV8rt.addUndefined(PARAM_autosens_data); + mAutosensData = null; } } - public void release() { - mProfile.release(); - mCurrentTemp.release(); - mIobData.release(); - mMealData.release(); - mGlucoseStatus.release(); - if (mAutosensData != null) { - mAutosensData.release(); - } - mV8rt.release(); + public Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) { + + if(jsonObject == null) return Undefined.instance; + + Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), new Callable() { + @Override + public Object call(Context context, Scriptable scriptable, Scriptable scriptable1, Object[] objects) { + return objects[1]; + } + }); + return param; + } + + public Object makeParamArray(JSONArray jsonArray, Context rhino, Scriptable scope) { + //Object param = NativeJSON.parse(rhino, scope, "{myarray: " + jsonArray.toString() + " }", new Callable() { + Object param = NativeJSON.parse(rhino, scope, jsonArray.toString(), new Callable() { + @Override + public Object call(Context context, Scriptable scriptable, Scriptable scriptable1, Object[] objects) { + return objects[1]; + } + }); + return param; } public String readFile(String filename) throws IOException { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java index 31501b7032..774ff55401 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/DetermineBasalResultAMA.java @@ -5,6 +5,7 @@ import com.eclipsesource.v8.V8Object; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.javascript.NativeObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -25,35 +26,34 @@ public class DetermineBasalResultAMA extends APSResult { public double snoozeBG; public IobTotal iob; - public DetermineBasalResultAMA(V8Object result, JSONObject j) { + public DetermineBasalResultAMA(NativeObject result, JSONObject j) { date = new Date(); json = j; - if (result.contains("error")) { - reason = result.getString("error"); + if (result.containsKey("error")) { + reason = result.get("error").toString(); changeRequested = false; rate = -1; duration = -1; } else { - reason = result.getString("reason"); - if (result.contains("eventualBG")) eventualBG = result.getDouble("eventualBG"); - if (result.contains("snoozeBG")) snoozeBG = result.getDouble("snoozeBG"); - if (result.contains("rate")) { - rate = result.getDouble("rate"); + reason = result.get("reason").toString(); + if (result.containsKey("eventualBG")) eventualBG = (Double) result.get("eventualBG"); + if (result.containsKey("snoozeBG")) snoozeBG = (Double) result.get("snoozeBG"); + if (result.containsKey("rate")) { + rate = (Double) result.get("rate"); if (rate < 0d) rate = 0d; changeRequested = true; } else { rate = -1; changeRequested = false; } - if (result.contains("duration")) { - duration = result.getInteger("duration"); + if (result.containsKey("duration")) { + duration = ((Double)result.get("duration")).intValue(); //changeRequested as above } else { duration = -1; changeRequested = false; } } - result.release(); } public DetermineBasalResultAMA() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java index dfad17de2e..1e574bcc6c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSAMA/OpenAPSAMAPlugin.java @@ -222,11 +222,16 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { Profiler.log(log, "AMA data gathering", start); start = new Date(); - determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobArray, glucoseStatus, mealData, - lastAutosensResult.ratio, //autosensDataRatio - isTempTarget, - SafeParse.stringToDouble(SP.getString("openapsama_min_5m_carbimpact", "3.0"))//min_5m_carbimpact - ); + + try { + determineBasalAdapterAMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobArray, glucoseStatus, mealData, + lastAutosensResult.ratio, //autosensDataRatio + isTempTarget, + SafeParse.stringToDouble(SP.getString("openapsama_min_5m_carbimpact", "3.0"))//min_5m_carbimpact + ); + } catch (JSONException e) { + log.error("Unable to set data: " + e.toString()); + } DetermineBasalResultAMA determineBasalResultAMA = determineBasalAdapterAMAJS.invoke(); @@ -244,8 +249,6 @@ public class OpenAPSAMAPlugin implements PluginBase, APSInterface { determineBasalResultAMA.iob = iobArray[0]; - determineBasalAdapterAMAJS.release(); - Date now = new Date(); try { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterMAJS.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterMAJS.java index a8f797f8c1..a7e1d5da58 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterMAJS.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalAdapterMAJS.java @@ -1,16 +1,20 @@ package info.nightscout.androidaps.plugins.OpenAPSMA; -import com.eclipsesource.v8.JavaVoidCallback; -import com.eclipsesource.v8.V8; -import com.eclipsesource.v8.V8Array; -import com.eclipsesource.v8.V8Object; - import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.javascript.Callable; +import org.mozilla.javascript.Context; +import org.mozilla.javascript.Function; +import org.mozilla.javascript.NativeJSON; +import org.mozilla.javascript.NativeObject; +import org.mozilla.javascript.RhinoException; +import org.mozilla.javascript.Scriptable; +import org.mozilla.javascript.ScriptableObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Constants; @@ -26,20 +30,12 @@ import info.nightscout.utils.SP; public class DetermineBasalAdapterMAJS { private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterMAJS.class); - private ScriptReader mScriptReader = null; - V8 mV8rt; - private V8Object mProfile; - private V8Object mGlucoseStatus; - private V8Object mIobData; - private V8Object mMealData; - private V8Object mCurrentTemp; - - private final String PARAM_currentTemp = "currentTemp"; - private final String PARAM_iobData = "iobData"; - private final String PARAM_glucoseStatus = "glucose_status"; - private final String PARAM_profile = "profile"; - private final String PARAM_meal_data = "meal_data"; + private JSONObject mProfile; + private JSONObject mGlucoseStatus; + private JSONObject mIobData; + private JSONObject mMealData; + private JSONObject mCurrentTemp; private String storedCurrentTemp = null; public String storedIobData = null; @@ -47,104 +43,90 @@ public class DetermineBasalAdapterMAJS { private String storedProfile = null; private String storedMeal_data = null; - /** - * Main code - */ - public DetermineBasalAdapterMAJS(ScriptReader scriptReader) throws IOException { - mV8rt = V8.createV8Runtime(); mScriptReader = scriptReader; - - init(); - initLogCallback(); - initProcessExitCallback(); - initModuleParent(); - loadScript(); - } - - public void init() { - // Profile - mProfile = new V8Object(mV8rt); - mProfile.add("max_iob", 0); - mProfile.add("dia", 0); - mProfile.add("type", "current"); - mProfile.add("max_daily_basal", 0); - mProfile.add("max_basal", 0); - mProfile.add("max_bg", 0); - mProfile.add("min_bg", 0); - mProfile.add("carb_ratio", 0); - mProfile.add("sens", 0); - mProfile.add("current_basal", 0); - mV8rt.add(PARAM_profile, mProfile); - // Current temp - mCurrentTemp = new V8Object(mV8rt); - mCurrentTemp.add("temp", "absolute"); - mCurrentTemp.add("duration", 0); - mCurrentTemp.add("rate", 0); - mV8rt.add(PARAM_currentTemp, mCurrentTemp); - // IOB data - mIobData = new V8Object(mV8rt); - mIobData.add("iob", 0); //netIob - mIobData.add("activity", 0); //netActivity - mIobData.add("bolussnooze", 0); //bolusIob - mIobData.add("basaliob", 0); - mIobData.add("netbasalinsulin", 0); - mIobData.add("hightempinsulin", 0); - mV8rt.add(PARAM_iobData, mIobData); - // Glucose status - mGlucoseStatus = new V8Object(mV8rt); - mGlucoseStatus.add("glucose", 0); - mGlucoseStatus.add("delta", 0); - mGlucoseStatus.add("avgdelta", 0); - mV8rt.add(PARAM_glucoseStatus, mGlucoseStatus); - // Meal data - mMealData = new V8Object(mV8rt); - mMealData.add("carbs", 0); - mMealData.add("boluses", 0); - mV8rt.add(PARAM_meal_data, mMealData); } public DetermineBasalResultMA invoke() { - mV8rt.executeVoidScript( - "console.error(\"determine_basal(\"+\n" + - "JSON.stringify(" + PARAM_glucoseStatus + ")+ \", \" +\n" + - "JSON.stringify(" + PARAM_currentTemp + ")+ \", \" +\n" + - "JSON.stringify(" + PARAM_iobData + ")+ \", \" +\n" + - "JSON.stringify(" + PARAM_profile + ")+ \", \" +\n" + - "JSON.stringify(" + PARAM_meal_data + ")+ \") \");" - ); - mV8rt.executeVoidScript( - "var rT = determine_basal(" + - PARAM_glucoseStatus + ", " + - PARAM_currentTemp + ", " + - PARAM_iobData + ", " + - PARAM_profile + ", " + - "undefined, " + - PARAM_meal_data + ", " + - "setTempBasal" + - ");"); + DetermineBasalResultMA determineBasalResultMA = null; + Context rhino = Context.enter(); + Scriptable scope = rhino.initStandardObjects(); + // Turn off optimization to make Rhino Android compatible + rhino.setOptimizationLevel(-1); - String ret = mV8rt.executeStringScript("JSON.stringify(rT);"); - if (Config.logAPSResult) - log.debug("Result: " + ret); - - V8Object v8ObjectReuslt = mV8rt.getObject("rT"); - - DetermineBasalResultMA result = null; try { - result = new DetermineBasalResultMA(v8ObjectReuslt, new JSONObject(ret)); - } catch (JSONException e) { - log.error("Unhandled exception", e); + + //register logger callback for console.log and console.error + ScriptableObject.defineClass(scope, LoggerCallback.class); + Scriptable myLogger = rhino.newObject(scope, "LoggerCallback", null); + scope.put("console", scope, myLogger); + + //set module parent + rhino.evaluateString(scope, "var module = {\"parent\":Boolean(1)};", "JavaScript", 0, null); + + //generate functions "determine_basal" and "setTempBasal" + rhino.evaluateString(scope, readFile("OpenAPSMA/determine-basal.js"), "JavaScript", 0, null); + + String setTempBasalCode = "var setTempBasal = function (rate, duration, profile, rT, offline) {" + + "rT.duration = duration;\n" + + " rT.rate = rate;" + + "return rT;" + + "};"; + rhino.evaluateString(scope, setTempBasalCode, "setTempBasal.js", 0, null); + Object determineBasalObj = scope.get("determine_basal", scope); + Object setTempBasalObj = scope.get("setTempBasal", scope); + + //call determine-basal + if (determineBasalObj instanceof Function && setTempBasalObj instanceof Function) { + Function determineBasalJS = (Function) determineBasalObj; + Function setTempBasalJS = (Function) setTempBasalObj; + + //prepare parameters + Object[] params = new Object[]{ + makeParam(mGlucoseStatus, rhino, scope), + makeParam(mCurrentTemp, rhino, scope), + makeParam(mIobData, rhino, scope), + makeParam(mProfile, rhino, scope), + "undefined", + makeParam(mMealData, rhino, scope), + setTempBasalJS}; + + NativeObject jsResult = (NativeObject) determineBasalJS.call(rhino, scope, scope, params); + + // Parse the jsResult object to a JSON-String + String result = NativeJSON.stringify(rhino, scope, jsResult, null, null).toString(); + if (Config.logAPSResult) + log.debug("Result: " + result); + try { + determineBasalResultMA = new DetermineBasalResultMA(jsResult, new JSONObject(result)); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + } else { + log.debug("Problem loading JS Functions"); + } + } catch (IOException e) { + log.debug("IOException"); + } catch (RhinoException e) { + log.error("RhinoException: (" + e.lineNumber() + "," + e.columnNumber() + ") " + e.toString()); + } catch (IllegalAccessException e) { + log.error(e.toString()); + } catch (InstantiationException e) { + log.error(e.toString()); + } catch (InvocationTargetException e) { + log.error(e.toString()); + } finally { + Context.exit(); } - storedGlucoseStatus = mV8rt.executeStringScript("JSON.stringify(" + PARAM_glucoseStatus + ");"); - storedIobData = mV8rt.executeStringScript("JSON.stringify(" + PARAM_iobData + ");"); - storedCurrentTemp = mV8rt.executeStringScript("JSON.stringify(" + PARAM_currentTemp + ");"); - storedProfile = mV8rt.executeStringScript("JSON.stringify(" + PARAM_profile + ");"); - storedMeal_data = mV8rt.executeStringScript("JSON.stringify(" + PARAM_meal_data + ");"); + storedGlucoseStatus = mGlucoseStatus.toString(); + storedIobData = mIobData.toString(); + storedCurrentTemp = mCurrentTemp.toString(); + storedProfile = mProfile.toString(); + storedMeal_data = mMealData.toString(); - return result; + return determineBasalResultMA; } String getGlucoseStatusParam() { @@ -167,57 +149,6 @@ public class DetermineBasalAdapterMAJS { return storedMeal_data; } - private void loadScript() throws IOException { - mV8rt.executeVoidScript( - readFile("OpenAPSMA/determine-basal.js"), - "OpenAPSMA/bin/oref0-determine-basal.js", - 0); - mV8rt.executeVoidScript("var determine_basal = module.exports;"); - mV8rt.executeVoidScript( - "var setTempBasal = function (rate, duration, profile, rT, offline) {" + - "rT.duration = duration;\n" + - " rT.rate = rate;" + - "return rT;" + - "};", - "setTempBasal.js", - 0 - ); - } - - private void initModuleParent() { - mV8rt.executeVoidScript("var module = {\"parent\":Boolean(1)};"); - } - - private void initProcessExitCallback() { - JavaVoidCallback callbackProccessExit = new JavaVoidCallback() { - @Override - public void invoke(V8Object arg0, V8Array parameters) { - if (parameters.length() > 0) { - Object arg1 = parameters.get(0); - log.error("ProccessExit " + arg1); - } - } - }; - mV8rt.registerJavaMethod(callbackProccessExit, "proccessExit"); - mV8rt.executeVoidScript("var process = {\"exit\": function () { proccessExit(); } };"); - } - - private void initLogCallback() { - JavaVoidCallback callbackLog = new JavaVoidCallback() { - @Override - public void invoke(V8Object arg0, V8Array parameters) { - if (parameters.length() > 0) { - Object arg1 = parameters.get(0); - if (Config.logAPSResult) - log.debug("Input params: " + arg1); - } - } - }; - mV8rt.registerJavaMethod(callbackLog, "log"); - mV8rt.executeVoidScript("var console = {\"log\":log, \"error\":log};"); - } - - public void setData(Profile profile, double maxIob, double maxBasal, @@ -227,57 +158,52 @@ public class DetermineBasalAdapterMAJS { PumpInterface pump, IobTotal iobData, GlucoseStatus glucoseStatus, - MealData mealData) { + MealData mealData) throws JSONException { String units = profile.getUnits(); - mProfile.add("max_iob", maxIob); - mProfile.add("dia", Math.min(profile.getDia(), 3d)); - mProfile.add("type", "current"); - mProfile.add("max_daily_basal", profile.getMaxDailyBasal()); - mProfile.add("max_basal", maxBasal); - mProfile.add("min_bg", minBg); - mProfile.add("max_bg", maxBg); - mProfile.add("target_bg", targetBg); - mProfile.add("carb_ratio", profile.getIc()); - mProfile.add("sens", Profile.toMgdl(profile.getIsf().doubleValue(), units)); + mProfile = new JSONObject(); + mProfile.put("max_iob", maxIob); + mProfile.put("dia", Math.min(profile.getDia(), 3d)); + mProfile.put("type", "current"); + mProfile.put("max_daily_basal", profile.getMaxDailyBasal()); + mProfile.put("max_basal", maxBasal); + mProfile.put("min_bg", minBg); + mProfile.put("max_bg", maxBg); + mProfile.put("target_bg", targetBg); + mProfile.put("carb_ratio", profile.getIc()); + mProfile.put("sens", Profile.toMgdl(profile.getIsf().doubleValue(), units)); - mProfile.add("current_basal", pump.getBaseBasalRate()); + mProfile.put("current_basal", pump.getBaseBasalRate()); if (units.equals(Constants.MMOL)) { - mProfile.add("out_units", "mmol/L"); + mProfile.put("out_units", "mmol/L"); } - mCurrentTemp.add("duration", MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory()); - mCurrentTemp.add("rate", MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()); + mCurrentTemp = new JSONObject(); + mCurrentTemp.put("duration", MainApp.getConfigBuilder().getTempBasalRemainingMinutesFromHistory()); + mCurrentTemp.put("rate", MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory()); - mIobData.add("iob", iobData.iob); //netIob - mIobData.add("activity", iobData.activity); //netActivity - mIobData.add("bolussnooze", iobData.bolussnooze); //bolusIob - mIobData.add("basaliob", iobData.basaliob); - mIobData.add("netbasalinsulin", iobData.netbasalinsulin); - mIobData.add("hightempinsulin", iobData.hightempinsulin); + mIobData = new JSONObject(); + mIobData.put("iob", iobData.iob); //netIob + mIobData.put("activity", iobData.activity); //netActivity + mIobData.put("bolussnooze", iobData.bolussnooze); //bolusIob + mIobData.put("basaliob", iobData.basaliob); + mIobData.put("netbasalinsulin", iobData.netbasalinsulin); + mIobData.put("hightempinsulin", iobData.hightempinsulin); - mGlucoseStatus.add("glucose", glucoseStatus.glucose); + mGlucoseStatus = new JSONObject(); + mGlucoseStatus.put("glucose", glucoseStatus.glucose); if (SP.getBoolean("always_use_shortavg", false)) { - mGlucoseStatus.add("delta", glucoseStatus.short_avgdelta); + mGlucoseStatus.put("delta", glucoseStatus.short_avgdelta); } else { - mGlucoseStatus.add("delta", glucoseStatus.delta); + mGlucoseStatus.put("delta", glucoseStatus.delta); } - mGlucoseStatus.add("avgdelta", glucoseStatus.avgdelta); + mGlucoseStatus.put("avgdelta", glucoseStatus.avgdelta); - mMealData.add("carbs", mealData.carbs); - mMealData.add("boluses", mealData.boluses); - } - - - public void release() { - mProfile.release(); - mCurrentTemp.release(); - mIobData.release(); - mMealData.release(); - mGlucoseStatus.release(); - mV8rt.release(); + mMealData = new JSONObject(); + mMealData.put("carbs", mealData.carbs); + mMealData.put("boluses", mealData.boluses); } public String readFile(String filename) throws IOException { @@ -289,4 +215,14 @@ public class DetermineBasalAdapterMAJS { return string; } + public Object makeParam(JSONObject jsonObject, Context rhino, Scriptable scope) { + Object param = NativeJSON.parse(rhino, scope, jsonObject.toString(), new Callable() { + @Override + public Object call(Context context, Scriptable scriptable, Scriptable scriptable1, Object[] objects) { + return objects[1]; + } + }); + return param; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java index 23f7c14a88..e132c9f953 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/DetermineBasalResultMA.java @@ -1,12 +1,8 @@ package info.nightscout.androidaps.plugins.OpenAPSMA; -import android.os.Parcel; -import android.os.Parcelable; - -import com.eclipsesource.v8.V8Object; - import org.json.JSONException; import org.json.JSONObject; +import org.mozilla.javascript.NativeObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,38 +18,37 @@ public class DetermineBasalResultMA extends APSResult { public String mealAssist; public IobTotal iob; - public DetermineBasalResultMA(V8Object result, JSONObject j) { + public DetermineBasalResultMA(NativeObject result, JSONObject j) { json = j; - if (result.contains("error")) { - reason = result.getString("error"); + if (result.containsKey("error")) { + reason = (String) result.get("error"); changeRequested = false; rate = -1; duration = -1; mealAssist = ""; } else { - reason = result.getString("reason"); - eventualBG = result.getDouble("eventualBG"); - snoozeBG = result.getDouble("snoozeBG"); - if (result.contains("rate")) { - rate = result.getDouble("rate"); + reason = result.get("reason").toString(); + eventualBG = (Double) result.get("eventualBG"); + snoozeBG = (Double) result.get("snoozeBG"); + if (result.containsKey("rate")) { + rate = (Double) result.get("rate"); if (rate < 0d) rate = 0d; changeRequested = true; } else { rate = -1; changeRequested = false; } - if (result.contains("duration")) { - duration = result.getInteger("duration"); + if (result.containsKey("duration")) { + duration = ((Double) result.get("duration")).intValue(); //changeRequested as above } else { duration = -1; changeRequested = false; } - if (result.contains("mealAssist")) { - mealAssist = result.getString("mealAssist"); + if (result.containsKey("mealAssist")) { + mealAssist = result.get("mealAssist").toString(); } else mealAssist = ""; } - result.release(); } public DetermineBasalResultMA() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/LoggerCallback.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/LoggerCallback.java new file mode 100644 index 0000000000..991ec2b25e --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/LoggerCallback.java @@ -0,0 +1,63 @@ +package info.nightscout.androidaps.plugins.OpenAPSMA; + +import org.mozilla.javascript.ScriptableObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.utils.ToastUtils; + +/** + * Created by adrian on 15/10/17. + */ + + +public class LoggerCallback extends ScriptableObject { + + private static Logger log = LoggerFactory.getLogger(DetermineBasalAdapterMAJS.class); + + static StringBuffer errorBuffer = new StringBuffer(); + static StringBuffer logBuffer = new StringBuffer(); + + + public LoggerCallback() { + //empty constructor needed for Rhino + errorBuffer = new StringBuffer(); + logBuffer = new StringBuffer(); + } + + @Override + public String getClassName() { + return "LoggerCallback"; + } + + public void jsConstructor() { + //empty constructor on JS site; could work as setter + } + + public void jsFunction_log(Object obj1) { + log.debug(obj1.toString()); + logBuffer.append(obj1.toString()); + logBuffer.append(' '); + } + + public void jsFunction_error(Object obj1) { + log.error(obj1.toString()); + errorBuffer.append(obj1.toString()); + errorBuffer.append(' '); + } + + + + public static String getScriptDebug(){ + String ret = ""; + if(errorBuffer.length() > 0){ + ret += "e:\n" + errorBuffer.toString(); + } + if(ret.length() > 0 && logBuffer.length() > 0) ret += '\n'; + if(logBuffer.length() > 0){ + ret += "d:\n" + logBuffer.toString(); + } + return ret; + } +} \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java index 42741340b5..9b9bdcbbf8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/OpenAPSMA/OpenAPSMAPlugin.java @@ -211,12 +211,16 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface { if (!checkOnlyHardLimits(pump.getBaseBasalRate(), "current_basal", 0.01, 5)) return; start = new Date(); - determineBasalAdapterMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobTotal, glucoseStatus, mealData); + try { + determineBasalAdapterMAJS.setData(profile, maxIob, maxBasal, minBg, maxBg, targetBg, pump, iobTotal, glucoseStatus, mealData); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } Profiler.log(log, "MA calculation", start); DetermineBasalResultMA determineBasalResultMA = determineBasalAdapterMAJS.invoke(); - // Fix bug determine basal + // Fix bug determinef basal if (determineBasalResultMA.rate == 0d && determineBasalResultMA.duration == 0 && !MainApp.getConfigBuilder().isTempBasalInProgress()) determineBasalResultMA.changeRequested = false; // limit requests on openloop mode @@ -229,8 +233,6 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface { determineBasalResultMA.iob = iobTotal; - determineBasalAdapterMAJS.release(); - try { determineBasalResultMA.json.put("timestamp", DateUtil.toISOString(now)); } catch (JSONException e) { @@ -241,8 +243,6 @@ public class OpenAPSMAPlugin implements PluginBase, APSInterface { lastAPSResult = determineBasalResultMA; lastAPSRun = now; MainApp.bus().post(new EventOpenAPSUpdateGui()); - - //deviceStatus.suggested = determineBasalResultMA.json; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java index 6cc8decfa3..dec763beff 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/NewTreatmentDialog.java @@ -7,7 +7,9 @@ import android.os.Handler; import android.os.HandlerThread; import android.support.v4.app.DialogFragment; import android.support.v7.app.AlertDialog; +import android.text.Editable; import android.text.Html; +import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; @@ -36,22 +38,53 @@ import info.nightscout.androidaps.plugins.Overview.Notification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.utils.NumberPicker; import info.nightscout.utils.SafeParse; +import info.nightscout.utils.ToastUtils; public class NewTreatmentDialog extends DialogFragment implements OnClickListener { private static Logger log = LoggerFactory.getLogger(NewTreatmentDialog.class); - NumberPicker editCarbs; - NumberPicker editInsulin; + private NumberPicker editCarbs; + private NumberPicker editInsulin; - Handler mHandler; - public static HandlerThread mHandlerThread; + private Integer maxCarbs; + private Double maxInsulin; + + private Handler mHandler; public NewTreatmentDialog() { - mHandlerThread = new HandlerThread(NewTreatmentDialog.class.getSimpleName()); + HandlerThread mHandlerThread = new HandlerThread(NewTreatmentDialog.class.getSimpleName()); mHandlerThread.start(); this.mHandler = new Handler(mHandlerThread.getLooper()); } + final private TextWatcher textWatcher = new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + validateInputs(); + } + }; + + private void validateInputs() { + Integer carbs = SafeParse.stringToInt(editCarbs.getText()); + if (carbs > maxCarbs) { + editCarbs.setValue(0d); + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.carbsconstraintapplied)); + } + Double insulin = SafeParse.stringToDouble(editInsulin.getText()); + if (insulin > maxInsulin) { + editInsulin.setValue(0d); + ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.bolusconstraintapplied)); + } + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -63,14 +96,14 @@ public class NewTreatmentDialog extends DialogFragment implements OnClickListene getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); - Integer maxCarbs = MainApp.getConfigBuilder().applyCarbsConstraints(Constants.carbsOnlyForCheckLimit); - Double maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); + maxCarbs = MainApp.getConfigBuilder().applyCarbsConstraints(Constants.carbsOnlyForCheckLimit); + maxInsulin = MainApp.getConfigBuilder().applyBolusConstraints(Constants.bolusOnlyForCheckLimit); editCarbs = (NumberPicker) view.findViewById(R.id.treatments_newtreatment_carbsamount); editInsulin = (NumberPicker) view.findViewById(R.id.treatments_newtreatment_insulinamount); - editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false); - editInsulin.setParams(0d, 0d, maxInsulin, MainApp.getConfigBuilder().getPumpDescription().bolusStep, new DecimalFormat("0.00"), false); + editCarbs.setParams(0d, 0d, (double) maxCarbs, 1d, new DecimalFormat("0"), false, textWatcher); + editInsulin.setParams(0d, 0d, maxInsulin, MainApp.getConfigBuilder().getPumpDescription().bolusStep, new DecimalFormat("0.00"), false, textWatcher); return view; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java index 54f526288b..308965a5ea 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Dialogs/WizardDialog.java @@ -344,7 +344,7 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com MainApp.bus().post(new EventRefreshOverview("WizardDialog")); } pump.cancelTempBasal(true); - result = pump.setTempBasalAbsolute(0d, 120); + result = pump.setTempBasalAbsolute(0d, 120, true); if (!result.success) { OKDialog.show(getActivity(), MainApp.sResources.getString(R.string.tempbasaldeliveryerror), result.comment, null); } @@ -420,15 +420,9 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com BgReading lastBg = DatabaseHelper.actualBg(); if (lastBg != null) { - editBg.removeTextChangedListener(textWatcher); - //bgInput.setText(lastBg.valueToUnitsToString(units)); editBg.setValue(lastBg.valueToUnits(units)); - editBg.addTextChangedListener(textWatcher); } else { - editBg.removeTextChangedListener(textWatcher); - //bgInput.setText(""); editBg.setValue(0d); - editBg.addTextChangedListener(textWatcher); } ttCheckbox.setEnabled(MainApp.getConfigBuilder().getTempTargetFromHistory() != null); @@ -465,19 +459,13 @@ public class WizardDialog extends DialogFragment implements OnClickListener, Com Double c_correction = SafeParse.stringToDouble(editCorr.getText()); Double corrAfterConstraint = MainApp.getConfigBuilder().applyBolusConstraints(c_correction); if (c_correction - corrAfterConstraint != 0) { // c_correction != corrAfterConstraint doesn't work - editCorr.removeTextChangedListener(textWatcher); editCorr.setValue(0d); - editCorr.addTextChangedListener(textWatcher); - //wizardDialogDeliverButton.setVisibility(Button.GONE); ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.bolusconstraintapplied)); return; } Integer carbsAfterConstraint = MainApp.getConfigBuilder().applyCarbsConstraints(c_carbs); if (c_carbs - carbsAfterConstraint != 0) { - editCarbs.removeTextChangedListener(textWatcher); editCarbs.setValue(0d); - editCarbs.addTextChangedListener(textWatcher); - //wizardDialogDeliverButton.setVisibility(Button.GONE); ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.carbsconstraintapplied)); return; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java index 0201d9cabe..a857153c73 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/Notification.java @@ -49,9 +49,9 @@ public class Notification { public static final int NSURGENTALARM = 20; public static final int SHORT_DIA = 21; public static final int TOAST_ALARM = 22; + public static final int WRONGBASALSTEP = 23; public static final int BOLUS_DELIVERY_ERROR = 24; - public int id; public Date date; public String text; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java index c331cd0445..67ab9227ed 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Overview/OverviewFragment.java @@ -121,6 +121,7 @@ import info.nightscout.androidaps.plugins.Overview.graphExtensions.FixedLineGrap import info.nightscout.androidaps.plugins.Overview.graphExtensions.PointsWithLabelGraphSeries; import info.nightscout.androidaps.plugins.Overview.graphExtensions.TimeAsXAxisLabelFormatter; import info.nightscout.androidaps.plugins.SourceXdrip.SourceXdripPlugin; +import info.nightscout.androidaps.plugins.Treatments.fragments.ProfileViewerDialog; import info.nightscout.utils.BolusWizard; import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; @@ -351,27 +352,33 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, @Override public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { super.onCreateContextMenu(menu, v, menuInfo); - final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop(); - if (activeloop == null) - return; - menu.setHeaderTitle(MainApp.sResources.getString(R.string.loop)); - if (activeloop.isEnabled(PluginBase.LOOP)) { - menu.add(MainApp.sResources.getString(R.string.disableloop)); - if (!activeloop.isSuspended()) { - menu.add(MainApp.sResources.getString(R.string.suspendloopfor1h)); - menu.add(MainApp.sResources.getString(R.string.suspendloopfor2h)); - menu.add(MainApp.sResources.getString(R.string.suspendloopfor3h)); - menu.add(MainApp.sResources.getString(R.string.suspendloopfor10h)); - menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor30m)); - menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor1h)); - menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor2h)); - menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor3h)); - } else { - menu.add(MainApp.sResources.getString(R.string.resume)); + if (v == apsModeView) { + final LoopPlugin activeloop = ConfigBuilderPlugin.getActiveLoop(); + if (activeloop == null) + return; + menu.setHeaderTitle(MainApp.sResources.getString(R.string.loop)); + if (activeloop.isEnabled(PluginBase.LOOP)) { + menu.add(MainApp.sResources.getString(R.string.disableloop)); + if (!activeloop.isSuspended()) { + menu.add(MainApp.sResources.getString(R.string.suspendloopfor1h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor2h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor3h)); + menu.add(MainApp.sResources.getString(R.string.suspendloopfor10h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor30m)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor1h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor2h)); + menu.add(MainApp.sResources.getString(R.string.disconnectpumpfor3h)); + } else { + menu.add(MainApp.sResources.getString(R.string.resume)); + } } + if (!activeloop.isEnabled(PluginBase.LOOP)) + menu.add(MainApp.sResources.getString(R.string.enableloop)); + } else if (v == activeProfileView) { + menu.setHeaderTitle(MainApp.sResources.getString(R.string.profile)); + menu.add(MainApp.sResources.getString(R.string.danar_viewprofile)); + menu.add(MainApp.sResources.getString(R.string.careportal_profileswitch)); } - if (!activeloop.isEnabled(PluginBase.LOOP)) - menu.add(MainApp.sResources.getString(R.string.enableloop)); } @Override @@ -555,6 +562,16 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, }); NSUpload.uploadOpenAPSOffline(180); return true; + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.careportal_profileswitch))) { + NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); + final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCHDIRECT; + profileswitch.executeProfileSwitch = true; + newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); + newDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); + } else if (item.getTitle().equals(MainApp.sResources.getString(R.string.danar_viewprofile))) { + ProfileViewerDialog pvd = ProfileViewerDialog.newInstance(System.currentTimeMillis()); + FragmentManager manager = getFragmentManager(); + pvd.show(manager, "ProfileViewDialog"); } return super.onContextItemSelected(item); @@ -739,6 +756,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, MainApp.bus().unregister(this); sLoopHandler.removeCallbacksAndMessages(null); unregisterForContextMenu(apsModeView); + unregisterForContextMenu(activeProfileView); } @Override @@ -754,6 +772,7 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, }; sLoopHandler.postDelayed(sRefreshLoop, 60 * 1000L); registerForContextMenu(apsModeView); + registerForContextMenu(activeProfileView); updateGUI("onResume"); } @@ -1089,27 +1108,12 @@ public class OverviewFragment extends Fragment implements View.OnClickListener, activeProfileView.setText(MainApp.getConfigBuilder().getProfileName()); activeProfileView.setBackgroundColor(Color.GRAY); - activeProfileView.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View view) { - view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); - NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); - final OptionsToShow profileswitch = CareportalFragment.profileswitch; - profileswitch.executeProfileSwitch = true; - newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); - newDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); - return true; - } - }); - activeProfileView.setLongClickable(true); - - tempTargetView.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View view) { view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); NewNSTreatmentDialog newTTDialog = new NewNSTreatmentDialog(); - final OptionsToShow temptarget = CareportalFragment.temptarget; + final OptionsToShow temptarget = CareportalFragment.TEMPTARGET; temptarget.executeTempTarget = true; newTTDialog.setOptions(temptarget, R.string.careportal_temporarytarget); newTTDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java index c7d7333aba..53ceed17a8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfileFragment.java @@ -2,11 +2,12 @@ package info.nightscout.androidaps.plugins.ProfileCircadianPercentage; import android.app.Activity; +import android.app.AlertDialog; import android.content.Context; +import android.content.DialogInterface; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v4.app.DialogFragment; -import android.support.v4.app.Fragment; import android.support.v4.content.ContextCompat; import android.text.Editable; import android.text.Html; @@ -33,7 +34,6 @@ import org.slf4j.LoggerFactory; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.events.EventInitializationChanged; -import info.nightscout.androidaps.events.EventNewBasalProfile; import info.nightscout.androidaps.events.EventProfileSwitchChange; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Careportal.CareportalFragment; @@ -125,6 +125,9 @@ public class CircadianPercentageProfileFragment extends SubscriberFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + + showDeprecatedDialog(); + View layout = inflater.inflate(R.layout.circadianpercentageprofile_fragment, container, false); fl = (FrameLayout) layout.findViewById(R.id.circadianpercentageprofile_framelayout); fl.requestFocusFromTouch(); @@ -178,7 +181,7 @@ public class CircadianPercentageProfileFragment extends SubscriberFragment { @Override public void onClick(View view) { NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); - final OptionsToShow profileswitch = CareportalFragment.profileswitch; + final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCHDIRECT; profileswitch.executeProfileSwitch = true; newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); newDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); @@ -232,7 +235,7 @@ public class CircadianPercentageProfileFragment extends SubscriberFragment { } }); - timeshiftView.setOnFocusChangeListener(new View.OnFocusChangeListener() { + /*timeshiftView.setOnFocusChangeListener(new View.OnFocusChangeListener() { @Override public void onFocusChange(View view, boolean hasFocus) { @@ -268,7 +271,7 @@ public class CircadianPercentageProfileFragment extends SubscriberFragment { } } } - }); + });*/ diaView.setOnFocusChangeListener(new View.OnFocusChangeListener() { @@ -317,6 +320,25 @@ public class CircadianPercentageProfileFragment extends SubscriberFragment { return layout; } + private void showDeprecatedDialog() { + AlertDialog.Builder adb = new AlertDialog.Builder(getContext()); + adb.setTitle("DEPRECATED! Please migrate!"); + adb.setMessage("CircadianPercentageProfile has been deprecated. " + + "It is recommended to migrate to LocalProfile.\n\n" + + "Good news: You won't lose any functionality! Percentage and Timeshift have been ported to the ProfileSwitch :) \n\n " + + "How to migrate:\n" + + "1) Press MIGRATE, the system will automatically fill the LocalProfile for you.\n" + + "2) Switch to LocalProfile in the ConfigBuilder\n" + + "3) CHECK that all settings are correct in the LocalProfile!!!"); + adb.setIcon(android.R.drawable.ic_dialog_alert); + adb.setPositiveButton("MIGRATE", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + CircadianPercentageProfilePlugin.migrateToLP(); + } }); + adb.setNegativeButton("Cancel", null); + adb.show(); + } + public void updateGUI() { updateProfileInfo(); @@ -502,11 +524,7 @@ public class CircadianPercentageProfileFragment extends SubscriberFragment { public void run() { if (!MainApp.getConfigBuilder().isInitialized() || MainApp.getConfigBuilder().isSuspended()) { profileswitchButton.setVisibility(View.GONE); - } else if (!MainApp.getConfigBuilder().getPumpDescription().isSetBasalProfileCapable) { - profileswitchButton.setText(MainApp.instance().getText(R.string.activate_profile)); - profileswitchButton.setVisibility(View.VISIBLE); } else { - profileswitchButton.setText(MainApp.instance().getText(R.string.send_to_pump)); profileswitchButton.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java index e88089fdb7..62b0326eae 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileCircadianPercentage/CircadianPercentageProfilePlugin.java @@ -21,6 +21,8 @@ import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; +import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; +import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.NSUpload; import info.nightscout.utils.SP; @@ -199,7 +201,7 @@ public class CircadianPercentageProfilePlugin implements PluginBase, ProfileInte //send profile to pumpe new NewNSTreatmentDialog(); //init - NewNSTreatmentDialog.doProfileSwitch(this.getProfile(), this.getProfileName(), 0); + NewNSTreatmentDialog.doProfileSwitch(this.getProfile(), this.getProfileName(), 0, percentage, timeshift); //return formatted string /*msg += "%: " + this.percentage + " h: +" + this.timeshift; @@ -211,6 +213,91 @@ public class CircadianPercentageProfilePlugin implements PluginBase, ProfileInte return msg; } + public static void migrateToLP(){ + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); + SharedPreferences.Editor editor = settings.edit(); + editor.putBoolean("LocalProfile" + "mmol", SP.getBoolean(SETTINGS_PREFIX + "mmol", false)); + editor.putBoolean("LocalProfile" + "mgdl", SP.getBoolean(SETTINGS_PREFIX + "mgdl", true)); + editor.putString("LocalProfile" + "dia", "" + SP.getDouble(SETTINGS_PREFIX + "dia", Constants.defaultDIA)); + editor.putString("LocalProfile" + "ic", getLPic()); + editor.putString("LocalProfile" + "isf", getLPisf()); + editor.putString("LocalProfile" + "basal", getLPbasal()); + try { + JSONArray targetLow = new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", SP.getDouble(SETTINGS_PREFIX + "targetlow", 120d))); + JSONArray targetHigh = new JSONArray().put(new JSONObject().put("time", "00:00").put("timeAsSeconds", 0).put("value", SP.getDouble(SETTINGS_PREFIX + "targethigh", 120d))); + editor.putString("LocalProfile" + "targetlow", targetLow.toString()); + editor.putString("LocalProfile" + "targethigh", targetHigh.toString()); + } catch (JSONException e) { + e.printStackTrace(); + } + editor.commit(); + LocalProfilePlugin lp = MainApp.getSpecificPlugin(LocalProfilePlugin.class); + lp.loadSettings(); + + /* TODO: remove Settings and switch to LP later on + * For now only nag the user every time (s)he opens the CPP fragment and offer to migrate. + * Keep settings for now in order to allow the user to check that the migration went well. + */ + //removeSettings(); + + } + + public static String getLPisf(){ + return getLPConversion("baseisf", 35d); + } + + public static String getLPic(){ + return getLPConversion("baseic", 4); + } + + public static String getLPbasal(){ + return getLPConversion("basebasal", 1); + } + + public static String getLPConversion(String type, double defaultValue){ + try { + JSONArray jsonArray = new JSONArray(); + double last = -1d; + + for (int i = 0; i < 24; i++) { + double value = SP.getDouble(SETTINGS_PREFIX + type + i, defaultValue); + String time; + DecimalFormat df = new DecimalFormat("00"); + time = df.format(i) + ":00"; + if(last != value) { + jsonArray.put(new JSONObject().put("time", time).put("timeAsSeconds", i * 60 * 60).put("value", value)); + } + last = value; + } + return jsonArray.toString(); + } catch (JSONException e) { + log.error("Unhandled exception", e); + } + return LocalProfilePlugin.DEFAULTARRAY; + } + + static void removeSettings() { + if (Config.logPrefsChange) + log.debug("Removing settings"); + SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); + SharedPreferences.Editor editor = settings.edit(); + editor.remove(SETTINGS_PREFIX + "mmol"); + editor.remove(SETTINGS_PREFIX + "mgdl"); + editor.remove(SETTINGS_PREFIX + "dia"); + editor.remove(SETTINGS_PREFIX + "targetlow"); + editor.remove(SETTINGS_PREFIX + "targethigh"); + editor.remove(SETTINGS_PREFIX + "timeshift"); + editor.remove(SETTINGS_PREFIX + "percentage"); + + + for (int i = 0; i < 24; i++) { + editor.remove(SETTINGS_PREFIX + "basebasal"); + editor.remove(SETTINGS_PREFIX + "baseisf" + i); + editor.remove(SETTINGS_PREFIX + "baseic" + i); + } + editor.commit(); + } + private void createConvertedProfile() { JSONObject json = new JSONObject(); JSONObject store = new JSONObject(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java index e491a41b1b..24965861df 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfileFragment.java @@ -3,16 +3,16 @@ package info.nightscout.androidaps.plugins.ProfileLocal; import android.app.Activity; import android.os.Bundle; -import android.support.v4.app.Fragment; +import android.support.annotation.NonNull; import android.text.Editable; import android.text.TextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; -import android.widget.EditText; import android.widget.RadioButton; +import com.crashlytics.android.Crashlytics; import com.squareup.otto.Subscribe; import org.slf4j.Logger; @@ -28,6 +28,8 @@ import info.nightscout.androidaps.plugins.Careportal.CareportalFragment; import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.Careportal.OptionsToShow; import info.nightscout.androidaps.plugins.Common.SubscriberFragment; +import info.nightscout.utils.DecimalFormatter; +import info.nightscout.utils.NumberPicker; import info.nightscout.utils.SafeParse; import info.nightscout.utils.TimeListEdit; @@ -40,7 +42,7 @@ public class LocalProfileFragment extends SubscriberFragment { return localProfilePlugin; } - EditText diaView; + NumberPicker diaView; RadioButton mgdlView; RadioButton mmolView; TimeListEdit icView; @@ -52,88 +54,101 @@ public class LocalProfileFragment extends SubscriberFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - Runnable save = new Runnable() { - @Override - public void run() { - localProfilePlugin.storeSettings(); + try { + Runnable save = new Runnable() { + @Override + public void run() { + localProfilePlugin.storeSettings(); + if(basalView!=null){ + basalView.updateLabel(MainApp.sResources.getString(R.string.nsprofileview_basal_label)+ ": "+ getSumLabel()); + } + } + }; + + TextWatcher textWatch = new TextWatcher() { + + @Override + public void afterTextChanged(Editable s) { + } + + @Override + public void beforeTextChanged(CharSequence s, int start, + int count, int after) { + } + + @Override + public void onTextChanged(CharSequence s, int start, + int before, int count) { + localProfilePlugin.dia = SafeParse.stringToDouble(diaView.getText().toString()); + localProfilePlugin.storeSettings(); + } + }; + + View layout = inflater.inflate(R.layout.localprofile_fragment, container, false); + diaView = (NumberPicker) layout.findViewById(R.id.localprofile_dia); + diaView.setParams(localProfilePlugin.dia, 2d, 48d, 0.1d, new DecimalFormat("0.0"), false, textWatch); + mgdlView = (RadioButton) layout.findViewById(R.id.localprofile_mgdl); + mmolView = (RadioButton) layout.findViewById(R.id.localprofile_mmol); + icView = new TimeListEdit(getContext(), layout, R.id.localprofile_ic, MainApp.sResources.getString(R.string.nsprofileview_ic_label) + ":", getPlugin().ic, null, 0.1d, new DecimalFormat("0.0"), save); + isfView = new TimeListEdit(getContext(), layout, R.id.localprofile_isf, MainApp.sResources.getString(R.string.nsprofileview_isf_label) + ":", getPlugin().isf, null, 0.1d, new DecimalFormat("0.0"), save); + basalView = new TimeListEdit(getContext(), layout, R.id.localprofile_basal, MainApp.sResources.getString(R.string.nsprofileview_basal_label)+ ": " + getSumLabel(), getPlugin().basal, null, 0.01d, new DecimalFormat("0.00"), save); + targetView = new TimeListEdit(getContext(), layout, R.id.localprofile_target, MainApp.sResources.getString(R.string.nsprofileview_target_label)+ ":", getPlugin().targetLow, getPlugin().targetHigh, 0.1d, new DecimalFormat("0.0"), save); + profileswitchButton = (Button) layout.findViewById(R.id.localprofile_profileswitch); + + PumpInterface pump = MainApp.getConfigBuilder(); + if (!pump.getPumpDescription().isTempBasalCapable) { + layout.findViewById(R.id.localprofile_basal).setVisibility(View.GONE); } - }; - View layout = inflater.inflate(R.layout.localprofile_fragment, container, false); - diaView = (EditText) layout.findViewById(R.id.localprofile_dia); - mgdlView = (RadioButton) layout.findViewById(R.id.localprofile_mgdl); - mmolView = (RadioButton) layout.findViewById(R.id.localprofile_mmol); - icView = new TimeListEdit(getContext(), layout, R.id.localprofile_ic, MainApp.sResources.getString(R.string.nsprofileview_ic_label), getPlugin().ic, null, new DecimalFormat("0.0"), save); - isfView = new TimeListEdit(getContext(), layout, R.id.localprofile_isf, MainApp.sResources.getString(R.string.nsprofileview_isf_label), getPlugin().isf, null, new DecimalFormat("0.0"), save); - basalView = new TimeListEdit(getContext(), layout, R.id.localprofile_basal, MainApp.sResources.getString(R.string.nsprofileview_basal_label), getPlugin().basal, null, new DecimalFormat("0.00"), save); - targetView = new TimeListEdit(getContext(), layout, R.id.localprofile_target, MainApp.sResources.getString(R.string.nsprofileview_target_label), getPlugin().targetLow, getPlugin().targetHigh, new DecimalFormat("0.0"), save); - profileswitchButton = (Button) layout.findViewById(R.id.localprofile_profileswitch); + updateGUI(); - PumpInterface pump = MainApp.getConfigBuilder(); - if (!pump.getPumpDescription().isTempBasalCapable) { - layout.findViewById(R.id.localprofile_basal).setVisibility(View.GONE); + mgdlView.setChecked(localProfilePlugin.mgdl); + mmolView.setChecked(localProfilePlugin.mmol); + + mgdlView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + localProfilePlugin.mgdl = mgdlView.isChecked(); + localProfilePlugin.mmol = !localProfilePlugin.mgdl; + mmolView.setChecked(localProfilePlugin.mmol); + localProfilePlugin.storeSettings(); + } + }); + mmolView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + localProfilePlugin.mmol = mmolView.isChecked(); + localProfilePlugin.mgdl = !localProfilePlugin.mmol; + mgdlView.setChecked(localProfilePlugin.mgdl); + localProfilePlugin.storeSettings(); + } + }); + + profileswitchButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); + final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCHDIRECT; + profileswitch.executeProfileSwitch = true; + newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); + newDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); + } + }); + + + updateGUI(); + return layout; + } catch (Exception e) { + log.error("Unhandled exception: ", e); + Crashlytics.logException(e); } - updateGUI(); + return null; + } - mgdlView.setChecked(localProfilePlugin.mgdl); - mmolView.setChecked(localProfilePlugin.mmol); - diaView.setText(localProfilePlugin.dia.toString()); - - mgdlView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - localProfilePlugin.mgdl = mgdlView.isChecked(); - localProfilePlugin.mmol = !localProfilePlugin.mgdl; - mmolView.setChecked(localProfilePlugin.mmol); - localProfilePlugin.storeSettings(); - } - }); - mmolView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - localProfilePlugin.mmol = mmolView.isChecked(); - localProfilePlugin.mgdl = !localProfilePlugin.mmol; - mgdlView.setChecked(localProfilePlugin.mgdl); - localProfilePlugin.storeSettings(); - } - }); - - profileswitchButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); - final OptionsToShow profileswitch = CareportalFragment.profileswitch; - profileswitch.executeProfileSwitch = true; - newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); - newDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); - } - }); - - TextWatcher textWatch = new TextWatcher() { - - @Override - public void afterTextChanged(Editable s) { - } - - @Override - public void beforeTextChanged(CharSequence s, int start, - int count, int after) { - } - - @Override - public void onTextChanged(CharSequence s, int start, - int before, int count) { - localProfilePlugin.dia = SafeParse.stringToDouble(diaView.getText().toString()); - localProfilePlugin.storeSettings(); - } - }; - - diaView.addTextChangedListener(textWatch); - - updateGUI(); - - return layout; + @NonNull + public String getSumLabel() { + return " ∑" + DecimalFormatter.to2Decimal(localProfilePlugin.getProfile().getDefaultProfile().baseBasalSum()) +"U"; } @Subscribe @@ -150,11 +165,7 @@ public class LocalProfileFragment extends SubscriberFragment { public void run() { if (!MainApp.getConfigBuilder().isInitialized() || MainApp.getConfigBuilder().isSuspended()) { profileswitchButton.setVisibility(View.GONE); - } else if (!MainApp.getConfigBuilder().getPumpDescription().isSetBasalProfileCapable) { - profileswitchButton.setText(MainApp.instance().getText(R.string.activate_profile)); - profileswitchButton.setVisibility(View.VISIBLE); } else { - profileswitchButton.setText(MainApp.instance().getText(R.string.send_to_pump)); profileswitchButton.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfilePlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfilePlugin.java index 5b7cdcac5d..db22677a82 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfilePlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileLocal/LocalProfilePlugin.java @@ -16,21 +16,23 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.data.ProfileStore; +import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.SP; /** * Created by mike on 05.08.2016. */ public class LocalProfilePlugin implements PluginBase, ProfileInterface { + public static final String LOCAL_PROFILE = "LocalProfile"; private static Logger log = LoggerFactory.getLogger(LocalProfilePlugin.class); private boolean fragmentEnabled = false; private boolean fragmentVisible = true; - private static ProfileStore convertedProfile = null; - private static String convertedProfileName = null; + private ProfileStore convertedProfile = null; + private String convertedProfileName = null; - final private String DEFAULTARRAY = "[{\"time\":\"00:00\",\"timeAsSeconds\":0,\"value\":0}]"; + public static final String DEFAULTARRAY = "[{\"time\":\"00:00\",\"timeAsSeconds\":0,\"value\":0}]"; boolean mgdl; boolean mmol; @@ -107,68 +109,68 @@ public class LocalProfilePlugin implements PluginBase, ProfileInterface { } public void storeSettings() { - if (Config.logPrefsChange) - log.debug("Storing settings"); SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApp.instance().getApplicationContext()); SharedPreferences.Editor editor = settings.edit(); - editor.putBoolean("LocalProfile" + "mmol", mmol); - editor.putBoolean("LocalProfile" + "mgdl", mgdl); - editor.putString("LocalProfile" + "dia", dia.toString()); - editor.putString("LocalProfile" + "ic", ic.toString()); - editor.putString("LocalProfile" + "isf", isf.toString()); - editor.putString("LocalProfile" + "basal", basal.toString()); - editor.putString("LocalProfile" + "targetlow", targetLow.toString()); - editor.putString("LocalProfile" + "targethigh", targetHigh.toString()); + editor.putBoolean(LOCAL_PROFILE + "mmol", mmol); + editor.putBoolean(LOCAL_PROFILE + "mgdl", mgdl); + editor.putString(LOCAL_PROFILE + "dia", dia.toString()); + editor.putString(LOCAL_PROFILE + "ic", ic.toString()); + editor.putString(LOCAL_PROFILE + "isf", isf.toString()); + editor.putString(LOCAL_PROFILE + "basal", basal.toString()); + editor.putString(LOCAL_PROFILE + "targetlow", targetLow.toString()); + editor.putString(LOCAL_PROFILE + "targethigh", targetHigh.toString()); - editor.commit(); + editor.apply(); createConvertedProfile(); + if (Config.logPrefsChange) + log.debug("Storing settings: " + getProfile().getData().toString()); } - private void loadSettings() { + public void loadSettings() { if (Config.logPrefsChange) log.debug("Loading stored settings"); - mgdl = SP.getBoolean("LocalProfile" + "mgdl", false); - mmol = SP.getBoolean("LocalProfile" + "mmol", true); - dia = SP.getDouble("LocalProfile" + "dia", Constants.defaultDIA); + mgdl = SP.getBoolean(LOCAL_PROFILE + "mgdl", false); + mmol = SP.getBoolean(LOCAL_PROFILE + "mmol", true); + dia = SP.getDouble(LOCAL_PROFILE + "dia", Constants.defaultDIA); try { - ic = new JSONArray(SP.getString("LocalProfile" + "ic", DEFAULTARRAY)); + ic = new JSONArray(SP.getString(LOCAL_PROFILE + "ic", DEFAULTARRAY)); } catch (JSONException e1) { try { ic = new JSONArray(DEFAULTARRAY); - } catch (JSONException e2) { + } catch (JSONException ignored) { } } try { - isf = new JSONArray(SP.getString("LocalProfile" + "isf", DEFAULTARRAY)); + isf = new JSONArray(SP.getString(LOCAL_PROFILE + "isf", DEFAULTARRAY)); } catch (JSONException e1) { try { isf = new JSONArray(DEFAULTARRAY); - } catch (JSONException e2) { + } catch (JSONException ignored) { } } try { - basal = new JSONArray(SP.getString("LocalProfile" + "basal", DEFAULTARRAY)); + basal = new JSONArray(SP.getString(LOCAL_PROFILE + "basal", DEFAULTARRAY)); } catch (JSONException e1) { try { basal = new JSONArray(DEFAULTARRAY); - } catch (JSONException e2) { + } catch (JSONException ignored) { } } try { - targetLow = new JSONArray(SP.getString("LocalProfile" + "targetlow", DEFAULTARRAY)); + targetLow = new JSONArray(SP.getString(LOCAL_PROFILE + "targetlow", DEFAULTARRAY)); } catch (JSONException e1) { try { targetLow = new JSONArray(DEFAULTARRAY); - } catch (JSONException e2) { + } catch (JSONException ignored) { } } try { - targetHigh = new JSONArray(SP.getString("LocalProfile" + "targethigh", DEFAULTARRAY)); + targetHigh = new JSONArray(SP.getString(LOCAL_PROFILE + "targethigh", DEFAULTARRAY)); } catch (JSONException e1) { try { targetHigh = new JSONArray(DEFAULTARRAY); - } catch (JSONException e2) { + } catch (JSONException ignored) { } } createConvertedProfile(); @@ -212,13 +214,13 @@ public class LocalProfilePlugin implements PluginBase, ProfileInterface { "created_at": "2016-06-16T08:34:41.256Z" } */ - void createConvertedProfile() { + private void createConvertedProfile() { JSONObject json = new JSONObject(); JSONObject store = new JSONObject(); JSONObject profile = new JSONObject(); try { - json.put("defaultProfile", "LocalProfile"); + json.put("defaultProfile", LOCAL_PROFILE); json.put("store", store); profile.put("dia", dia); profile.put("carbratio", ic); @@ -227,12 +229,12 @@ public class LocalProfilePlugin implements PluginBase, ProfileInterface { profile.put("target_low", targetLow); profile.put("target_high", targetHigh); profile.put("units", mgdl ? Constants.MGDL : Constants.MMOL); - store.put("LocalProfile", profile); + store.put(LOCAL_PROFILE, profile); } catch (JSONException e) { log.error("Unhandled exception", e); } convertedProfile = new ProfileStore(json); - convertedProfileName = "LocalProfile"; + convertedProfileName = LOCAL_PROFILE; } @Override @@ -247,7 +249,7 @@ public class LocalProfilePlugin implements PluginBase, ProfileInterface { @Override public String getProfileName() { - return convertedProfileName; + return DecimalFormatter.to2Decimal(convertedProfile.getDefaultProfile().percentageBasalSum()) + "U "; } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileNS/NSProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileNS/NSProfileFragment.java index 4c4fea419c..546a232ca4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileNS/NSProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileNS/NSProfileFragment.java @@ -5,19 +5,27 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.Spinner; import android.widget.TextView; import com.crashlytics.android.Crashlytics; import com.squareup.otto.Subscribe; +import java.util.ArrayList; + import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.androidaps.plugins.Common.SubscriberFragment; import info.nightscout.androidaps.plugins.ProfileNS.events.EventNSProfileUpdateGUI; import info.nightscout.utils.DecimalFormatter; -public class NSProfileFragment extends SubscriberFragment { + +public class NSProfileFragment extends SubscriberFragment implements AdapterView.OnItemSelectedListener { + private Spinner profileSpinner; private TextView noProfile; private TextView units; private TextView dia; @@ -31,8 +39,9 @@ public class NSProfileFragment extends SubscriberFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { try { - View layout = inflater.inflate(R.layout.nsprofileviewer_fragment, container, false); + View layout = inflater.inflate(R.layout.nsprofile_fragment, container, false); + profileSpinner = (Spinner) layout.findViewById(R.id.nsprofile_spinner); noProfile = (TextView) layout.findViewById(R.id.profileview_noprofile); units = (TextView) layout.findViewById(R.id.profileview_units); dia = (TextView) layout.findViewById(R.id.profileview_dia); @@ -42,6 +51,8 @@ public class NSProfileFragment extends SubscriberFragment { basal = (TextView) layout.findViewById(R.id.profileview_basal); target = (TextView) layout.findViewById(R.id.profileview_target); + profileSpinner.setOnItemSelectedListener(this); + updateGUI(); return layout; } catch (Exception e) { @@ -72,14 +83,42 @@ public class NSProfileFragment extends SubscriberFragment { noProfile.setVisibility(View.GONE); } - Profile profile = MainApp.getConfigBuilder().getProfile(); + ProfileStore profileStore = NSProfilePlugin.getPlugin().getProfile(); + ArrayList profileList = profileStore.getProfileList(); + ArrayAdapter adapter = new ArrayAdapter<>(getContext(), + R.layout.spinner_centered, profileList); + profileSpinner.setAdapter(adapter); + // set selected to actual profile + for (int p = 0; p < profileList.size(); p++) { + if (profileList.get(p).equals(MainApp.getConfigBuilder().getProfileName())) + profileSpinner.setSelection(p); + } + + } + + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + String name = parent.getItemAtPosition(position).toString(); + + Profile profile = NSProfilePlugin.getPlugin().getProfile().getSpecificProfile(name); units.setText(profile.getUnits()); dia.setText(DecimalFormatter.to2Decimal(profile.getDia()) + " h"); - activeProfile.setText(MainApp.getConfigBuilder().getProfileName()); + activeProfile.setText(name); ic.setText(profile.getIcList()); isf.setText(profile.getIsfList()); basal.setText(profile.getBasalList()); target.setText(profile.getTargetList()); } + @Override + public void onNothingSelected(AdapterView parent) { + noProfile.setVisibility(View.VISIBLE); + units.setText(""); + dia.setText(""); + activeProfile.setText(""); + ic.setText(""); + isf.setText(""); + basal.setText(""); + target.setText(""); + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileSimple/SimpleProfileFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileSimple/SimpleProfileFragment.java index b6d24741a0..88057a68c1 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/ProfileSimple/SimpleProfileFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/ProfileSimple/SimpleProfileFragment.java @@ -96,7 +96,7 @@ public class SimpleProfileFragment extends SubscriberFragment { @Override public void onClick(View view) { NewNSTreatmentDialog newDialog = new NewNSTreatmentDialog(); - final OptionsToShow profileswitch = CareportalFragment.profileswitch; + final OptionsToShow profileswitch = CareportalFragment.PROFILESWITCH; profileswitch.executeProfileSwitch = true; newDialog.setOptions(profileswitch, R.string.careportal_profileswitch); newDialog.show(getFragmentManager(), "NewNSTreatmentDialog"); @@ -158,11 +158,7 @@ public class SimpleProfileFragment extends SubscriberFragment { public void run() { if (!MainApp.getConfigBuilder().isInitialized() || MainApp.getConfigBuilder().isSuspended()) { profileswitchButton.setVisibility(View.GONE); - } else if (!MainApp.getConfigBuilder().getPumpDescription().isSetBasalProfileCapable) { - profileswitchButton.setText(MainApp.instance().getText(R.string.activate_profile)); - profileswitchButton.setVisibility(View.VISIBLE); } else { - profileswitchButton.setText(MainApp.instance().getText(R.string.send_to_pump)); profileswitchButton.setVisibility(View.VISIBLE); } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java index c5c87f194e..d48013b0e6 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRFragment.java @@ -12,6 +12,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; +import android.widget.LinearLayout; import android.widget.TextView; import com.crashlytics.android.Crashlytics; @@ -56,10 +57,21 @@ public class DanaRFragment extends SubscriberFragment { TextView firmwareView; TextView basalStepView; TextView bolusStepView; + TextView serialNumberView; Button viewProfileButton; Button historyButton; Button statsButton; + LinearLayout pumpStatusLayout; + TextView pumpStatusView; + + static Runnable connectRunnable = new Runnable() { + @Override + public void run() { + MainApp.getConfigBuilder().refreshDataFromPump("Connect request from GUI"); + } + }; + public DanaRFragment() { if (sHandlerThread == null) { @@ -105,7 +117,11 @@ public class DanaRFragment extends SubscriberFragment { statsButton = (Button) view.findViewById(R.id.danar_stats); basalStepView = (TextView) view.findViewById(R.id.danar_basalstep); bolusStepView = (TextView) view.findViewById(R.id.danar_bolusstep); + serialNumberView = (TextView) view.findViewById(R.id.danar_serialnumber); + pumpStatusView = (TextView) view.findViewById(R.id.overview_pumpstatus); + pumpStatusView.setBackgroundColor(MainApp.sResources.getColor(R.color.colorInitializingBorder)); + pumpStatusLayout = (LinearLayout) view.findViewById(R.id.overview_pumpstatuslayout); viewProfileButton.setOnClickListener(new View.OnClickListener() { @Override @@ -133,13 +149,8 @@ public class DanaRFragment extends SubscriberFragment { btConnectionView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - sHandler.post(new Runnable() { - @Override - public void run() { - MainApp.getConfigBuilder().refreshDataFromPump("Connect request from GUI"); - } - } - ); + log.debug("Clicked connect to pump"); + sHandler.post(connectRunnable); } }); @@ -155,6 +166,7 @@ public class DanaRFragment extends SubscriberFragment { @Subscribe public void onStatusEvent(final EventPumpStatusChanged c) { Activity activity = getActivity(); + final String status = c.textStatus(); if (activity != null) { activity.runOnUiThread( new Runnable() { @@ -166,6 +178,13 @@ public class DanaRFragment extends SubscriberFragment { btConnectionView.setText("{fa-bluetooth}"); else if (c.sStatus == EventPumpStatusChanged.DISCONNECTED) btConnectionView.setText("{fa-bluetooth-b}"); + + if (!status.equals("")) { + pumpStatusView.setText(status); + pumpStatusLayout.setVisibility(View.VISIBLE); + } else { + pumpStatusLayout.setVisibility(View.GONE); + } } } ); @@ -246,6 +265,7 @@ public class DanaRFragment extends SubscriberFragment { } basalStepView.setText("" + pump.basalStep); bolusStepView.setText("" + pump.bolusStep); + serialNumberView.setText("" + pump.serialNumber); } }); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java index 7ea3308469..65dd5192e4 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/DanaRPlugin.java @@ -342,7 +342,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C // This is called from APS @Override - public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { // Recheck pump status if older than 30 min if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { doConnect("setTempBasalAbsolute old data"); @@ -408,7 +408,7 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C if (Config.logPumpActions) log.debug("setTempBasalAbsolute: currently running: " + running.toString()); if (running.percentRate == percentRate) { - if (force) { + if (enforceNew) { cancelTempBasal(true); } else { result.success = true; @@ -649,7 +649,11 @@ public class DanaRPlugin implements PluginBase, PumpInterface, DanaRInterface, C } public static void doConnect(String from) { - if (sExecutionService != null) sExecutionService.connect(from); + if (sExecutionService != null) { + sExecutionService.connect(from); + pumpDescription.basalStep = pump.basalStep; + pumpDescription.bolusStep = pump.bolusStep; + } } public static boolean isConnected() { 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..9f88011c96 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 @@ -9,8 +9,10 @@ import org.slf4j.LoggerFactory; import java.text.DecimalFormat; import java.util.Date; +import info.nightscout.androidaps.Config; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.data.ProfileStore; import info.nightscout.utils.SP; @@ -52,6 +54,7 @@ public class DanaRPump { public static final int PRIME = 12; public static final int PROFILECHANGE = 13; public static final int CARBS = 14; + public static final int PRIMECANNULA = 15; public Date lastConnection = new Date(0); public Date lastSettingsRead = new Date(0); @@ -78,10 +81,12 @@ 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; - public double basalStep; + public double bolusStep = 0.1; + public double basalStep = 0.1; public double iob; @@ -108,6 +113,7 @@ public class DanaRPump { public int extendedBolusSoFarInMinutes; public Date extendedBolusStart; public int extendedBolusRemainingMinutes; + public double extendedBolusDeliveredSoFar; //RS only // Profile public int units; @@ -136,6 +142,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; } @@ -205,4 +232,17 @@ public class DanaRPump { return PROFILE_PREFIX + (activeProfile + 1); } + public static double[] buildDanaRProfileRecord(Profile nsProfile) { + double[] record = new double[24]; + for (Integer hour = 0; hour < 24; hour++) { + //Some values get truncated to the next lower one. + // -> round them to two decimals and make sure we are a small delta larger (that will get truncated) + double value = Math.round(100d * nsProfile.getBasal((Integer) (hour * 60 * 60)))/100d + 0.00001; + if (Config.logDanaMessageDetail) + log.debug("NS basal value for " + hour + ":00 is " + value); + record[hour] = value; + } + return record; + } + } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/Dialogs/ProfileViewDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/Dialogs/ProfileViewDialog.java index a20934fdb7..fc7a9a2411 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/Dialogs/ProfileViewDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/Dialogs/ProfileViewDialog.java @@ -57,7 +57,7 @@ public class ProfileViewDialog extends DialogFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.nsprofileviewer_fragment, container, false); + View layout = inflater.inflate(R.layout.profileviewer_fragment, container, false); noProfile = (TextView) layout.findViewById(R.id.profileview_noprofile); units = (TextView) layout.findViewById(R.id.profileview_units); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRHistoryActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRHistoryActivity.java index 5fc022bcc6..0612b9e1c3 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRHistoryActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRHistoryActivity.java @@ -42,6 +42,7 @@ import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionServi import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus; import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin; +import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.ToastUtils; @@ -122,6 +123,7 @@ public class DanaRHistoryActivity extends Activity { statusView.setVisibility(View.GONE); boolean isKorean = MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isEnabled(PluginBase.PUMP); + boolean isRS = MainApp.getSpecificPlugin(DanaRSPlugin.class).isEnabled(PluginBase.PUMP); // Types @@ -132,8 +134,12 @@ public class DanaRHistoryActivity extends Activity { typeList.add(new TypeList(RecordTypes.RECORD_TYPE_CARBO, getString(R.string.danar_history_carbohydrates))); typeList.add(new TypeList(RecordTypes.RECORD_TYPE_DAILY, getString(R.string.danar_history_dailyinsulin))); typeList.add(new TypeList(RecordTypes.RECORD_TYPE_GLUCOSE, getString(R.string.danar_history_glucose))); - if (!isKorean) { + if (!isKorean && !isRS) { typeList.add(new TypeList(RecordTypes.RECORD_TYPE_ERROR, getString(R.string.danar_history_errors))); + } + if (isRS) + typeList.add(new TypeList(RecordTypes.RECORD_TYPE_PRIME, getString(R.string.danar_history_prime))); + if (!isKorean) { typeList.add(new TypeList(RecordTypes.RECORD_TYPE_REFILL, getString(R.string.danar_history_refill))); typeList.add(new TypeList(RecordTypes.RECORD_TYPE_SUSPEND, getString(R.string.danar_history_syspend))); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRStatsActivity.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRStatsActivity.java index fbe828a25f..5240005dc0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRStatsActivity.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/activities/DanaRStatsActivity.java @@ -1,16 +1,11 @@ package info.nightscout.androidaps.plugins.PumpDanaR.activities; import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; import android.graphics.Color; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; -import android.os.IBinder; import android.support.v7.widget.LinearLayoutManager; import android.text.TextUtils; import android.view.KeyEvent; @@ -42,16 +37,14 @@ import java.util.List; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.db.DanaRHistoryRecord; import info.nightscout.androidaps.events.EventPumpStatusChanged; import info.nightscout.androidaps.interfaces.DanaRInterface; -import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin; -import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfilePlugin; import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus; -import info.nightscout.androidaps.plugins.PumpDanaR.services.DanaRExecutionService; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.SP; import info.nightscout.utils.SafeParse; @@ -134,15 +127,14 @@ public class DanaRStatsActivity extends Activity { llm = new LinearLayoutManager(this); TBB = SP.getString("TBB", "10.00"); - totalBaseBasal.setText(TBB); - ProfileInterface pi = ConfigBuilderPlugin.getActiveProfileInterface(); - if (pi != null && pi instanceof CircadianPercentageProfilePlugin) { - double cppTBB = ((CircadianPercentageProfilePlugin) pi).baseBasalSum(); - totalBaseBasal.setText(decimalFormat.format(cppTBB)); - SP.putString("TBB", totalBaseBasal.getText().toString()); - TBB = SP.getString("TBB", ""); + Profile profile = MainApp.getConfigBuilder().getProfile(); + if (profile != null) { + double cppTBB = profile.baseBasalSum(); + TBB = decimalFormat.format(cppTBB); + SP.putString("TBB", TBB); } + totalBaseBasal.setText(TBB); // stats table tl = (TableLayout) findViewById(R.id.main_table); @@ -241,7 +233,7 @@ public class DanaRStatsActivity extends Activity { reloadButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - final PumpInterface pump = MainApp.getConfigBuilder().getActivePump(); + final PumpInterface pump = ConfigBuilderPlugin.getActivePump(); if (pump.isBusy()) { ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), getString(R.string.pumpbusy)); return; @@ -258,7 +250,7 @@ public class DanaRStatsActivity extends Activity { statsMessage.setText(getString(R.string.danar_stats_warning_Message)); } }); - ((DanaRInterface)pump).loadHistory(RecordTypes.RECORD_TYPE_DAILY); + ((DanaRInterface) pump).loadHistory(RecordTypes.RECORD_TYPE_DAILY); loadDataFromDB(RecordTypes.RECORD_TYPE_DAILY); runOnUiThread(new Runnable() { @Override @@ -311,15 +303,15 @@ public class DanaRStatsActivity extends Activity { //fill single gaps dummies = new LinkedList(); DateFormat df = new SimpleDateFormat("dd.MM."); - for(int i = 0; i < historyList.size()-1; i++){ + for (int i = 0; i < historyList.size() - 1; i++) { DanaRHistoryRecord elem1 = historyList.get(i); - DanaRHistoryRecord elem2 = historyList.get(i+1); + DanaRHistoryRecord elem2 = historyList.get(i + 1); - if (!df.format(new Date(elem1.recordDate)).equals(df.format(new Date(elem2.recordDate + 25*60*60*1000)))){ + if (!df.format(new Date(elem1.recordDate)).equals(df.format(new Date(elem2.recordDate + 25 * 60 * 60 * 1000)))) { DanaRHistoryRecord dummy = new DanaRHistoryRecord(); - dummy.recordDate = elem1.recordDate - 24*60*60*1000; - dummy.recordDailyBasal = elem1.recordDailyBasal/2; - dummy.recordDailyBolus = elem1.recordDailyBolus/2; + dummy.recordDate = elem1.recordDate - 24 * 60 * 60 * 1000; + dummy.recordDailyBasal = elem1.recordDailyBasal / 2; + dummy.recordDailyBolus = elem1.recordDailyBolus / 2; dummies.add(dummy); elem1.recordDailyBasal /= 2; elem1.recordDailyBolus /= 2; @@ -329,7 +321,7 @@ public class DanaRStatsActivity extends Activity { Collections.sort(historyList, new Comparator() { @Override public int compare(DanaRHistoryRecord lhs, DanaRHistoryRecord rhs) { - return (int) (rhs.recordDate-lhs.recordDate); + return (int) (rhs.recordDate - lhs.recordDate); } }); @@ -363,7 +355,7 @@ public class DanaRStatsActivity extends Activity { // Create the table row TableRow tr = new TableRow(DanaRStatsActivity.this); if (i % 2 != 0) tr.setBackgroundColor(Color.DKGRAY); - if(dummies.contains(record)){ + if (dummies.contains(record)) { tr.setBackgroundColor(Color.argb(125, 255, 0, 0)); } tr.setId(100 + i); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MessageHashTable.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MessageHashTable.java index debdd8a35f..10d2c0b091 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MessageHashTable.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MessageHashTable.java @@ -18,6 +18,7 @@ public class MessageHashTable { messages = new HashMap(); put(new MsgBolusStop()); // 0x0101 CMD_MEALINS_STOP put(new MsgBolusStart()); // 0x0102 CMD_MEALINS_START_DATA + put(new MsgBolusStartWithSpeed()); // 0x0104 CMD_MEALINS_START_DATA_SPEED put(new MsgBolusProgress()); // 0x0202 CMD_PUMP_THIS_REMAINDER_MEAL_INS put(new MsgStatusProfile()); // 0x0204 CMD_PUMP_CALCULATION_SETTING put(new MsgStatusTempBasal()); // 0x0205 CMD_PUMP_EXERCISE_MODE diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgBolusStartWithSpeed.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgBolusStartWithSpeed.java new file mode 100644 index 0000000000..b04d501ef0 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgBolusStartWithSpeed.java @@ -0,0 +1,43 @@ +package info.nightscout.androidaps.plugins.PumpDanaR.comm; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.utils.HardLimits; + +public class MsgBolusStartWithSpeed extends MessageBase { + private static Logger log = LoggerFactory.getLogger(MsgBolusStartWithSpeed.class); + + public MsgBolusStartWithSpeed() { + SetCommand(0x0104); + } + + public MsgBolusStartWithSpeed(double amount, int speed) { + this(); + + // HARDCODED LIMIT + amount = MainApp.getConfigBuilder().applyBolusConstraints(amount); + if (amount < 0) amount = 0d; + if (amount > HardLimits.maxBolus()) amount = HardLimits.maxBolus(); + + AddParamInt((int) (amount * 100)); + AddParamByte((byte) speed); + + if (Config.logDanaMessageDetail) + log.debug("Bolus start : " + amount + " speed: " + speed); + } + + @Override + public void handleMessage(byte[] bytes) { + int result = intFromBuff(bytes, 0, 1); + if (result != 2) { + failed = true; + log.debug("Messsage response: " + result + " FAILED!!"); + } else { + if (Config.logDanaMessageDetail) + log.debug("Messsage response: " + result); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java index 4ed5de2920..727b6cd7fb 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgSettingMeal.java @@ -40,6 +40,13 @@ public class MsgSettingMeal extends MessageBase { log.debug("Is Config U/d: " + pump.isConfigUD); } + if (pump.basalStep != 0.01d) { + Notification notification = new Notification(Notification.WRONGBASALSTEP, MainApp.sResources.getString(R.string.danar_setbasalstep001), Notification.URGENT); + MainApp.bus().post(new EventNewNotification(notification)); + } else { + MainApp.bus().post(new EventDismissNotification(Notification.WRONGBASALSTEP)); + } + if (pump.isConfigUD) { Notification notification = new Notification(Notification.UD_MODE_ENABLED, MainApp.sResources.getString(R.string.danar_switchtouhmode), Notification.URGENT); MainApp.bus().post(new EventNewNotification(notification)); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBasic.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBasic.java index ba8374f383..2aba028250 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBasic.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/comm/MsgStatusBasic.java @@ -24,9 +24,10 @@ public class MsgStatusBasic extends MessageBase { pump.reservoirRemainingUnits = intFromBuff(bytes, 7, 3) / 750d; pump.bolusBlocked = intFromBuff(bytes, 10, 1) == 1; pump.currentBasal = intFromBuff(bytes, 11, 2) / 100d; - pump.tempBasalPercent = intFromBuff(bytes, 13, 1); - pump.isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1; - pump.isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1; + // removed. info taken from tempstatus message + //pump.tempBasalPercent = intFromBuff(bytes, 13, 1); + //pump.isExtendedInProgress = intFromBuff(bytes, 14, 1) == 1; + //pump.isTempBasalInProgress = intFromBuff(bytes, 15, 1) == 1; pump.batteryRemaining = intFromBuff(bytes, 20, 1); if (Config.logDanaMessageDetail) { @@ -37,9 +38,9 @@ public class MsgStatusBasic extends MessageBase { log.debug("Reservoir remaining units: " + pump.reservoirRemainingUnits); log.debug("Bolus blocked: " + pump.bolusBlocked); log.debug("Current basal: " + pump.currentBasal); - log.debug("Current temp basal percent: " + pump.tempBasalPercent); - log.debug("Is extended bolus running: " + pump.isExtendedInProgress); - log.debug("Is temp basal running: " + pump.isTempBasalInProgress); + //log.debug("Current temp basal percent: " + pump.tempBasalPercent); + //log.debug("Is extended bolus running: " + pump.isExtendedInProgress); + //log.debug("Is temp basal running: " + pump.isTempBasalInProgress); } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java index 419d5feb2c..9d94634094 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaR/services/DanaRExecutionService.java @@ -40,6 +40,7 @@ import info.nightscout.androidaps.plugins.PumpDanaR.SerialIOThread; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MessageBase; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusProgress; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStart; +import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStartWithSpeed; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgBolusStop; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgCheckValue; import info.nightscout.androidaps.plugins.PumpDanaR.comm.MsgHistoryAlarm; @@ -109,7 +110,7 @@ public class DanaRExecutionService extends Service { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String action = intent.getAction(); if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) { - log.debug("Device has disconnected " + device.getName());//Device has disconnected + log.debug("Device was disconnected " + device.getName());//Device was disconnected if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) { if (mSerialIOThread != null) { mSerialIOThread.disconnect("BT disconnection broadcast"); @@ -290,10 +291,13 @@ public class DanaRExecutionService extends Service { } } - mSerialIOThread.sendMessage(tempStatusMsg); // do this before statusBasic because here is temp duration - mSerialIOThread.sendMessage(exStatusMsg); mSerialIOThread.sendMessage(statusMsg); mSerialIOThread.sendMessage(statusBasicMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingtempbasalstatus))); + mSerialIOThread.sendMessage(tempStatusMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingextendedbolusstatus))); + mSerialIOThread.sendMessage(exStatusMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus))); if (!statusMsg.received) { mSerialIOThread.sendMessage(statusMsg); @@ -319,6 +323,7 @@ public class DanaRExecutionService extends Service { Date now = new Date(); if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRPlugin.class).isInitialized()) { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings))); mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); mSerialIOThread.sendMessage(new MsgSettingActiveProfile()); mSerialIOThread.sendMessage(new MsgSettingMeal()); @@ -329,6 +334,7 @@ public class DanaRExecutionService extends Service { mSerialIOThread.sendMessage(new MsgSettingActiveProfile()); mSerialIOThread.sendMessage(new MsgSettingProfileRatios()); mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll()); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime))); mSerialIOThread.sendMessage(new MsgSettingPumpTime()); long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L; log.debug("Pump time difference: " + timeDiff + " seconds"); @@ -404,7 +410,12 @@ public class DanaRExecutionService extends Service { public boolean bolus(double amount, int carbs, Treatment t) { bolusingTreatment = t; - MsgBolusStart start = new MsgBolusStart(amount); + int speed = SP.getInt(R.string.key_danars_bolusspeed, 0); + MessageBase start; + if (speed == 0) + start = new MsgBolusStart(amount); + else + start = new MsgBolusStartWithSpeed(amount, speed); MsgBolusStop stop = new MsgBolusStop(amount, t); connect("bolus"); @@ -526,7 +537,7 @@ public class DanaRExecutionService extends Service { connect("updateBasalsInPump"); if (!isConnected()) return false; MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.updatingbasalrates))); - double[] basal = buildDanaRProfileRecord(profile); + double[] basal = DanaRPump.buildDanaRProfileRecord(profile); MsgSetBasalProfile msgSet = new MsgSetBasalProfile((byte) 0, basal); mSerialIOThread.sendMessage(msgSet); MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0); @@ -537,19 +548,6 @@ public class DanaRExecutionService extends Service { return true; } - private double[] buildDanaRProfileRecord(Profile nsProfile) { - double[] record = new double[24]; - for (Integer hour = 0; hour < 24; hour++) { - //Some values get truncated to the next lower one. - // -> round them to two decimals and make sure we are a small delta larger (that will get truncated) - double value = Math.round(100d * nsProfile.getBasal((Integer) (hour * 60 * 60)))/100d + 0.00001; - if (Config.logDanaMessageDetail) - log.debug("NS basal value for " + hour + ":00 is " + value); - record[hour] = value; - } - return record; - } - private void waitMsec(long msecs) { SystemClock.sleep(msecs); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java index d8c840f262..c8b2d04759 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/DanaRKoreanPlugin.java @@ -68,7 +68,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf private static DanaRKoreanExecutionService sExecutionService; - private DanaRPump pump = DanaRPump.getInstance(); + private static DanaRPump pump = DanaRPump.getInstance(); private boolean useExtendedBoluses = false; private static DanaRKoreanPlugin plugin = null; @@ -345,7 +345,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf // This is called from APS @Override - public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { // Recheck pump status if older than 30 min if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { doConnect("setTempBasalAbsolute old data"); @@ -405,7 +405,7 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf if (MainApp.getConfigBuilder().isInHistoryRealTempBasalInProgress()) { // Correct basal already set ? if (MainApp.getConfigBuilder().getRealTempBasalFromHistory(System.currentTimeMillis()).percentRate == percentRate) { - if (force) { + if (enforceNew) { cancelTempBasal(true); } else { result.success = true; @@ -646,7 +646,11 @@ public class DanaRKoreanPlugin implements PluginBase, PumpInterface, DanaRInterf } public static void doConnect(String from) { - if (sExecutionService != null) sExecutionService.connect(from); + if (sExecutionService != null) { + sExecutionService.connect(from); + pumpDescription.basalStep = pump.basalStep; + pumpDescription.bolusStep = pump.bolusStep; + } } public static boolean isConnected() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java index 470d526360..f77c03e337 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRKorean/services/DanaRKoreanExecutionService.java @@ -105,7 +105,7 @@ public class DanaRKoreanExecutionService extends Service { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String action = intent.getAction(); if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) { - log.debug("Device has disconnected " + device.getName());//Device has disconnected + log.debug("Device was disconnected " + device.getName());//Device was disconnected if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) { if (mSerialIOThread != null) { mSerialIOThread.disconnect("BT disconnection broadcast"); @@ -286,11 +286,13 @@ public class DanaRKoreanExecutionService extends Service { } } - mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); // TODO: show it somewhere - mSerialIOThread.sendMessage(tempStatusMsg); // do this before statusBasic because here is temp duration - mSerialIOThread.sendMessage(exStatusMsg); //mSerialIOThread.sendMessage(statusMsg); mSerialIOThread.sendMessage(statusBasicMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingtempbasalstatus))); + mSerialIOThread.sendMessage(tempStatusMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingextendedbolusstatus))); + mSerialIOThread.sendMessage(exStatusMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus))); // if (!statusMsg.received) { // mSerialIOThread.sendMessage(statusMsg); @@ -316,6 +318,7 @@ public class DanaRKoreanExecutionService extends Service { Date now = new Date(); if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRKoreanPlugin.class).isInitialized()) { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings))); mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); mSerialIOThread.sendMessage(new MsgSettingMeal()); mSerialIOThread.sendMessage(new MsgSettingBasal_k()); @@ -323,6 +326,8 @@ public class DanaRKoreanExecutionService extends Service { mSerialIOThread.sendMessage(new MsgSettingMaxValues()); mSerialIOThread.sendMessage(new MsgSettingGlucose()); mSerialIOThread.sendMessage(new MsgSettingProfileRatios()); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime))); + mSerialIOThread.sendMessage(new MsgSettingPumpTime()); long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L; log.debug("Pump time difference: " + timeDiff + " seconds"); if (Math.abs(timeDiff) > 10) { @@ -502,7 +507,7 @@ public class DanaRKoreanExecutionService extends Service { connect("updateBasalsInPump"); if (!isConnected()) return false; MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.updatingbasalrates))); - double[] basal = buildDanaRProfileRecord(profile); + double[] basal = DanaRPump.buildDanaRProfileRecord(profile); MsgSetSingleBasalProfile msgSet = new MsgSetSingleBasalProfile(basal); mSerialIOThread.sendMessage(msgSet); danaRPump.lastSettingsRead = new Date(0); // force read full settings @@ -511,17 +516,6 @@ public class DanaRKoreanExecutionService extends Service { return true; } - private double[] buildDanaRProfileRecord(Profile nsProfile) { - double[] record = new double[24]; - for (Integer hour = 0; hour < 24; hour++) { - double value = Math.round(100d * nsProfile.getBasal((Integer) (hour * 60 * 60)))/100d + 0.00001; - if (Config.logDanaMessageDetail) - log.debug("NS basal value for " + hour + ":00 is " + value); - record[hour] = value; - } - return record; - } - private void waitMsec(long msecs) { SystemClock.sleep(msecs); } 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..04a82ed1bd --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/DanaRSPlugin.java @@ -0,0 +1,818 @@ +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.events.EventPumpStatusChanged; +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 connectIfNotConnected(String from) { + if (!isConnected()) + connect(from); + } + + public static synchronized void connect(String from) { + log.debug("RS connect from: " + from); + if (danaRSService != null && !mDeviceAddress.equals("") && !mDeviceName.equals("")) { + final Object o = new Object(); + + danaRSService.connect(from, mDeviceAddress, o); + synchronized (o) { + try { + o.wait(20000); + } catch (InterruptedException e) { + log.error("InterruptedException " + e); + } + } + pumpDescription.basalStep = pump.basalStep; + pumpDescription.bolusStep = pump.bolusStep; + if (isConnected()) + log.debug("RS connected: " + from); + else { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.connectiontimedout))); + danaRSService.stopConnecting(); + log.debug("RS connect failed from: " + from); + } + } + } + + 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) { + connectIfNotConnected("loadHistory"); + 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)); + } + connectIfNotConnected("updateBasalsInPump"); + 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) { + log.debug("Refreshing data from pump"); + if (!isConnected() && !isConnecting()) { + connect(reason); + } else + log.debug("Already connecting ..."); + } + + @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 + int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0); + int speed = 12; + switch (preferencesSpeed) { + case 0: + speed = 12; + break; + case 1: + speed = 30; + break; + case 2: + speed = 60; + break; + } + // v2 stores end time for bolus, we need to adjust time + // default delivery speed is 12 U/min + detailedBolusInfo.date += detailedBolusInfo.insulin / speed * 60d * 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; + connectIfNotConnected("bolus"); + 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 enforceNew) { + // 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 (!enforceNew) { + 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; + TemporaryBasal runningTB = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); + if (runningTB != null && runningTB.percentRate == 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); + connectIfNotConnected("tempbasal"); + 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(); + connectIfNotConnected("hightempbasal"); + 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(); + ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()); + if (runningEB != null && Math.abs(runningEB.insulin - 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; + } + connectIfNotConnected("extendedBolus"); + 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(); + TemporaryBasal runningTB = MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()); + if (runningTB != null) { + connectIfNotConnected("tempBasalStop"); + 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(); + ExtendedBolus runningEB = MainApp.getConfigBuilder().getExtendedBolusFromHistory(System.currentTimeMillis()); + if (runningEB != null) { + connectIfNotConnected("extendedBolusStop"); + 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..5457bb4155 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRSMessageHashTable.java @@ -0,0 +1,108 @@ +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_Set_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_Get_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()); + + // APS + put(new DanaRS_Packet_APS_Basal_Set_Temporary_Basal()); + put(new DanaRS_Packet_APS_History_Events()); + put(new DanaRS_Packet_APS_Set_Event_History()); + + 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..8ac5bfac13 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet.java @@ -0,0 +1,207 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import android.annotation.TargetApi; +import android.os.Build; + +import com.cozmo.danar.util.BleCommandUtil; + +import java.nio.charset.StandardCharsets; +import java.util.Date; + +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 boolean failed; + 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; + failed = 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"; + } + + 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; + } + + public static Date dateTimeSecFromBuff(byte[] buff, int offset) { + Date date = + new Date( + 100 + intFromBuff(buff, offset, 1), + intFromBuff(buff, offset + 1, 1) - 1, + intFromBuff(buff, offset + 2, 1), + intFromBuff(buff, offset + 3, 1), + intFromBuff(buff, offset + 4, 1), + intFromBuff(buff, offset + 5, 1) + ); + return date; + } + + protected static int intFromBuff(byte[] b, int srcStart, int srcLength) { + int ret; + + switch (srcLength) { + case 1: + ret = b[DATA_START + srcStart + 0] & 0x000000FF; + break; + case 2: + ret = ((b[DATA_START + srcStart + 1] & 0x000000FF) << 8) + (b[DATA_START + srcStart + 0] & 0x000000FF); + break; + case 3: + ret = ((b[DATA_START + srcStart + 2] & 0x000000FF) << 16) + ((b[DATA_START + srcStart + 1] & 0x000000FF) << 8) + (b[DATA_START + srcStart + 0] & 0x000000FF); + break; + case 4: + ret = ((b[DATA_START + srcStart + 3] & 0x000000FF) << 24) + ((b[DATA_START + srcStart + 2] & 0x000000FF) << 16) + ((b[DATA_START + srcStart + 1] & 0x000000FF) << 8) + (b[DATA_START + srcStart + 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_APS_Basal_Set_Temporary_Basal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Basal_Set_Temporary_Basal.java new file mode 100644 index 0000000000..7ce847dc58 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Basal_Set_Temporary_Basal.java @@ -0,0 +1,67 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import com.cozmo.danar.util.BleCommandUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; + +public class DanaRS_Packet_APS_Basal_Set_Temporary_Basal extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_APS_Basal_Set_Temporary_Basal.class); + + private int temporaryBasalRatio; + private int temporaryBasalDuration; + public int error; + + public DanaRS_Packet_APS_Basal_Set_Temporary_Basal() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE_BASAL__APS_SET_TEMPORARY_BASAL; + } + + public DanaRS_Packet_APS_Basal_Set_Temporary_Basal(int percent) { + this(); + + //HARDCODED LIMITS + if (percent < 0) percent = 0; + if (percent > 500) percent = 500; + + temporaryBasalRatio = percent; + if (percent < 100) { + temporaryBasalDuration = 160; + if (Config.logDanaMessageDetail) + log.debug("APS Temp basal start percent: " + percent + " duration 30 min"); + } else { + temporaryBasalDuration = 150; + if (Config.logDanaMessageDetail) + log.debug("APS Temp basal start percent: " + percent + " duration 15 min"); + } + + } + + @Override + public byte[] getRequestParams() { + byte[] request = new byte[3]; + request[0] = (byte) (temporaryBasalRatio & 0xff); + request[1] = (byte) ((temporaryBasalRatio >>> 8) & 0xff); + request[2] = (byte) (temporaryBasalDuration & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int result = byteArrayToInt(getBytes(data, DATA_START, 1)); + if (result != 1) { + failed = true; + log.debug("Set APS temp basal start result: " + result + " FAILED!!!"); + } else { + if (Config.logDanaMessageDetail) + log.debug("Set APS temp basal start result: " + result); + } + } + + @Override + public String getFriendlyName() { + return "BASAL__APS_SET_TEMPORARY_BASAL"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_History_Events.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_History_Events.java new file mode 100644 index 0000000000..fe010eb72f --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_History_Events.java @@ -0,0 +1,190 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import com.cozmo.danar.util.BleCommandUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.db.DanaRHistoryRecord; +import info.nightscout.androidaps.db.ExtendedBolus; +import info.nightscout.androidaps.db.Source; +import info.nightscout.androidaps.db.TemporaryBasal; +import info.nightscout.androidaps.plugins.ConfigBuilder.DetailedBolusInfoStorage; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; +import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus; +import info.nightscout.utils.DateUtil; + +public class DanaRS_Packet_APS_History_Events extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_APS_History_Events.class); + + private int year = 0; + private int month = 0; + private int day = 0; + private int hour = 0; + private int min = 0; + private int sec = 0; + + public boolean done; + public int totalCount; + + public static long lastEventTimeLoaded = 0; + + public DanaRS_Packet_APS_History_Events() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE__APS_HISTORY_EVENTS; + done = false; + totalCount = 0; + } + + public DanaRS_Packet_APS_History_Events(long from) { + this(); + GregorianCalendar cal = new GregorianCalendar(); + if (from != 0) + cal.setTimeInMillis(from); + else + cal.set(2000, 0, 1, 0, 0, 0); + 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); + log.debug("Loading event history from: " + new Date(cal.getTimeInMillis()).toLocaleString()); + } + + @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) { + byte recordCode = (byte) intFromBuff(data, 0, 1); + + // Last record + if (recordCode == (byte) 0xFF) { + done = true; + return; + } + + Date datetime = dateTimeSecFromBuff(data, 1); // 6 bytes + int param1 = ((intFromBuff(data, 7, 1) << 8) & 0xFF00) + (intFromBuff(data, 8, 1) & 0xFF); + int param2 = ((intFromBuff(data, 9, 1) << 8) & 0xFF00) + (intFromBuff(data, 10, 1) & 0xFF); + + TemporaryBasal temporaryBasal = new TemporaryBasal(); + temporaryBasal.date = datetime.getTime(); + temporaryBasal.source = Source.PUMP; + temporaryBasal.pumpId = datetime.getTime(); + + ExtendedBolus extendedBolus = new ExtendedBolus(); + extendedBolus.date = datetime.getTime(); + extendedBolus.source = Source.PUMP; + extendedBolus.pumpId = datetime.getTime(); + + DetailedBolusInfo detailedBolusInfo = DetailedBolusInfoStorage.findDetailedBolusInfo(datetime.getTime()); + if (detailedBolusInfo == null) { + log.debug("DetailedBolusInfo not found for " + datetime.toLocaleString()); + detailedBolusInfo = new DetailedBolusInfo(); + } + detailedBolusInfo.date = datetime.getTime(); + detailedBolusInfo.source = Source.PUMP; + detailedBolusInfo.pumpId = datetime.getTime(); + + switch (recordCode) { + case DanaRPump.TEMPSTART: + log.debug("EVENT TEMPSTART (" + recordCode + ") " + datetime.toLocaleString() + " Ratio: " + param1 + "% Duration: " + param2 + "min"); + temporaryBasal.percentRate = param1; + temporaryBasal.durationInMinutes = param2; + MainApp.getConfigBuilder().addToHistoryTempBasal(temporaryBasal); + break; + case DanaRPump.TEMPSTOP: + log.debug("EVENT TEMPSTOP (" + recordCode + ") " + datetime.toLocaleString()); + MainApp.getConfigBuilder().addToHistoryTempBasal(temporaryBasal); + break; + case DanaRPump.EXTENDEDSTART: + log.debug("EVENT EXTENDEDSTART (" + recordCode + ") " + datetime.toLocaleString() + " Amount: " + (param1 / 100d) + "U Duration: " + param2 + "min"); + extendedBolus.insulin = param1 / 100d; + extendedBolus.durationInMinutes = param2; + MainApp.getConfigBuilder().addToHistoryExtendedBolus(extendedBolus); + break; + case DanaRPump.EXTENDEDSTOP: + log.debug("EVENT EXTENDEDSTOP (" + recordCode + ") " + datetime.toLocaleString() + " Delivered: " + (param1 / 100d) + "U RealDuration: " + param2 + "min"); + MainApp.getConfigBuilder().addToHistoryExtendedBolus(extendedBolus); + break; + case DanaRPump.BOLUS: + detailedBolusInfo.insulin = param1 / 100d; + boolean newRecord = MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + log.debug((newRecord ? "**NEW** " : "") + "EVENT BOLUS (" + recordCode + ") " + datetime.toLocaleString() + " Bolus: " + (param1 / 100d) + "U Duration: " + param2 + "min"); + DetailedBolusInfoStorage.remove(detailedBolusInfo.date); + break; + case DanaRPump.DUALBOLUS: + detailedBolusInfo.insulin = param1 / 100d; + newRecord = MainApp.getConfigBuilder().addToHistoryTreatment(detailedBolusInfo); + log.debug((newRecord ? "**NEW** " : "") + "EVENT DUALBOLUS (" + recordCode + ") " + datetime.toLocaleString() + " Bolus: " + (param1 / 100d) + "U Duration: " + param2 + "min"); + DetailedBolusInfoStorage.remove(detailedBolusInfo.date); + break; + case DanaRPump.DUALEXTENDEDSTART: + log.debug("EVENT DUALEXTENDEDSTART (" + recordCode + ") " + datetime.toLocaleString() + " Amount: " + (param1 / 100d) + "U Duration: " + param2 + "min"); + extendedBolus.insulin = param1 / 100d; + extendedBolus.durationInMinutes = param2; + MainApp.getConfigBuilder().addToHistoryExtendedBolus(extendedBolus); + break; + case DanaRPump.DUALEXTENDEDSTOP: + log.debug("EVENT DUALEXTENDEDSTOP (" + recordCode + ") " + datetime.toLocaleString() + " Delivered: " + (param1 / 100d) + "U RealDuration: " + param2 + "min"); + MainApp.getConfigBuilder().addToHistoryExtendedBolus(extendedBolus); + break; + case DanaRPump.SUSPENDON: + log.debug("EVENT SUSPENDON (" + recordCode + ") " + datetime.toLocaleString()); + break; + case DanaRPump.SUSPENDOFF: + log.debug("EVENT SUSPENDOFF (" + recordCode + ") " + datetime.toLocaleString()); + break; + case DanaRPump.REFILL: + log.debug("EVENT REFILL (" + recordCode + ") " + datetime.toLocaleString() + " Amount: " + param1 / 100d + "U"); + break; + case DanaRPump.PRIME: + log.debug("EVENT PRIME (" + recordCode + ") " + datetime.toLocaleString() + " Amount: " + param1 / 100d + "U"); + break; + case DanaRPump.PROFILECHANGE: + log.debug("EVENT PROFILECHANGE (" + recordCode + ") " + datetime.toLocaleString() + " No: " + param1 + " CurrentRate: " + (param2 / 100d) + "U/h"); + break; + case DanaRPump.CARBS: + DetailedBolusInfo emptyCarbsInfo = new DetailedBolusInfo(); + emptyCarbsInfo.carbs = param1; + emptyCarbsInfo.date = datetime.getTime(); + emptyCarbsInfo.source = Source.PUMP; + emptyCarbsInfo.pumpId = datetime.getTime(); + newRecord = MainApp.getConfigBuilder().addToHistoryTreatment(emptyCarbsInfo); + log.debug((newRecord ? "**NEW** " : "") + "EVENT CARBS (" + recordCode + ") " + datetime.toLocaleString() + " Carbs: " + param1 + "g"); + break; + case DanaRPump.PRIMECANNULA: + log.debug("EVENT PRIME CANNULA(" + recordCode + ") " + datetime.toLocaleString() + " Amount: " + param1 / 100d + "U"); + break; + default: + log.debug("Event: " + recordCode + " " + datetime.toLocaleString() + " Param1: " + param1 + " Param2: " + param2); + break; + } + + if (datetime.getTime() > lastEventTimeLoaded) + lastEventTimeLoaded = datetime.getTime(); + } + + @Override + public String getFriendlyName() { + return "APS_HISTORY_EVENTS"; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java new file mode 100644 index 0000000000..0f102090a7 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_APS_Set_Event_History.java @@ -0,0 +1,77 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import com.cozmo.danar.util.BleCommandUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.GregorianCalendar; + +import info.nightscout.androidaps.Config; + +public class DanaRS_Packet_APS_Set_Event_History extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_APS_Set_Event_History.class); + + private int type; + private long time; + public int param1; + public int param2; + + public DanaRS_Packet_APS_Set_Event_History() { + super(); + opCode = BleCommandUtil.DANAR_PACKET__OPCODE__APS_SET_EVENT_HISTORY; + } + + public DanaRS_Packet_APS_Set_Event_History(int type, long time, int param1, int param2) { + this(); + + this.type = type; + this.time = time; + this.param1 = param1; + this.param2 = param2; + } + + @Override + public byte[] getRequestParams() { + GregorianCalendar cal = new GregorianCalendar(); + cal.setTimeInMillis(time); + int year = cal.get(Calendar.YEAR) - 1900 - 100; + int month = cal.get(Calendar.MONTH) + 1; + int day = cal.get(Calendar.DAY_OF_MONTH); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int min = cal.get(Calendar.MINUTE); + int sec = cal.get(Calendar.SECOND); + + byte[] request = new byte[11]; + request[0] = (byte) (type & 0xff); + request[1] = (byte) (year & 0xff); + request[2] = (byte) (month & 0xff); + request[3] = (byte) (day & 0xff); + request[4] = (byte) (hour & 0xff); + request[5] = (byte) (min & 0xff); + request[6] = (byte) (sec & 0xff); + request[7] = (byte) ((param1 >>> 8) & 0xff); + request[8] = (byte) (param1 & 0xff); + request[9] = (byte) ((param2 >>> 8) & 0xff); + request[10] = (byte) (param2 & 0xff); + return request; + } + + @Override + public void handleMessage(byte[] data) { + int result = intFromBuff(data, 0, 1); + if (result != 1) { + failed = true; + log.debug("Set history entry result: " + result + " FAILED!!!"); + } else { + if (Config.logDanaMessageDetail) + log.debug("Set history entry result: " + result); + } + } + + @Override + public String getFriendlyName() { + return "APS_SET_EVENT_HISTORY"; + } +} 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..efc87d3834 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Basal_Rate.java @@ -0,0 +1,68 @@ +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 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.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_Set_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]); + } + + if (pump.basalStep != 0.01d) { + Notification notification = new Notification(Notification.WRONGBASALSTEP, MainApp.sResources.getString(R.string.danar_setbasalstep001), Notification.URGENT); + MainApp.bus().post(new EventNewNotification(notification)); + } else { + MainApp.bus().post(new EventDismissNotification(Notification.WRONGBASALSTEP)); + } + + } + + @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_Get_Temporary_Basal_State.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_Temporary_Basal_State.java new file mode 100644 index 0000000000..dbf917874d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Get_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_Get_Temporary_Basal_State extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Get_Temporary_Basal_State.class); + + public DanaRS_Packet_Basal_Get_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_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_Cancel_Temporary_Basal.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal.java new file mode 100644 index 0000000000..70a8b02826 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Basal_Set_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_Set_Cancel_Temporary_Basal extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal.class); + + public int error; + + public DanaRS_Packet_Basal_Set_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_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_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..61296f42ed --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Get_Bolus_Option.java @@ -0,0 +1,137 @@ +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.MainApp; +import info.nightscout.androidaps.R; +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.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 (!pump.isExtendedBolusEnabled) { + Notification notification = new Notification(Notification.EXTENDED_BOLUS_DISABLED, MainApp.sResources.getString(R.string.danar_enableextendedbolus), Notification.URGENT); + MainApp.bus().post(new EventNewNotification(notification)); + } else { + MainApp.bus().post(new EventDismissNotification(Notification.EXTENDED_BOLUS_DISABLED)); + } + + 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..d5f61c0946 --- /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..1263aeb629 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Start.java @@ -0,0 +1,66 @@ +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 boolean failed; + + 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)); + + failed = status != 0x00; + + 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..61ddd05c9b --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Bolus_Set_Step_Bolus_Stop.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 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; + stopped = 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..c38439d7eb --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_General_Get_Pump_Check.java @@ -0,0 +1,51 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import com.cozmo.danar.util.BleCommandUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +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.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..d05777d20d --- /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 = (int) (byteArrayToInt(getBytes(data, dataIndex, dataSize)) / 100d); + + 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..6bae4ab8c1 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_History_.java @@ -0,0 +1,230 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.comm; + +import com.cozmo.danar.util.BleCommandUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.db.DanaRHistoryRecord; +import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; +import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRSyncStatus; +import info.nightscout.utils.DateUtil; + +public abstract class DanaRS_Packet_History_ extends DanaRS_Packet { + private static Logger log = LoggerFactory.getLogger(DanaRS_Packet_History_.class); + + private int year = 0; + private int month = 0; + private int day = 0; + private int hour = 0; + private int min = 0; + private int sec = 0; + + public boolean done; + public int totalCount; + + public DanaRS_Packet_History_() { + super(); + done = false; + totalCount = 0; + } + + public DanaRS_Packet_History_(Date from) { + this(); + GregorianCalendar cal = new GregorianCalendar(); + if (from.getTime() != 0) + cal.setTime(from); + else + cal.set(2000, 0, 1, 0, 0, 0); + 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); + log.debug("Loading event history from: " + new Date(cal.getTimeInMillis()).toLocaleString()); + } + + @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; + totalCount = 0; + if (data.length == 3) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + done = true; + log.debug("History end. Code: " + error + " Success: " + (error == 0x00)); + } else if (data.length == 5) { + int dataIndex = DATA_START; + int dataSize = 1; + error = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + done = true; + + dataIndex += dataSize; + dataSize = 2; + totalCount = byteArrayToInt(getBytes(data, dataIndex, dataSize)); + log.debug("History end. Code: " + error + " Success: " + (error == 0x00) + " Toatal count: " + totalCount); + } else { + int recordCode = byteArrayToInt(getBytes(data, DATA_START, 1)); + int historyYear = byteArrayToInt(getBytes(data, DATA_START + 1, 1)); + int historyMonth = byteArrayToInt(getBytes(data, DATA_START +2 , 1)); + int historyDay = byteArrayToInt(getBytes(data, DATA_START + 3, 1)); + int historyHour = byteArrayToInt(getBytes(data, DATA_START + 4, 1)); + double dailyBasal = (((data[DATA_START + 4] & 0xFF) << 8) + (data[DATA_START + 5] & 0xFF)) * 0.01d; + int historyMinute = byteArrayToInt(getBytes(data, DATA_START + 5, 1)); + int historySecond = byteArrayToInt(getBytes(data, DATA_START + 6, 1)); + byte paramByte7 = (byte) historySecond; + double dailyBolus = (((data[DATA_START + 6] & 0xFF) << 8) + (data[DATA_START + 7] & 0xFF)) * 0.01d; + + Date date = new Date(100 + historyYear, historyMonth - 1, historyDay); + Date datetime = new Date(100 + historyYear, historyMonth - 1, historyDay, historyHour, historyMinute); + Date datetimewihtsec = new Date(100 + historyYear, historyMonth - 1, historyDay, historyHour, historyMinute, historySecond); + + int historyCode = byteArrayToInt(getBytes(data, DATA_START + 7, 1)); + byte paramByte8 = (byte) historyCode; + + int value = ((data[DATA_START + 8] & 0xFF) << 8) + (data[DATA_START + 9] & 0xFF); + + log.debug("History packet: " + recordCode + " Date: " + datetimewihtsec.toLocaleString() + " Code: " + historyCode + " Value: " + value); + + + EventDanaRSyncStatus ev = new EventDanaRSyncStatus(); + DanaRHistoryRecord danaRHistoryRecord = new DanaRHistoryRecord(); + + danaRHistoryRecord.setBytes(data); + // danaRHistoryRecord.recordCode is different from DanaR codes + // set in switch for every type + + String messageType = ""; + + switch (recordCode) { + case 0x02: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_BOLUS; + danaRHistoryRecord.recordDate = datetime.getTime(); + switch (0xF0 & paramByte8) { + case 0xA0: + danaRHistoryRecord.bolusType = "DS"; + messageType += "DS bolus"; + break; + case 0xC0: + danaRHistoryRecord.bolusType = "E"; + messageType += "E bolus"; + break; + case 0x80: + danaRHistoryRecord.bolusType = "S"; + messageType += "S bolus"; + break; + case 0x90: + danaRHistoryRecord.bolusType = "DE"; + messageType += "DE bolus"; + break; + default: + danaRHistoryRecord.bolusType = "None"; + break; + } + danaRHistoryRecord.recordDuration = ((int) paramByte8 & 0x0F) * 60 + (int) paramByte7; + danaRHistoryRecord.recordValue = value * 0.01; + break; + case 0x03: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_DAILY; + messageType += "dailyinsulin"; + danaRHistoryRecord.recordDate = date.getTime(); + danaRHistoryRecord.recordDailyBasal = dailyBasal; + danaRHistoryRecord.recordDailyBolus = dailyBolus; + break; + case 0x04: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_PRIME; + messageType += "prime"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + danaRHistoryRecord.recordValue = value * 0.01; + break; + case 0x05: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_REFILL; + messageType += "refill"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + danaRHistoryRecord.recordValue = value * 0.01; + break; + case 0x0b: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_BASALHOUR; + messageType += "basal hour"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + danaRHistoryRecord.recordValue = value * 0.01; + break; + case 0x99: ///// ????????? don't know the right code + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_TEMP_BASAL; + messageType += "tb"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + danaRHistoryRecord.recordValue = value * 0.01; + break; + case 0x06: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_GLUCOSE; + messageType += "glucose"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + danaRHistoryRecord.recordValue = value; + break; + case 0x07: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_CARBO; + messageType += "carbo"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + danaRHistoryRecord.recordValue = value; + break; + case 0x0a: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_ALARM; + messageType += "alarm"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + String strAlarm = "None"; + switch ((int) paramByte8) { + case 67: + strAlarm = "Check"; + break; + case 79: + strAlarm = "Occlusion"; + break; + case 66: + strAlarm = "Low Battery"; + break; + case 83: + strAlarm = "Shutdown"; + break; + } + danaRHistoryRecord.recordAlarm = strAlarm; + danaRHistoryRecord.recordValue = value * 0.01; + break; + case 0x09: + danaRHistoryRecord.recordCode = RecordTypes.RECORD_TYPE_SUSPEND; + messageType += "suspend"; + danaRHistoryRecord.recordDate = datetimewihtsec.getTime(); + String strRecordValue = "Off"; + if ((int) paramByte8 == 79) + strRecordValue = "On"; + danaRHistoryRecord.stringRecordValue = strRecordValue; + break; + } + + MainApp.getDbHelper().createOrUpdate(danaRHistoryRecord); + + ev.message = DateUtil.dateAndTimeString(danaRHistoryRecord.recordDate); + ev.message += " " + messageType; + MainApp.bus().post(ev); + + } + } +} 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..0139b12197 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/comm/DanaRS_Packet_Notify_Delivery_Complete.java @@ -0,0 +1,57 @@ +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 static boolean done; + + 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; + done = false; + } + + @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); + done = true; + 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/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/BLEComm.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/BLEComm.java new file mode 100644 index 0000000000..dde50a93e1 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/BLEComm.java @@ -0,0 +1,706 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.services; + +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.Handler; +import android.os.HandlerThread; +import android.os.SystemClock; + +import com.cozmo.danar.util.BleCommandUtil; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.events.EventPumpStatusChanged; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; +import info.nightscout.androidaps.plugins.PumpDanaRS.activities.PairingHelperActivity; +import info.nightscout.androidaps.plugins.PumpDanaRS.activities.PairingProgressDialog; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRSMessageHashTable; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSPacket; +import info.nightscout.androidaps.plugins.PumpDanaRS.events.EventDanaRSPairingSuccess; +import info.nightscout.utils.SP; + +/** + * Created by mike on 23.09.2017. + */ + +public class BLEComm { + private static Logger log = LoggerFactory.getLogger(BLEComm.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 static BLEComm instance = null; + + public static BLEComm getInstance(DanaRSService service) { + if (instance == null) + instance = new BLEComm(service); + return instance; + } + + private Object mConfirmConnect = null; + + private final ScheduledExecutorService worker = Executors.newSingleThreadScheduledExecutor(); + private ScheduledFuture scheduledDisconnection = null; + + private DanaRS_Packet processsedMessage = null; + private ArrayList mSendQueue = new ArrayList<>(); + + // Variables for connection progress (elapsed time) + private Handler sHandler; + private HandlerThread sHandlerThread; + private long connectionStartTime = 0; + private final Runnable updateProgress = new Runnable() { + @Override + public void run() { + long secondsElapsed = (System.currentTimeMillis() - connectionStartTime) / 1000; + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTING, (int) secondsElapsed)); + sHandler.postDelayed(updateProgress, 1000); + } + }; + + private BluetoothManager mBluetoothManager = null; + private BluetoothAdapter mBluetoothAdapter = null; + private BluetoothDevice mBluetoothDevice = null; + private String mBluetoothDeviceAddress = null; + private String mBluetoothDeviceName = null; + private BluetoothGatt mBluetoothGatt = null; + + protected boolean isConnected = false; + protected boolean isConnecting = false; + + private BluetoothGattCharacteristic UART_Read; + private BluetoothGattCharacteristic UART_Write; + + private DanaRSService service; + + BLEComm(DanaRSService service) { + this.service = service; + initialize(); + + if (sHandlerThread == null) { + sHandlerThread = new HandlerThread(PairingProgressDialog.class.getSimpleName()); + sHandlerThread.start(); + sHandler = new Handler(sHandlerThread.getLooper()); + } + } + + private boolean initialize() { + log.debug("Initializing BLEComm."); + + 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, Object confirmConnect) { + mConfirmConnect = confirmConnect; + 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; + } + + connectionStartTime = System.currentTimeMillis(); + + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTING)); + isConnecting = true; + + // Following should be removed later because we close Gatt on disconnect and this should never happen + if ((mBluetoothDeviceAddress != null) && (address.equals(mBluetoothDeviceAddress)) && (mBluetoothGatt != null)) { + log.debug("Trying to use an existing mBluetoothGatt for connection."); + sHandler.post(updateProgress); + if (mBluetoothGatt.connect()) { + setCharacteristicNotification(getUARTReadBTGattChar(), true); + return true; + } + sHandler.removeCallbacks(updateProgress); + return false; + } + // end + + BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); + if (device == null) { + log.debug("Device not found. Unable to connect."); + return false; + } + + sHandler.post(updateProgress); + mBluetoothGatt = device.connectGatt(service.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 stopConnecting() { + isConnecting = false; + sHandler.removeCallbacks(updateProgress); // just to be sure + } + + 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; + sHandler.removeCallbacks(updateProgress); // just to be sure + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED)); + log.debug("Device was disconnected " + gatt.getDevice().getName());//Device was disconnected + } + } + + public void onServicesDiscovered(BluetoothGatt gatt, int status) { + log.debug("onServicesDiscovered"); + + isConnecting = false; + + if (status == BluetoothGatt.GATT_SUCCESS) { + findCharacteristic(); + } + // stop sending connection progress + sHandler.removeCallbacks(updateProgress); + SendPumpCheck(); + // 1st message sent to pump after connect + } + + public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + log.debug("onCharacteristicRead" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); + addToReadBuffer(characteristic.getValue()); + readDataParsing(); + } + + public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { + log.debug("onCharacteristicChanged" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); + addToReadBuffer(characteristic.getValue()); + new Thread(new Runnable() { + @Override + public void run() { + readDataParsing(); + } + }).start(); + } + + public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { + log.debug("onCharacteristicWrite" + (characteristic != null ? ":" + DanaRS_Packet.toHexString(characteristic.getValue()) : "")); + new Thread(new Runnable() { + @Override + public void run() { + 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); + } + } + } + }).start(); + } + }; + + 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() { + SystemClock.sleep(WRITE_DELAY_MILLIS); + characteristic.setValue(data); + characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE); + log.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data)); + mBluetoothGatt.writeCharacteristic(characteristic); + } + }).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 addToReadBuffer(byte[] buffer) { + //log.debug("addToReadBuffer " + DanaRS_Packet.toHexString(buffer)); + if (buffer == null || buffer.length == 0) { + return; + } + synchronized (readBuffer) { + // Append incomming data to input buffer + System.arraycopy(buffer, 0, readBuffer, bufferLength, buffer.length); + bufferLength += buffer.length; + } + } + + private void readDataParsing() { + boolean startSignatureFound = false, packetIsValid = false; + boolean isProcessing; + + isProcessing = true; + + while (isProcessing) { + int length = 0; + byte[] inputBuffer = null; + synchronized (readBuffer) { + // 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 + 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) { + inputBuffer = new byte[length + 7]; + // copy packet to input buffer + System.arraycopy(readBuffer, 0, inputBuffer, 0, length + 7); + // Cut off the message from readBuffer + try { + System.arraycopy(readBuffer, length + 7, readBuffer, 0, bufferLength - (length + 7)); + } catch (Exception e) { + log.debug("length: " + length + "bufferLength: " + bufferLength); + throw e; + } + bufferLength -= (length + 7); + // now we have encrypted packet in inputBuffer + } + } + if (packetIsValid) { + try { + // decrypt the packet + inputBuffer = BleCommandUtil.getInstance().getDecryptedPacket(inputBuffer); + + if (inputBuffer == null) { + log.debug("Null decryptedInputBuffer"); + return; + } + + 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(MainApp.sResources.getString(R.string.key_danars_pairingkey) + DanaRSPlugin.mDeviceName, 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)); + mSendQueue.clear(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED, MainApp.sResources.getString(R.string.pumpbusy))); + } else { + log.debug("<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(inputBuffer)); + mSendQueue.clear(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTED, MainApp.sResources.getString(R.string.connectionerror))); + } + 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(MainApp.sResources.getString(R.string.key_danars_pairingkey) + DanaRSPlugin.mDeviceName, 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)); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.CONNECTED)); + + isConnected = true; + isConnecting = false; + service.getPumpStatus(); + scheduleDisconnection(); + if (mConfirmConnect != null) { + synchronized (mConfirmConnect) { + mConfirmConnect.notify(); + mConfirmConnect = null; + } + } + 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)); + } + scheduleDisconnection(); + break; + } + } catch (Exception e) { + e.printStackTrace(); + } + 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(); + } + } + + //SystemClock.sleep(200); + if (!message.isReceived()) { + log.warn("Reply not received " + message.getFriendlyName()); + } + scheduleDisconnection(); + } + + 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); + } + + protected void SendPumpCheck() { + // 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); + } + + 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); + } + + public void scheduleDisconnection() { + class DisconnectRunnable implements Runnable { + public void run() { + disconnect("scheduleDisconnection"); + scheduledDisconnection = null; + } + } + // prepare task for execution in 5 sec + // cancel waiting task to prevent sending multiple disconnections + if (scheduledDisconnection != null) + scheduledDisconnection.cancel(false); + Runnable task = new DisconnectRunnable(); + final int sec = 5; + scheduledDisconnection = worker.schedule(task, sec, TimeUnit.SECONDS); + log.debug("Disconnection scheduled"); + } + +} 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..6b39788342 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRS/services/DanaRSService.java @@ -0,0 +1,402 @@ +package info.nightscout.androidaps.plugins.PumpDanaRS.services; + +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.os.Binder; +import android.os.IBinder; +import android.os.PowerManager; +import android.os.SystemClock; + +import com.squareup.otto.Subscribe; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Date; + +import info.nightscout.androidaps.Config; +import info.nightscout.androidaps.Constants; +import info.nightscout.androidaps.MainApp; +import info.nightscout.androidaps.R; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.db.Treatment; +import info.nightscout.androidaps.events.EventAppExit; +import info.nightscout.androidaps.events.EventInitializationChanged; +import info.nightscout.androidaps.events.EventPumpStatusChanged; +import info.nightscout.androidaps.plugins.Overview.Notification; +import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; +import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; +import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; +import info.nightscout.androidaps.plugins.PumpDanaR.events.EventDanaRNewStatus; +import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_APS_Basal_Set_Temporary_Basal; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_APS_History_Events; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_APS_Set_Event_History; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Get_Basal_Rate; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Get_Profile_Number; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Get_Temporary_Basal_State; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Set_Profile_Basal_Rate; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Set_Profile_Number; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Basal_Set_Temporary_Basal; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Get_Bolus_Option; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Get_CIR_CF_Array; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Get_Calculation_Information; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Get_Extended_Bolus_State; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Get_Step_Bolus_Information; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Set_Extended_Bolus; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Set_Step_Bolus_Start; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Bolus_Set_Step_Bolus_Stop; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_General_Get_Pump_Check; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_General_Get_Shipping_Information; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_General_Initial_Screen_Information; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_General_Set_History_Upload_Mode; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Alarm; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Basal; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Blood_Glucose; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Bolus; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Carbohydrate; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Daily; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Prime; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Refill; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_History_Suspend; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Notify_Delivery_Complete; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Notify_Delivery_Rate_Display; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Option_Get_Pump_Time; +import info.nightscout.androidaps.plugins.PumpDanaRS.comm.DanaRS_Packet_Option_Set_Pump_Time; +import info.nightscout.utils.NSUpload; +import info.nightscout.utils.SP; + +public class DanaRSService extends Service { + private static Logger log = LoggerFactory.getLogger(DanaRSService.class); + + private BLEComm bleComm = BLEComm.getInstance(this); + + private PowerManager.WakeLock mWakeLock; + private IBinder mBinder = new LocalBinder(); + + private DanaRPump danaRPump = DanaRPump.getInstance(); + private Treatment bolusingTreatment = null; + + private long lastHistoryFetched = 0; + + public DanaRSService() { + try { + MainApp.bus().unregister(this); + } catch (RuntimeException x) { + // Ignore + } + MainApp.bus().register(this); + + PowerManager powerManager = (PowerManager) MainApp.instance().getApplicationContext().getSystemService(Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, DanaRSService.class.getSimpleName()); + + } + + public boolean isConnected() { + return bleComm.isConnected; + } + + public boolean isConnecting() { + return bleComm.isConnecting; + } + + public boolean connect(String from, String address, Object confirmConnect) { + return bleComm.connect(from, address, confirmConnect); + } + + public void stopConnecting() { + bleComm.stopConnecting(); + } + + public void disconnect(String from) { + bleComm.disconnect(from); + } + + public void sendMessage(DanaRS_Packet message) { + bleComm.sendMessage(message); + } + + protected boolean getPumpStatus() { + try { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpstatus))); + + bleComm.sendMessage(new DanaRS_Packet_General_Initial_Screen_Information()); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingextendedbolusstatus))); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Extended_Bolus_State()); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus))); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Step_Bolus_Information()); // last bolus + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingtempbasalstatus))); + bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State()); + + Date now = new Date(); + if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRSPlugin.class).isInitialized()) { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings))); + bleComm.sendMessage(new DanaRS_Packet_General_Get_Shipping_Information()); // serial no + bleComm.sendMessage(new DanaRS_Packet_General_Get_Pump_Check()); // firmware + bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Profile_Number()); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Bolus_Option()); // isExtendedEnabled + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Step_Bolus_Information()); // bolusStep, maxBolus + bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Basal_Rate()); // basal profile, basalStep, maxBasal + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Calculation_Information()); // target + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_CIR_CF_Array()); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime))); + bleComm.sendMessage(new DanaRS_Packet_Option_Get_Pump_Time()); + long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L; + log.debug("Pump time difference: " + timeDiff + " seconds"); + if (Math.abs(timeDiff) > 10) { + bleComm.sendMessage(new DanaRS_Packet_Option_Set_Pump_Time(new Date())); + bleComm.sendMessage(new DanaRS_Packet_Option_Get_Pump_Time()); + timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L; + log.debug("Pump time difference: " + timeDiff + " seconds"); + } + danaRPump.lastSettingsRead = now; + } + + loadEvents(); + + danaRPump.lastConnection = now; + MainApp.bus().post(new EventDanaRNewStatus()); + MainApp.bus().post(new EventInitializationChanged()); + NSUpload.uploadDeviceStatus(); + if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) { + log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits); + Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT); + MainApp.bus().post(new EventNewNotification(reportFail)); + NSUpload.uploadError(MainApp.sResources.getString(R.string.approachingdailylimit) + ": " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits + "U"); + } + } catch (Exception e) { + log.error("Unhandled exception", e); + } + return true; + } + + public boolean loadEvents() { + DanaRS_Packet_APS_History_Events msg; + if (lastHistoryFetched == 0) { + msg = new DanaRS_Packet_APS_History_Events(0); + log.debug("Loading complete event history"); + } else { + msg = new DanaRS_Packet_APS_History_Events(lastHistoryFetched); + log.debug("Loading event history from: " + new Date(lastHistoryFetched).toLocaleString()); + } + bleComm.sendMessage(msg); + while (!msg.done && bleComm.isConnected()) { + SystemClock.sleep(100); + } + SystemClock.sleep(200); + lastHistoryFetched = DanaRS_Packet_APS_History_Events.lastEventTimeLoaded; + return true; + } + + + public boolean bolus(double insulin, int carbs, long carbtime, Treatment t) { + bolusingTreatment = t; + int speed = SP.getInt(R.string.key_danars_bolusspeed, 0); + DanaRS_Packet_Bolus_Set_Step_Bolus_Start start = new DanaRS_Packet_Bolus_Set_Step_Bolus_Start(insulin, speed); + DanaRS_Packet_Bolus_Set_Step_Bolus_Stop stop = new DanaRS_Packet_Bolus_Set_Step_Bolus_Stop(insulin, t); // initialize static variables + DanaRS_Packet_Notify_Delivery_Complete complete = new DanaRS_Packet_Notify_Delivery_Complete(insulin, t); // initialize static variables + + if (!isConnected()) return false; + + if (carbs > 0) { +// MsgSetCarbsEntry msg = new MsgSetCarbsEntry(carbtime, carbs); #### +// bleComm.sendMessage(msg); + DanaRS_Packet_APS_Set_Event_History msgSetHistoryEntry_v2 = new DanaRS_Packet_APS_Set_Event_History(DanaRPump.CARBS, carbtime, carbs, 0); + bleComm.sendMessage(msgSetHistoryEntry_v2); + lastHistoryFetched = carbtime - 60000; + } + if (insulin > 0) { + DanaRS_Packet_Notify_Delivery_Rate_Display progress = new DanaRS_Packet_Notify_Delivery_Rate_Display(insulin, t); // initialize static variables + + if (!stop.stopped) { + bleComm.sendMessage(start); + } else { + t.insulin = 0d; + return false; + } + while (!stop.stopped && !start.failed && !complete.done) { + SystemClock.sleep(100); + if ((System.currentTimeMillis() - progress.lastReceive) > 5 * 1000L) { // if i didn't receive status for more than 5 sec expecting broken comm + stop.stopped = true; + stop.forced = true; + log.debug("Communication stopped"); + } + } + } + SystemClock.sleep(3000); + bolusingTreatment = null; + DanaRSPlugin.connectIfNotConnected("ReadHistoryAfterBolus"); + loadEvents(); + return true; + } + + public void bolusStop() { + if (Config.logDanaBTComm) + log.debug("bolusStop >>>>> @ " + (bolusingTreatment == null ? "" : bolusingTreatment.insulin)); + DanaRS_Packet_Bolus_Set_Step_Bolus_Stop stop = new DanaRS_Packet_Bolus_Set_Step_Bolus_Stop(); + stop.forced = true; + if (isConnected()) { + bleComm.sendMessage(stop); + while (!stop.stopped) { + bleComm.sendMessage(stop); + SystemClock.sleep(200); + } + } else { + stop.stopped = true; + } + } + + public boolean tempBasal(Integer percent, int durationInHours) { + if (!isConnected()) return false; + if (danaRPump.isTempBasalInProgress) { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); + bleComm.sendMessage(new DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal()); + SystemClock.sleep(500); + } + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); + bleComm.sendMessage(new DanaRS_Packet_Basal_Set_Temporary_Basal(percent, durationInHours)); + SystemClock.sleep(200); + bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State()); + loadEvents(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + return true; + } + + public boolean highTempBasal(Integer percent) { + if (danaRPump.isTempBasalInProgress) { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); + bleComm.sendMessage(new DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal()); + SystemClock.sleep(500); + } + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingtempbasal))); + bleComm.sendMessage(new DanaRS_Packet_APS_Basal_Set_Temporary_Basal(percent)); + bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State()); + loadEvents(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + return true; + } + + public boolean tempBasalStop() { + if (!isConnected()) return false; + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingtempbasal))); + bleComm.sendMessage(new DanaRS_Packet_Basal_Set_Cancel_Temporary_Basal()); + bleComm.sendMessage(new DanaRS_Packet_Basal_Get_Temporary_Basal_State()); + loadEvents(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + return true; + } + + public boolean extendedBolus(Double insulin, int durationInHalfHours) { + if (!isConnected()) return false; + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.settingextendedbolus))); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Set_Extended_Bolus(insulin, durationInHalfHours)); + SystemClock.sleep(200); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Extended_Bolus_State()); + loadEvents(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + return true; + } + + public boolean extendedBolusStop() { + if (!isConnected()) return false; + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.stoppingextendedbolus))); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Set_Extended_Bolus_Cancel()); + bleComm.sendMessage(new DanaRS_Packet_Bolus_Get_Extended_Bolus_State()); + loadEvents(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + return true; + } + + public boolean updateBasalsInPump(Profile profile) { + if (!isConnected()) return false; + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.updatingbasalrates))); + double[] basal = DanaRPump.buildDanaRProfileRecord(profile); + DanaRS_Packet_Basal_Set_Profile_Basal_Rate msgSet = new DanaRS_Packet_Basal_Set_Profile_Basal_Rate(0, basal); + bleComm.sendMessage(msgSet); + DanaRS_Packet_Basal_Set_Profile_Number msgActivate = new DanaRS_Packet_Basal_Set_Profile_Number(0); + bleComm.sendMessage(msgActivate); + danaRPump.lastSettingsRead = new Date(0); // force read full settings + getPumpStatus(); + MainApp.bus().post(new EventPumpStatusChanged(EventPumpStatusChanged.DISCONNECTING)); + return true; + } + + public boolean loadHistory(byte type) { + if (!isConnected()) return false; + DanaRS_Packet_History_ msg = null; + switch (type) { + case RecordTypes.RECORD_TYPE_ALARM: + msg = new DanaRS_Packet_History_Alarm(); + break; + case RecordTypes.RECORD_TYPE_PRIME: + msg = new DanaRS_Packet_History_Prime(); + break; + case RecordTypes.RECORD_TYPE_BASALHOUR: + msg = new DanaRS_Packet_History_Basal(); + break; + case RecordTypes.RECORD_TYPE_BOLUS: + msg = new DanaRS_Packet_History_Bolus(); + break; + case RecordTypes.RECORD_TYPE_CARBO: + msg = new DanaRS_Packet_History_Carbohydrate(); + break; + case RecordTypes.RECORD_TYPE_DAILY: + msg = new DanaRS_Packet_History_Daily(); + break; + case RecordTypes.RECORD_TYPE_GLUCOSE: + msg = new DanaRS_Packet_History_Blood_Glucose(); + break; + case RecordTypes.RECORD_TYPE_REFILL: + msg = new DanaRS_Packet_History_Refill(); + break; + case RecordTypes.RECORD_TYPE_SUSPEND: + msg = new DanaRS_Packet_History_Suspend(); + break; + } + if (msg != null) { + bleComm.sendMessage(new DanaRS_Packet_General_Set_History_Upload_Mode(1)); + SystemClock.sleep(200); + bleComm.sendMessage(msg); + while (!msg.done && isConnected()) { + SystemClock.sleep(100); + } + SystemClock.sleep(200); + bleComm.sendMessage(new DanaRS_Packet_General_Set_History_Upload_Mode(0)); + } + return true; + } + + + 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"); + } + +} 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 1c69de81f7..ea174e4608 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 @@ -48,6 +48,7 @@ import info.nightscout.androidaps.plugins.PumpDanaRv2.services.DanaRv2ExecutionS import info.nightscout.utils.DateUtil; import info.nightscout.utils.DecimalFormatter; import info.nightscout.utils.Round; +import info.nightscout.utils.SP; /** * Created by mike on 05.08.2016. @@ -210,7 +211,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 @@ -294,8 +295,21 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, 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; + // default delivery speed is 12 U/min + int preferencesSpeed = SP.getInt(R.string.key_danars_bolusspeed, 0); + int speed = 12; + switch (preferencesSpeed) { + case 0: + speed = 12; + break; + case 1: + speed = 30; + break; + case 2: + speed = 60; + break; + } + detailedBolusInfo.date += detailedBolusInfo.insulin / speed * 60d * 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; @@ -338,7 +352,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, // This is called from APS @Override - public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { // Recheck pump status if older than 30 min if (pump.lastConnection.getTime() + 30 * 60 * 1000L < System.currentTimeMillis()) { doConnect("setTempBasalAbsolute old data"); @@ -380,7 +394,7 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, if (MainApp.getConfigBuilder().isTempBasalInProgress()) { // Correct basal already set ? if (MainApp.getConfigBuilder().getTempBasalFromHistory(System.currentTimeMillis()).percentRate == percentRate) { - if (!force) { + if (!enforceNew) { result.success = true; result.percent = percentRate; result.absolute = MainApp.getConfigBuilder().getTempBasalAbsoluteRateHistory(); @@ -578,7 +592,11 @@ public class DanaRv2Plugin implements PluginBase, PumpInterface, DanaRInterface, } public static void doConnect(String from) { - if (sExecutionService != null) sExecutionService.connect(from); + if (sExecutionService != null) { + sExecutionService.connect(from); + pumpDescription.basalStep = pump.basalStep; + pumpDescription.bolusStep = pump.bolusStep; + } } public static boolean isConnected() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MessageHashTable_v2.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MessageHashTable_v2.java index 0940efd73f..cafba32239 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MessageHashTable_v2.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/comm/MessageHashTable_v2.java @@ -22,6 +22,7 @@ public class MessageHashTable_v2 { messages = new HashMap(); put(new MsgBolusStop()); // 0x0101 CMD_MEALINS_STOP put(new MsgBolusStart()); // 0x0102 CMD_MEALINS_START_DATA + put(new MsgBolusStartWithSpeed()); // 0x0104 CMD_MEALINS_START_DATA_SPEED put(new MsgBolusProgress()); // 0x0202 CMD_PUMP_THIS_REMAINDER_MEAL_INS put(new MsgStatusProfile()); // 0x0204 CMD_PUMP_CALCULATION_SETTING diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java index 0e96987728..fc3df19296 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpDanaRv2/services/DanaRv2ExecutionService.java @@ -79,7 +79,7 @@ public class DanaRv2ExecutionService extends Service { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); String action = intent.getAction(); if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) { - log.debug("Device has disconnected " + device.getName());//Device has disconnected + log.debug("Device was disconnected " + device.getName());//Device was disconnected if (mBTDevice != null && mBTDevice.getName() != null && mBTDevice.getName().equals(device.getName())) { if (mSerialIOThread != null) { mSerialIOThread.disconnect("BT disconnection broadcast"); @@ -261,10 +261,13 @@ public class DanaRv2ExecutionService extends Service { } } - mSerialIOThread.sendMessage(tempStatusMsg); // do this before statusBasic because here is temp duration - mSerialIOThread.sendMessage(exStatusMsg); mSerialIOThread.sendMessage(statusMsg); mSerialIOThread.sendMessage(statusBasicMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingtempbasalstatus))); + mSerialIOThread.sendMessage(tempStatusMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingextendedbolusstatus))); + mSerialIOThread.sendMessage(exStatusMsg); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingbolusstatus))); if (!statusMsg.received) { mSerialIOThread.sendMessage(statusMsg); @@ -290,6 +293,7 @@ public class DanaRv2ExecutionService extends Service { Date now = new Date(); if (danaRPump.lastSettingsRead.getTime() + 60 * 60 * 1000L < now.getTime() || !MainApp.getSpecificPlugin(DanaRv2Plugin.class).isInitialized()) { + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumpsettings))); mSerialIOThread.sendMessage(new MsgSettingShippingInfo()); mSerialIOThread.sendMessage(new MsgSettingActiveProfile()); mSerialIOThread.sendMessage(new MsgSettingMeal()); @@ -300,6 +304,7 @@ public class DanaRv2ExecutionService extends Service { mSerialIOThread.sendMessage(new MsgSettingActiveProfile()); mSerialIOThread.sendMessage(new MsgSettingProfileRatios()); mSerialIOThread.sendMessage(new MsgSettingProfileRatiosAll()); + MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.gettingpumptime))); mSerialIOThread.sendMessage(new MsgSettingPumpTime()); long timeDiff = (danaRPump.pumpTime.getTime() - System.currentTimeMillis()) / 1000L; log.debug("Pump time difference: " + timeDiff + " seconds"); @@ -318,7 +323,7 @@ public class DanaRv2ExecutionService extends Service { MainApp.bus().post(new EventDanaRNewStatus()); MainApp.bus().post(new EventInitializationChanged()); NSUpload.uploadDeviceStatus(); - if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning ) { + if (danaRPump.dailyTotalUnits > danaRPump.maxDailyTotalUnits * Constants.dailyLimitWarning) { log.debug("Approaching daily limit: " + danaRPump.dailyTotalUnits + "/" + danaRPump.maxDailyTotalUnits); Notification reportFail = new Notification(Notification.APPROACHING_DAILY_LIMIT, MainApp.sResources.getString(R.string.approachingdailylimit), Notification.URGENT); MainApp.bus().post(new EventNewNotification(reportFail)); @@ -397,7 +402,12 @@ public class DanaRv2ExecutionService extends Service { public boolean bolus(double amount, int carbs, long carbtime, Treatment t) { bolusingTreatment = t; - MsgBolusStart start = new MsgBolusStart(amount); + int speed = SP.getInt(R.string.key_danars_bolusspeed, 0); + MessageBase start; + if (speed == 0) + start = new MsgBolusStart(amount); + else + start = new MsgBolusStartWithSpeed(amount, speed); MsgBolusStop stop = new MsgBolusStop(amount, t); connect("bolus"); @@ -538,7 +548,7 @@ public class DanaRv2ExecutionService extends Service { connect("updateBasalsInPump"); if (!isConnected()) return false; MainApp.bus().post(new EventPumpStatusChanged(MainApp.sResources.getString(R.string.updatingbasalrates))); - double[] basal = buildDanaRProfileRecord(profile); + double[] basal = DanaRPump.buildDanaRProfileRecord(profile); MsgSetBasalProfile msgSet = new MsgSetBasalProfile((byte) 0, basal); mSerialIOThread.sendMessage(msgSet); MsgSetActivateBasalProfile msgActivate = new MsgSetActivateBasalProfile((byte) 0); @@ -549,17 +559,6 @@ public class DanaRv2ExecutionService extends Service { return true; } - private double[] buildDanaRProfileRecord(Profile nsProfile) { - double[] record = new double[24]; - for (Integer hour = 0; hour < 24; hour++) { - double value = Math.round(100d * nsProfile.getBasal((Integer) (hour * 60 * 60)))/100d + 0.00001; - if (Config.logDanaMessageDetail) - log.debug("NS basal value for " + hour + ":00 is " + value); - record[hour] = value; - } - return record; - } - private void waitMsec(long msecs) { SystemClock.sleep(msecs); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java index f4a37b9914..ca3f7a62a0 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpMDI/MDIPlugin.java @@ -166,7 +166,7 @@ public class MDIPlugin implements PluginBase, PumpInterface { } @Override - public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { PumpEnactResult result = new PumpEnactResult(); result.success = false; result.comment = MainApp.instance().getString(R.string.pumperror); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java index 3965ef5326..e7323f48af 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/PumpVirtual/VirtualPumpPlugin.java @@ -251,7 +251,7 @@ public class VirtualPumpPlugin implements PluginBase, PumpInterface { } @Override - public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean force) { + public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, boolean enforceNew) { TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder(); TemporaryBasal tempBasal = new TemporaryBasal(); tempBasal.date = System.currentTimeMillis(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java index 209743dee1..9f0e7b7b74 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/SmsCommunicator/SmsCommunicatorPlugin.java @@ -497,7 +497,7 @@ public class SmsCommunicatorPlugin implements PluginBase { PumpInterface pumpInterface = MainApp.getConfigBuilder(); if (pumpInterface != null) { danaRPlugin = MainApp.getSpecificPlugin(DanaRPlugin.class); - PumpEnactResult result = pumpInterface.setTempBasalAbsolute(tempBasalWaitingForConfirmation.tempBasal, 30, false); + PumpEnactResult result = pumpInterface.setTempBasalAbsolute(tempBasalWaitingForConfirmation.tempBasal, 30, true); if (result.success) { reply = String.format(MainApp.sResources.getString(R.string.smscommunicator_tempbasalset), result.absolute, result.duration); if (danaRPlugin != null) diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/ProfileViewerDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/ProfileViewerDialog.java index b4461eabb7..a34146f04a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/ProfileViewerDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/ProfileViewerDialog.java @@ -43,7 +43,7 @@ public class ProfileViewerDialog extends DialogFragment { private TextView dateTextView; private Button refreshButton; - static ProfileViewerDialog newInstance(long time) { + public static ProfileViewerDialog newInstance(long time) { ProfileViewerDialog dialog = new ProfileViewerDialog(); Bundle args = new Bundle(); @@ -63,7 +63,7 @@ public class ProfileViewerDialog extends DialogFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View layout = inflater.inflate(R.layout.nsprofileviewer_fragment, container, false); + View layout = inflater.inflate(R.layout.profileviewer_fragment, container, false); noProfile = (TextView) layout.findViewById(R.id.profileview_noprofile); units = (TextView) layout.findViewById(R.id.profileview_units); @@ -95,7 +95,7 @@ public class ProfileViewerDialog extends DialogFragment { noProfile.setVisibility(View.GONE); units.setText(profile.getUnits()); dia.setText(DecimalFormatter.to2Decimal(profile.getDia()) + " h"); - activeProfile.setText(profileSwitch.profileName); + activeProfile.setText(profileSwitch.getCustomizedName()); dateTextView.setText(DateUtil.dateAndTimeString(profileSwitch.date)); ic.setText(profile.getIcList()); isf.setText(profile.getIsfList()); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsProfileSwitchFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsProfileSwitchFragment.java index 7fcca51e67..e5655cdb18 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsProfileSwitchFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Treatments/fragments/TreatmentsProfileSwitchFragment.java @@ -74,7 +74,7 @@ public class TreatmentsProfileSwitchFragment extends SubscriberFragment implemen } else { holder.duration.setText(""); } - holder.name.setText(profileSwitch.profileName); + holder.name.setText(profileSwitch.getCustomizedName()); if (profileSwitch.isInProgress()) holder.date.setTextColor(ContextCompat.getColor(MainApp.instance(), R.color.colorActive)); else diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java index 07d41a0d8a..9fbcc31685 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/ActionStringHandler.java @@ -23,18 +23,20 @@ import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.DanaRHistoryRecord; import info.nightscout.androidaps.db.DatabaseHelper; +import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.TempTarget; import info.nightscout.androidaps.interfaces.APSInterface; import info.nightscout.androidaps.interfaces.DanaRInterface; import info.nightscout.androidaps.interfaces.PluginBase; +import info.nightscout.androidaps.interfaces.ProfileInterface; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.plugins.Actions.dialogs.FillDialog; +import info.nightscout.androidaps.plugins.Careportal.Dialogs.NewNSTreatmentDialog; import info.nightscout.androidaps.plugins.Loop.APSResult; import info.nightscout.androidaps.plugins.Loop.LoopPlugin; import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; -import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfilePlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin; import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPump; import info.nightscout.androidaps.plugins.PumpDanaR.comm.RecordTypes; @@ -67,8 +69,7 @@ public class ActionStringHandler { public synchronized static void handleInitiate(String actionstring) { - if (!BuildConfig.WEAR_CONTROL) return; - + if (!SP.getBoolean("wearcontrol", false)) return; lastBolusWizard = null; @@ -242,25 +243,21 @@ public class ActionStringHandler { lastBolusWizard = bolusWizard; } else if("opencpp".equals(act[0])){ - Object activeProfile = MainApp.getConfigBuilder().getActiveProfileInterface(); - CircadianPercentageProfilePlugin cpp = MainApp.getSpecificPlugin(CircadianPercentageProfilePlugin.class); - - if(cpp == null || activeProfile==null || cpp != activeProfile){ - sendError("CPP not activated!"); + ProfileSwitch activeProfileSwitch = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); + if(activeProfileSwitch==null){ + sendError("No active profile switch!"); return; } else { // read CPP values rTitle = "opencpp"; rMessage = "opencpp"; - rAction = "opencpp" + " " + cpp.getPercentage() + " " + cpp.getTimeshift(); + rAction = "opencpp" + " " + activeProfileSwitch.percentage + " " + activeProfileSwitch.timeshift; } } else if("cppset".equals(act[0])){ - Object activeProfile = MainApp.getConfigBuilder().getActiveProfileInterface(); - CircadianPercentageProfilePlugin cpp = MainApp.getSpecificPlugin(CircadianPercentageProfilePlugin.class); - - if(cpp == null || activeProfile==null || cpp != activeProfile){ - sendError("CPP not activated!"); + ProfileSwitch activeProfileSwitch = MainApp.getConfigBuilder().getProfileSwitchFromHistory(System.currentTimeMillis()); + if(activeProfileSwitch==null){ + sendError("No active profile switch!"); return; } else { // read CPP values @@ -334,13 +331,16 @@ public class ActionStringHandler { private static String generateTDDMessage(List historyList, List dummies) { + ProfileInterface activeProfile = MainApp.getConfigBuilder().getActiveProfileInterface(); + + if(activeProfile == null){ + return "No profile loaded :("; + } + DateFormat df = new SimpleDateFormat("dd.MM."); String message = ""; - CircadianPercentageProfilePlugin cpp = MainApp.getSpecificPlugin(CircadianPercentageProfilePlugin.class); - boolean isCPP = (cpp!= null && cpp.isEnabled(PluginBase.PROFILE)); - double refTDD = 100; - if(isCPP) refTDD = cpp.baseBasalSum()*2; + double refTDD = activeProfile.getProfile().getDefaultProfile().baseBasalSum()*2; int i = 0; double sum = 0d; @@ -364,15 +364,15 @@ public class ActionStringHandler { i++; } message += "weighted:\n"; - message += "0.3: " + DecimalFormatter.to2Decimal(weighted03) + "U " + (isCPP?(DecimalFormatter.to0Decimal(100*weighted03/refTDD) + "%"):"") + "\n"; - message += "0.5: " + DecimalFormatter.to2Decimal(weighted05) + "U " + (isCPP?(DecimalFormatter.to0Decimal(100*weighted05/refTDD) + "%"):"") + "\n"; - message += "0.7: " + DecimalFormatter.to2Decimal(weighted07) + "U " + (isCPP?(DecimalFormatter.to0Decimal(100*weighted07/refTDD) + "%"):"") + "\n"; + message += "0.3: " + DecimalFormatter.to2Decimal(weighted03) + "U " + (DecimalFormatter.to0Decimal(100*weighted03/refTDD) + "%") + "\n"; + message += "0.5: " + DecimalFormatter.to2Decimal(weighted05) + "U " + (DecimalFormatter.to0Decimal(100*weighted05/refTDD) + "%") + "\n"; + message += "0.7: " + DecimalFormatter.to2Decimal(weighted07) + "U " + (DecimalFormatter.to0Decimal(100*weighted07/refTDD) + "%") + "\n"; message += "\n"; PumpInterface pump = MainApp.getConfigBuilder().getActivePump(); if (pump != null && pump instanceof DanaRPlugin) { double tdd = DanaRPump.getInstance().dailyTotalUnits; - message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (isCPP?(DecimalFormatter.to0Decimal(100*tdd/refTDD) + "%"):"") + "\n"; + message += "Today: " + DecimalFormatter.to2Decimal(tdd) + "U " + (DecimalFormatter.to0Decimal(100*tdd/refTDD) + "%") + "\n"; message += "\n"; } @@ -380,7 +380,7 @@ public class ActionStringHandler { Collections.reverse(historyList); for (DanaRHistoryRecord record : historyList) { double tdd = record.recordDailyBolus + record.recordDailyBasal; - message += df.format(new Date(record.recordDate)) + " " + DecimalFormatter.to2Decimal(tdd) +"U " + (isCPP?(DecimalFormatter.to0Decimal(100*tdd/refTDD) + "%"):"") + (dummies.contains(record)?"x":"") +"\n"; + message += df.format(new Date(record.recordDate)) + " " + DecimalFormatter.to2Decimal(tdd) +"U " + (DecimalFormatter.to0Decimal(100*tdd/refTDD) + "%") + (dummies.contains(record)?"x":"") +"\n"; } return message; } @@ -521,7 +521,7 @@ public class ActionStringHandler { public synchronized static void handleConfirmation(String actionString) { - if (!BuildConfig.WEAR_CONTROL) return; + if (!SP.getBoolean("wearcontrol", false)) return; //Guard from old or duplicate confirmations @@ -564,29 +564,47 @@ public class ActionStringHandler { } else if ("cppset".equals(act[0])) { int timeshift = SafeParse.stringToInt(act[1]); int percentage = SafeParse.stringToInt(act[2]); - setCPP(percentage, timeshift); + setCPP(timeshift, percentage); } else if ("dismissoverviewnotification".equals(act[0])){ MainApp.bus().post(new EventDismissNotification(SafeParse.stringToInt(act[1]))); } lastBolusWizard = null; } - private static void setCPP(int percentage, int timeshift) { - Object activeProfile = MainApp.getConfigBuilder().getActiveProfileInterface(); - CircadianPercentageProfilePlugin cpp = MainApp.getSpecificPlugin(CircadianPercentageProfilePlugin.class); + private static void setCPP(int timeshift, int percentage) { - if(cpp == null || activeProfile==null || cpp != activeProfile){ - sendError("CPP not activated!"); - return; + String msg = ""; + + + //check for validity + if (percentage < Constants.CPP_MIN_PERCENTAGE || percentage > Constants.CPP_MAX_PERCENTAGE) { + msg+= String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Percentage") + "\n"; } - String msg = cpp.externallySetParameters(timeshift, percentage); - if(msg != null && !"".equals(msg)){ + if (timeshift < 0 || timeshift > 23) { + msg+= String.format(MainApp.sResources.getString(R.string.openapsma_valueoutofrange), "Profile-Timeshift") + "\n"; + } + if(!SP.getBoolean("syncprofiletopump", false)){ + msg+= MainApp.sResources.getString(R.string.syncprofiletopump_title) + " " + MainApp.sResources.getString(R.string.cpp_sync_setting_missing) + "\n"; + } + final PumpInterface pump = MainApp.getConfigBuilder(); + final Profile profile = MainApp.getConfigBuilder().getProfile(); + + if (pump == null || profile == null || profile.getBasal() == null){ + msg+= MainApp.sResources.getString(R.string.cpp_notloadedplugins) + "\n"; + } + if(!"".equals(msg)) { + msg += MainApp.sResources.getString(R.string.cpp_valuesnotstored); String rTitle = "STATUS"; String rAction = "statusmessage"; WearFragment.getPlugin(MainApp.instance()).requestActionConfirmation(rTitle, msg, rAction); lastSentTimestamp = System.currentTimeMillis(); lastConfirmActionString = rAction; + return; } + + //send profile to pumpe + new NewNSTreatmentDialog(); //init + NewNSTreatmentDialog.doProfileSwitch(0, percentage, timeshift); } private static void generateTempTarget(int duration, double low, double high) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java index a5715ed5a1..e0d8d9210d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/WearPlugin.java @@ -29,7 +29,7 @@ import info.nightscout.utils.SP; public class WearPlugin implements PluginBase { - private static boolean fragmentEnabled = Config.WEAR; + private static boolean fragmentEnabled = true; private boolean fragmentVisible = true; private static WatchUpdaterService watchUS; private final Context ctx; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java index 93a85686b3..89189e7e12 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/Wear/wearintegration/WatchUpdaterService.java @@ -23,7 +23,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Date; import java.util.List; import info.nightscout.androidaps.Constants; @@ -31,6 +30,7 @@ import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.data.GlucoseStatus; import info.nightscout.androidaps.data.IobTotal; +import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.db.BgReading; import info.nightscout.androidaps.db.DatabaseHelper; import info.nightscout.androidaps.db.TemporaryBasal; @@ -38,12 +38,11 @@ import info.nightscout.androidaps.interfaces.PluginBase; import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; import info.nightscout.androidaps.plugins.Loop.LoopPlugin; -import info.nightscout.androidaps.data.Profile; import info.nightscout.androidaps.plugins.Overview.OverviewPlugin; -import info.nightscout.androidaps.plugins.ProfileCircadianPercentage.CircadianPercentageProfilePlugin; import info.nightscout.androidaps.plugins.Wear.ActionStringHandler; import info.nightscout.androidaps.plugins.Wear.WearPlugin; import info.nightscout.utils.DecimalFormatter; +import info.nightscout.utils.SP; import info.nightscout.utils.SafeParse; import info.nightscout.utils.ToastUtils; @@ -67,6 +66,7 @@ public class WatchUpdaterService extends WearableListenerService implements private static final String OPEN_SETTINGS_PATH = "/openwearsettings"; private static final String NEW_STATUS_PATH = "/sendstatustowear"; + private static final String NEW_PREFERENCES_PATH = "/sendpreferencestowear"; public static final String BASAL_DATA_PATH = "/nightscout_watch_basal"; public static final String BOLUS_PROGRESS_PATH = "/nightscout_watch_bolusprogress"; public static final String ACTION_CONFIRMATION_REQUEST_PATH = "/nightscout_watch_actionconfirmationrequest"; @@ -76,7 +76,7 @@ public class WatchUpdaterService extends WearableListenerService implements SharedPreferences mPrefs; private static boolean lastLoopStatus; - private static Logger log = LoggerFactory.getLogger(CircadianPercentageProfilePlugin.class); + private static Logger log = LoggerFactory.getLogger(WatchUpdaterService.class); @Override @@ -328,6 +328,7 @@ public class WatchUpdaterService extends WearableListenerService implements entries.putDataMapArrayList("entries", dataMaps); new SendToDataLayerThread(WEARABLE_DATA_PATH, googleApiClient).execute(entries); } + sendPreferences(); sendBasals(); sendStatus(); } @@ -529,6 +530,22 @@ public class WatchUpdaterService extends WearableListenerService implements } } + private void sendPreferences() { + if (googleApiClient.isConnected()) { + + boolean wearcontrol = SP.getBoolean("wearcontrol",false); + + PutDataMapRequest dataMapRequest = PutDataMapRequest.create(NEW_PREFERENCES_PATH); + //unique content + dataMapRequest.getDataMap().putDouble("timestamp", System.currentTimeMillis()); + dataMapRequest.getDataMap().putBoolean("wearcontrol", wearcontrol); + PutDataRequest putDataRequest = dataMapRequest.asPutDataRequest(); + Wearable.DataApi.putDataItem(googleApiClient, putDataRequest); + } else { + Log.e("SendStatus", "No connection to wearable available!"); + } + } + @NonNull private String generateStatusString() { String status = ""; @@ -551,8 +568,8 @@ public class WatchUpdaterService extends WearableListenerService implements //Temp basal TreatmentsInterface treatmentsInterface = MainApp.getConfigBuilder(); - if (treatmentsInterface.isTempBasalInProgress()) { - TemporaryBasal activeTemp = treatmentsInterface.getTempBasalFromHistory(System.currentTimeMillis()); + TemporaryBasal activeTemp = treatmentsInterface.getTempBasalFromHistory(System.currentTimeMillis()); + if (activeTemp != null) { status += activeTemp.toStringShort(); } diff --git a/app/src/main/java/info/nightscout/utils/DateUtil.java b/app/src/main/java/info/nightscout/utils/DateUtil.java index 2410014808..3e32557adb 100644 --- a/app/src/main/java/info/nightscout/utils/DateUtil.java +++ b/app/src/main/java/info/nightscout/utils/DateUtil.java @@ -1,6 +1,8 @@ package info.nightscout.utils; +import android.support.v4.util.LongSparseArray; import android.text.format.DateUtils; +import android.util.SparseIntArray; import java.text.DateFormat; import java.text.ParseException; @@ -8,6 +10,7 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import java.util.Locale; import java.util.TimeZone; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -24,8 +27,8 @@ public class DateUtil { /** * The date format in iso. */ - public static String FORMAT_DATE_ISO = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - public static String FORMAT_DATE_ISO_MSEC = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; + private static String FORMAT_DATE_ISO = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + private static String FORMAT_DATE_ISO_MSEC = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; /** * Takes in an ISO date string of the following format: @@ -37,13 +40,13 @@ public class DateUtil { */ public static Date fromISODateString(String isoDateString) throws Exception { - SimpleDateFormat f = new SimpleDateFormat(FORMAT_DATE_ISO); + SimpleDateFormat f = new SimpleDateFormat(FORMAT_DATE_ISO, Locale.getDefault()); Date date; f.setTimeZone(TimeZone.getTimeZone("UTC")); try { date = f.parse(isoDateString); } catch (ParseException e) { - f = new SimpleDateFormat(FORMAT_DATE_ISO_MSEC); + f = new SimpleDateFormat(FORMAT_DATE_ISO_MSEC, Locale.getDefault()); f.setTimeZone(TimeZone.getTimeZone("UTC")); date = f.parse(isoDateString); } @@ -61,7 +64,7 @@ public class DateUtil { public static String toISOString(Date date, String format, TimeZone tz) { if (format == null) format = FORMAT_DATE_ISO; if (tz == null) tz = TimeZone.getDefault(); - DateFormat f = new SimpleDateFormat(format); + DateFormat f = new SimpleDateFormat(format, Locale.getDefault()); f.setTimeZone(tz); return f.format(date); } @@ -85,7 +88,7 @@ public class DateUtil { } public static int toSeconds(String hh_colon_mm) { - Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM | PM)"); + Pattern p = Pattern.compile("(\\d+):(\\d+)( a.m.| p.m.| AM | PM|)"); Matcher m = p.matcher(hh_colon_mm); int retval = 0; @@ -131,4 +134,16 @@ public class DateUtil { return String.format(MainApp.sResources.getString(R.string.minago), mins); } + private static LongSparseArray timeStrings = new LongSparseArray<>(); + + public static String timeStringFromSeconds(int seconds) { + String cached = timeStrings.get(seconds); + if (cached != null) + return cached; + String t = DateUtils.formatDateTime(MainApp.instance(), toDate(seconds).getTime(), DateUtils.FORMAT_SHOW_TIME); + timeStrings.put(seconds, t); + return t; + } + + } \ No newline at end of file diff --git a/app/src/main/java/info/nightscout/utils/NSUpload.java b/app/src/main/java/info/nightscout/utils/NSUpload.java index e6cb358ac1..98ce8632ff 100644 --- a/app/src/main/java/info/nightscout/utils/NSUpload.java +++ b/app/src/main/java/info/nightscout/utils/NSUpload.java @@ -274,7 +274,7 @@ public class NSUpload { JSONObject data = new JSONObject(); data.put("eventType", CareportalEvent.PROFILESWITCH); data.put("duration", profileSwitch.durationInMinutes); - data.put("profile", profileSwitch.profileName); + data.put("profile", profileSwitch.getCustomizedName()); data.put("profileJson", profileSwitch.profileJson); data.put("profilePlugin", profileSwitch.profilePlugin); if (profileSwitch.isCPP) { diff --git a/app/src/main/java/info/nightscout/utils/NumberPicker.java b/app/src/main/java/info/nightscout/utils/NumberPicker.java index 1827009a94..53ffd90f7b 100644 --- a/app/src/main/java/info/nightscout/utils/NumberPicker.java +++ b/app/src/main/java/info/nightscout/utils/NumberPicker.java @@ -43,6 +43,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, Double step = 1d; NumberFormat formater; boolean allowZero = false; + TextWatcher textWatcher = null; private Handler mHandler; private ScheduledExecutorService mUpdater; @@ -95,9 +96,12 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true); // init ui components - this.minusButton = (Button) findViewById(R.id.decrement); - this.plusButton = (Button) findViewById(R.id.increment); - this.editText = (EditText) findViewById(R.id.display); + minusButton = (Button) findViewById(R.id.decrement); + minusButton.setId(View.generateViewId()); + plusButton = (Button) findViewById(R.id.increment); + plusButton.setId(View.generateViewId()); + editText = (EditText) findViewById(R.id.display); + editText.setId(View.generateViewId()); mHandler = new Handler() { @Override @@ -120,7 +124,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, plusButton.setOnTouchListener(this); plusButton.setOnKeyListener(this); plusButton.setOnClickListener(this); - this.addTextChangedListener(new TextWatcher() { + setTextWatcher(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -138,16 +142,14 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, }); } - public void removeTextChangedListener(TextWatcher textWatcher) { - editText.removeTextChangedListener(textWatcher); - } - - public void addTextChangedListener(TextWatcher textWatcher) { + public void setTextWatcher(TextWatcher textWatcher) { + this.textWatcher = textWatcher; editText.addTextChangedListener(textWatcher); } public void setParams(Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formater, boolean allowZero, TextWatcher textWatcher) { setParams(initValue, minValue, maxValue, step, formater, allowZero); + this.textWatcher = textWatcher; editText.addTextChangedListener(textWatcher); } @@ -159,12 +161,20 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener, this.formater = formater; this.allowZero = allowZero; + if (textWatcher != null) + editText.removeTextChangedListener(textWatcher); updateEditText(); + if (textWatcher != null) + editText.addTextChangedListener(textWatcher); } public void setValue(Double value) { + if (textWatcher != null) + editText.removeTextChangedListener(textWatcher); this.value = value; updateEditText(); + if (textWatcher != null) + editText.addTextChangedListener(textWatcher); } public Double getValue() { diff --git a/app/src/main/java/info/nightscout/utils/PlusMinusEditText.java b/app/src/main/java/info/nightscout/utils/PlusMinusEditText.java deleted file mode 100644 index c9949252af..0000000000 --- a/app/src/main/java/info/nightscout/utils/PlusMinusEditText.java +++ /dev/null @@ -1,210 +0,0 @@ -package info.nightscout.utils; - -import android.os.Handler; -import android.os.Message; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; - -import android.widget.ImageView; -import android.widget.TextView; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.text.NumberFormat; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; - -import info.nightscout.androidaps.MainApp; -import info.nightscout.androidaps.R; - -/** - * Created by mike on 28.06.2016. - */ -public class PlusMinusEditText implements View.OnKeyListener, - View.OnTouchListener, View.OnClickListener { - private static Logger log = LoggerFactory.getLogger(PlusMinusEditText.class); - - Integer editTextID; - TextView editText; - ImageView minusImage; - ImageView plusImage; - - Double value; - Double minValue = 0d; - Double maxValue = 1d; - Double step = 1d; - NumberFormat formater; - boolean allowZero = false; - - private Handler mHandler; - private ScheduledExecutorService mUpdater; - - private class UpdateCounterTask implements Runnable { - private boolean mInc; - private int repeated = 0; - private int multiplier = 1; - - private final int doubleLimit = 5; - - public UpdateCounterTask(boolean inc) { - mInc = inc; - } - - public void run() { - Message msg = new Message(); - if (repeated % doubleLimit == 0) multiplier *= 2; - repeated++; - msg.arg1 = multiplier; - msg.arg2 = repeated; - if (mInc) { - msg.what = MSG_INC; - } else { - msg.what = MSG_DEC; - } - mHandler.sendMessage(msg); - } - } - - private static final int MSG_INC = 0; - private static final int MSG_DEC = 1; - - public PlusMinusEditText(View view, int editTextID, int plusID, int minusID, Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formater, boolean allowZero) { - editText = (TextView) view.findViewById(editTextID); - minusImage = (ImageView) view.findViewById(minusID); - plusImage = (ImageView) view.findViewById(plusID); - - this.value = initValue; - this.minValue = minValue; - this.maxValue = maxValue; - this.step = step; - this.formater = formater; - this.allowZero = allowZero; - - mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_INC: - inc(msg.arg1); - return; - case MSG_DEC: - dec(msg.arg1); - return; - } - super.handleMessage(msg); - } - }; - - minusImage.setOnTouchListener(this); - minusImage.setOnKeyListener(this); - minusImage.setOnClickListener(this); - plusImage.setOnTouchListener(this); - plusImage.setOnKeyListener(this); - plusImage.setOnClickListener(this); - updateEditText(); - } - - public void setValue(Double value) { - this.value = value; - updateEditText(); - } - - public Double getValue() { - return value; - } - - public String getText() { - return editText.getText().toString(); - } - - public void setStep(Double step) { - this.step = step; - } - - private void inc(int multiplier) { - value += step * multiplier; - if (value > maxValue) { - value = maxValue; - ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.youareonallowedlimit)); - stopUpdating(); - } - updateEditText(); - } - - private void dec( int multiplier) { - value -= step * multiplier; - if (value < minValue) { - value = minValue; - ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.sResources.getString(R.string.youareonallowedlimit)); - stopUpdating(); - } - updateEditText(); - } - - private void updateEditText() { - if (value == 0d && !allowZero) - editText.setText(""); - else - editText.setText(formater.format(value)); - } - - private void startUpdating(boolean inc) { - if (mUpdater != null) { - log.debug("Another executor is still active"); - return; - } - mUpdater = Executors.newSingleThreadScheduledExecutor(); - mUpdater.scheduleAtFixedRate(new UpdateCounterTask(inc), 200, 200, - TimeUnit.MILLISECONDS); - } - - private void stopUpdating() { - if (mUpdater != null) { - mUpdater.shutdownNow(); - mUpdater = null; - } - } - - @Override - public void onClick(View v) { - if (mUpdater == null) { - if (v == plusImage) { - inc(1); - } else { - dec(1); - } - } - } - - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - boolean isKeyOfInterest = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER; - boolean isReleased = event.getAction() == KeyEvent.ACTION_UP; - boolean isPressed = event.getAction() == KeyEvent.ACTION_DOWN - && event.getAction() != KeyEvent.ACTION_MULTIPLE; - - if (isKeyOfInterest && isReleased) { - stopUpdating(); - } else if (isKeyOfInterest && isPressed) { - startUpdating(v == plusImage); - } - return false; - } - - @Override - public boolean onTouch(View v, MotionEvent event) { - boolean isReleased = event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL; - boolean isPressed = event.getAction() == MotionEvent.ACTION_DOWN; - - if (isReleased) { - stopUpdating(); - } else if (isPressed) { - startUpdating(v == plusImage); - } - return false; - } - -} diff --git a/app/src/main/java/info/nightscout/utils/SpinnerHelper.java b/app/src/main/java/info/nightscout/utils/SpinnerHelper.java new file mode 100644 index 0000000000..84315825f5 --- /dev/null +++ b/app/src/main/java/info/nightscout/utils/SpinnerHelper.java @@ -0,0 +1,150 @@ +package info.nightscout.utils; + +import android.view.MotionEvent; +import android.view.View; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; +import android.widget.Spinner; +import android.widget.SpinnerAdapter; + +/** + * Spinner Helper class that works around some common issues + * with the stock Android Spinner + * + * A Spinner will normally call it's OnItemSelectedListener + * when you use setSelection(...) in your initialization code. + * This is usually unwanted behavior, and a common work-around + * is to use spinner.post(...) with a Runnable to assign the + * OnItemSelectedListener after layout. + * + * If you do not call setSelection(...) manually, the callback + * may be called with the first item in the adapter you have + * set. The common work-around for that is to count callbacks. + * + * While these workarounds usually *seem* to work, the callback + * may still be called repeatedly for other reasons while the + * selection hasn't actually changed. This will happen for + * example, if the user has accessibility options enabled - + * which is more common than you might think as several apps + * use this for different purposes, like detecting which + * notifications are active. + * + * Ideally, your OnItemSelectedListener callback should be + * coded defensively so that no problem would occur even + * if the callback was called repeatedly with the same values + * without any user interaction, so no workarounds are needed. + * + * This class does that for you. It keeps track of the values + * you have set with the setSelection(...) methods, and + * proxies the OnItemSelectedListener callback so your callback + * only gets called if the selected item's position differs + * from the one you have set by code, or the first item if you + * did not set it. + * + * This also means that if the user actually clicks the item + * that was previously selected by code (or the first item + * if you didn't set a selection by code), the callback will + * not fire. + * + * To implement, replace current occurrences of: + * + * Spinner spinner = + * (Spinner)findViewById(R.id.xxx); + * + * with: + * + * SpinnerHelper spinner = + * new SpinnerHelper(findViewById(R.id.xxx)) + * + * SpinnerHelper proxies the (my) most used calls to Spinner + * but not all of them. Should a method not be available, use: + * + * spinner.getSpinner().someMethod(...) + * + * Or just add the proxy method yourself :) + * + * (Quickly) Tested on devices from 2.3.6 through 4.2.2 + * + * @author Jorrit "Chainfire" Jongma + * @license WTFPL (do whatever you want with this, nobody cares) + */ +public class SpinnerHelper implements OnItemSelectedListener { + private final Spinner spinner; + private boolean userTouched; + + private int lastPosition = -1; + private OnItemSelectedListener proxiedItemSelectedListener = null; + + public SpinnerHelper(Object spinner) { + this.spinner = (spinner != null) ? (Spinner)spinner : null; + } + + public Spinner getSpinner() { + return spinner; + } + + public void setSelection(int position) { + lastPosition = Math.max(-1, position); + spinner.setSelection(position); + } + + public void setSelection(int position, boolean animate) { + lastPosition = Math.max(-1, position); + spinner.setSelection(position, animate); + } + + public void setOnItemSelectedListener(OnItemSelectedListener listener) { + proxiedItemSelectedListener = listener; + setTouchListener(); + spinner.setOnItemSelectedListener(listener == null ? null : this); + } + + public void setTouchListener() { + spinner.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + userTouched = true; + return false; + } + }); + } + + public void onItemSelected(AdapterView parent, View view, int position, long id) { + if (position != lastPosition && userTouched) { + lastPosition = position; + if (proxiedItemSelectedListener != null) { + proxiedItemSelectedListener.onItemSelected( + parent, view, position, id + ); + } + } + } + + public void onNothingSelected(AdapterView parent) { + if (-1 != lastPosition) { + lastPosition = -1; + if (proxiedItemSelectedListener != null) { + proxiedItemSelectedListener.onNothingSelected( + parent + ); + } + } + } + + public void setAdapter(SpinnerAdapter adapter) { + if (adapter.getCount() > 0) { + lastPosition = 0; + } + spinner.setAdapter(adapter); + } + + public SpinnerAdapter getAdapter() { return spinner.getAdapter(); } + public int getCount() { return spinner.getCount(); } + public Object getItemAtPosition(int position) { return spinner.getItemAtPosition(position); } + public long getItemIdAtPosition(int position) { return spinner.getItemIdAtPosition(position); } + public Object getSelectedItem() { return spinner.getSelectedItem(); } + public long getSelectedItemId() { return spinner.getSelectedItemId(); } + public int getSelectedItemPosition() { return spinner.getSelectedItemPosition(); } + public void setEnabled(boolean enabled) { spinner.setEnabled(enabled); } + public boolean isEnabled() { return spinner.isEnabled(); } +} diff --git a/app/src/main/java/info/nightscout/utils/TimeListEdit.java b/app/src/main/java/info/nightscout/utils/TimeListEdit.java index 8a1fac75a3..af3668310a 100644 --- a/app/src/main/java/info/nightscout/utils/TimeListEdit.java +++ b/app/src/main/java/info/nightscout/utils/TimeListEdit.java @@ -1,22 +1,18 @@ package info.nightscout.utils; import android.content.Context; -import android.os.Build; +import android.os.Handler; import android.support.v4.content.ContextCompat; import android.support.v4.widget.TextViewCompat; import android.text.Editable; -import android.text.Layout; import android.text.TextWatcher; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; -import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; -import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; -import android.widget.Spinner; import android.widget.TextView; import org.json.JSONArray; @@ -39,40 +35,49 @@ import info.nightscout.androidaps.R; public class TimeListEdit { private static Logger log = LoggerFactory.getLogger(TimeListEdit.class); - final int ONEHOURINSECONDS = 60 * 60; + private final int ONEHOURINSECONDS = 60 * 60; - LinearLayout layout; + private View[] intervals = new View[24]; + private SpinnerHelper[] spinners = new SpinnerHelper[24]; + private NumberPicker[] numberPickers1 = new NumberPicker[24]; + private NumberPicker[] numberPickers2 = new NumberPicker[24]; + private ImageView[] addButtons = new ImageView[24]; + private ImageView[] removeButtons = new ImageView[24]; + private ImageView finalAdd; - Context context; - View view; - int resLayoutId; - String label; - JSONArray data1; - JSONArray data2; - NumberFormat formatter; - Runnable save; + private Context context; + private View view; + private int resLayoutId; + private String label; + private JSONArray data1; + private JSONArray data2; + private double step; + private NumberFormat formatter; + private Runnable save; + private LinearLayout layout; + private TextView textlabel; + private int inflatedUntil = -1; - public TimeListEdit(Context context, View view, int resLayoutId, String label, JSONArray data1, JSONArray data2, NumberFormat formatter, Runnable save) { + + public TimeListEdit(Context context, View view, int resLayoutId, String label, JSONArray data1, JSONArray data2, double step, NumberFormat formatter, Runnable save) { this.context = context; this.view = view; this.resLayoutId = resLayoutId; this.label = label; this.data1 = data1; this.data2 = data2; + this.step = step; this.formatter = formatter; this.save = save; buildView(); } private void buildView() { - LayoutInflater inflater = LayoutInflater.from(context); layout = (LinearLayout) view.findViewById(resLayoutId); - layout.removeAllViews(); - - TextView textlabel = new TextView(context); + textlabel = new TextView(context); textlabel.setText(label); - textlabel.setGravity(Gravity.LEFT); + textlabel.setGravity(Gravity.START); LinearLayout.LayoutParams llp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); llp.setMargins(10, 0, 0, 0); // llp.setMargins(left, top, right, bottom); textlabel.setLayoutParams(llp); @@ -80,177 +85,219 @@ public class TimeListEdit { TextViewCompat.setTextAppearance(textlabel, android.R.style.TextAppearance_Medium); layout.addView(textlabel); - for (int i = 0; i < itemsCount(); i++) { - View childview = inflater.inflate(R.layout.timelistedit_element, layout, false); - childview.setId(View.generateViewId()); - final Spinner timeSpinner = (Spinner) childview.findViewById(R.id.timelistedit_time); - timeSpinner.setId(View.generateViewId()); - int previous = i == 0 ? -1 * ONEHOURINSECONDS : secondFromMidnight(i - 1); - int next = i == itemsCount() - 1 ? 24 * ONEHOURINSECONDS : secondFromMidnight(i + 1); - if (i == 0) next = ONEHOURINSECONDS; - fillSpinner(timeSpinner, secondFromMidnight(i), previous, next); + for (int i = 0; i < 24 && i < itemsCount(); i++) { + inflateRow(i); + inflatedUntil = i; + } - final EditText editText1 = (EditText) childview.findViewById(R.id.timelistedit_edit1); - editText1.setId(View.generateViewId()); - fillNumber(editText1, value1(i)); - final EditText editText2 = ((EditText) childview.findViewById(R.id.timelistedit_edit2)); - fillNumber(editText2, value2(i)); - editText2.setId(View.generateViewId()); - if (data2 == null) { - editText2.setVisibility(View.GONE); + // last "plus" to append new interval + finalAdd = new ImageView(context); + finalAdd.setImageResource(R.drawable.add); + LinearLayout.LayoutParams illp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); + illp.setMargins(0, 25, 0, 25); // llp.setMargins(left, top, right, bottom); + illp.gravity = Gravity.CENTER; + layout.addView(finalAdd); + finalAdd.setLayoutParams(illp); + finalAdd.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + addItem(itemsCount(), itemsCount() > 0 ? secondFromMidnight(itemsCount() - 1) + ONEHOURINSECONDS : 0, 0, 0); + callSave(); + log(); + fillView(); } + }); + fillView(); + } - ImageView addbutton = (ImageView) childview.findViewById(R.id.timelistedit_add); - addbutton.setId(View.generateViewId()); - ImageView removebutton = (ImageView) childview.findViewById(R.id.timelistedit_remove); - removebutton.setId(View.generateViewId()); + private void inflateRow(int i) { - if (itemsCount() == 1 && i == 0) { - removebutton.setVisibility(View.GONE); - } + LayoutInflater inflater = LayoutInflater.from(context); + View childview = intervals[i] = inflater.inflate(R.layout.timelistedit_element, layout, false); + spinners[i] = new SpinnerHelper(childview.findViewById(R.id.timelistedit_time)); + numberPickers1[i] = (NumberPicker) childview.findViewById(R.id.timelistedit_edit1); + numberPickers2[i] = (NumberPicker) childview.findViewById(R.id.timelistedit_edit2); + addButtons[i] = (ImageView) childview.findViewById(R.id.timelistedit_add); + removeButtons[i] = (ImageView) childview.findViewById(R.id.timelistedit_remove); - if (itemsCount() >= 24) { - addbutton.setVisibility(View.GONE); - } - - final int fixedPos = i; - addbutton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - int seconds = secondFromMidnight(fixedPos); - addItem(fixedPos, seconds, 0, 0); - // for here for the rest of values - for (int i = fixedPos + 1; i < itemsCount(); i++) { - if (secondFromMidnight(i - 1) >= secondFromMidnight(i)) { - editItem(i, secondFromMidnight(i - 1) + ONEHOURINSECONDS, value1(i), value2(i)); - } + final int fixedPos = i; + addButtons[i].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + int seconds = secondFromMidnight(fixedPos); + addItem(fixedPos, seconds, 0, 0); + // for here for the rest of values + for (int i = fixedPos + 1; i < itemsCount(); i++) { + if (secondFromMidnight(i - 1) >= secondFromMidnight(i)) { + editItem(i, secondFromMidnight(i - 1) + ONEHOURINSECONDS, value1(i), value2(i)); } - while (itemsCount() > 24 || secondFromMidnight(itemsCount() - 1) > 23 * ONEHOURINSECONDS) - removeItem(itemsCount() - 1); - log(); - buildView(); } - }); + while (itemsCount() > 24 || secondFromMidnight(itemsCount() - 1) > 23 * ONEHOURINSECONDS) + removeItem(itemsCount() - 1); + callSave(); + log(); + fillView(); + } + }); - removebutton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - removeItem(fixedPos); - log(); - buildView(); + removeButtons[i].setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + removeItem(fixedPos); + callSave(); + log(); + fillView(); + } + }); + + spinners[i].setOnItemSelectedListener( + new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + int seconds = DateUtil.toSeconds(spinners[fixedPos].getSelectedItem().toString()); + editItem(fixedPos, seconds, value1(fixedPos), value2(fixedPos)); + log(); + callSave(); + fillView(); + } + + @Override + public void onNothingSelected(AdapterView parent) { + } } - }); + ); - timeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - int seconds = DateUtil.toSeconds(timeSpinner.getSelectedItem().toString()); - editItem(fixedPos, seconds, value1(fixedPos), value2(fixedPos)); - log(); - buildView(); - } + numberPickers1[i].setTextWatcher(new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + editItem(fixedPos, secondFromMidnight(fixedPos), SafeParse.stringToDouble(numberPickers1[fixedPos].getText()), value2(fixedPos)); + callSave(); + log(); + } - @Override - public void onNothingSelected(AdapterView parent) { - editItem(fixedPos, 0, value1(fixedPos), value2(fixedPos)); - log(); - buildView(); - } - } - ); + @Override + public void beforeTextChanged(CharSequence s, int start, + int count, int after) { + } - editText1.addTextChangedListener(new TextWatcher() { - @Override - public void afterTextChanged(Editable s) { - editItem(fixedPos, secondFromMidnight(fixedPos), SafeParse.stringToDouble(editText1.getText().toString()), value2(fixedPos)); - log(); - } + @Override + public void onTextChanged(CharSequence s, int start, + int before, int count) { + } + }); - @Override - public void beforeTextChanged(CharSequence s, int start, - int count, int after) { - } - @Override - public void onTextChanged(CharSequence s, int start, - int before, int count) { - } - }); + numberPickers2[i].setTextWatcher(new TextWatcher() { + @Override + public void afterTextChanged(Editable s) { + editItem(fixedPos, secondFromMidnight(fixedPos), value1(fixedPos), SafeParse.stringToDouble(numberPickers2[fixedPos].getText())); + callSave(); + log(); + } - editText2.addTextChangedListener(new TextWatcher() { - @Override - public void afterTextChanged(Editable s) { - editItem(fixedPos, secondFromMidnight(fixedPos), value1(fixedPos), SafeParse.stringToDouble(editText2.getText().toString())); - log(); - } + @Override + public void beforeTextChanged(CharSequence s, int start, + int count, int after) { + } - @Override - public void beforeTextChanged(CharSequence s, int start, - int count, int after) { - } + @Override + public void onTextChanged(CharSequence s, int start, + int before, int count) { + } + }); - @Override - public void onTextChanged(CharSequence s, int start, - int before, int count) { - } - }); + layout.addView(childview); + } - layout.addView(childview); + private void fillView() { + for (int i = 0; i < 24; i++) { + if (i < itemsCount()) { + intervals[i].setVisibility(View.VISIBLE); + buildInterval(i); + } else if (i <= inflatedUntil){ + intervals[i].setVisibility(View.GONE); + } } if (!(itemsCount() > 0 && secondFromMidnight(itemsCount() - 1) == 23 * ONEHOURINSECONDS)) { - ImageView imageView = new ImageView(context); - imageView.setImageResource(R.drawable.add); - LinearLayout.LayoutParams illp = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); - illp.setMargins(0, 25, 0, 25); // llp.setMargins(left, top, right, bottom); - illp.gravity = Gravity.CENTER; - layout.addView(imageView); - imageView.setLayoutParams(illp); - imageView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - addItem(itemsCount(), itemsCount() > 0 ? secondFromMidnight(itemsCount() - 1) + ONEHOURINSECONDS : 0, 0, 0); - log(); - buildView(); - } - }); + finalAdd.setVisibility(View.VISIBLE); + } else { + finalAdd.setVisibility(View.GONE); } - } - public void fillSpinner(Spinner spinner, int secondsFromMidnight, int previous, int next) { + private View buildInterval(int i) { + SpinnerHelper timeSpinner = spinners[i]; + View childview = intervals[i]; + final NumberPicker editText1 = numberPickers1[i]; + final NumberPicker editText2 = numberPickers2[i]; + + + int previous = i == 0 ? -1 * ONEHOURINSECONDS : secondFromMidnight(i - 1); + int next = i == itemsCount() - 1 ? 24 * ONEHOURINSECONDS : secondFromMidnight(i + 1); + if (i == 0) next = ONEHOURINSECONDS; + fillSpinner(timeSpinner, secondFromMidnight(i), previous, next); + + editText1.setParams(value1(i), 0.1d, 100d, step, formatter, false); + editText2.setParams(value2(i), 0.1d, 100d, step, formatter, false); + + if (data2 == null) { + editText2.setVisibility(View.GONE); + } + + + if (itemsCount() == 1 || i == 0) { + removeButtons[i].setVisibility(View.INVISIBLE); + } else + removeButtons[i].setVisibility(View.VISIBLE); + + if (itemsCount() >= 24 || secondFromMidnight(i) >= 82800) { + addButtons[i].setVisibility(View.INVISIBLE); + } else { + addButtons[i].setVisibility(View.VISIBLE); + } + + return childview; + } + + private void fillSpinner(final SpinnerHelper spinner, int secondsFromMidnight, int previous, int next) { int posInList = 0; ArrayList timeList = new ArrayList<>(); int pos = 0; for (int t = previous + ONEHOURINSECONDS; t < next; t += ONEHOURINSECONDS) { - timeList.add(DateUtil.timeString(DateUtil.toDate(t))); + timeList.add(DateUtil.timeStringFromSeconds(t)); if (secondsFromMidnight == t) posInList = pos; pos++; } - ArrayAdapter adapter = new ArrayAdapter(context, + final ArrayAdapter adapter = new ArrayAdapter<>(context, R.layout.spinner_centered, timeList); spinner.setAdapter(adapter); - spinner.setSelection(posInList, false); + final int finalPosInList = posInList; + new Handler().postDelayed(new Runnable() { + public void run() { + spinner.setSelection(finalPosInList, false); + adapter.notifyDataSetChanged(); + } + }, 100); } - public void fillNumber(EditText edit, Double value) { - if (value.equals(0d)) - edit.setText(""); - else - edit.setText(formatter.format(value)); - } - - public int itemsCount() { + private int itemsCount() { return data1.length(); } - public int secondFromMidnight(int index) { + private int secondFromMidnight(int index) { try { JSONObject item = (JSONObject) data1.get(index); if (item.has("timeAsSeconds")) { - return item.getInt("timeAsSeconds"); + int time = item.getInt("timeAsSeconds"); + if (index == 0 && time != 0) { + // fix the bug, every array must start with 0 + item.put("timeAsSeconds", 0); + time = 0; + } + return time; } } catch (JSONException e) { log.error("Unhandled exception", e); @@ -258,7 +305,7 @@ public class TimeListEdit { return 0; } - public double value1(int index) { + private double value1(int index) { try { JSONObject item = (JSONObject) data1.get(index); if (item.has("value")) { @@ -270,7 +317,7 @@ public class TimeListEdit { return 0d; } - public double value2(int index) { + private double value2(int index) { if (data2 != null) { try { JSONObject item = (JSONObject) data2.get(index); @@ -284,7 +331,7 @@ public class TimeListEdit { return 0d; } - public void editItem(int index, int timeAsSeconds, double value1, double value2) { + private void editItem(int index, int timeAsSeconds, double value1, double value2) { try { String time; int hour = timeAsSeconds / 60 / 60; @@ -303,14 +350,18 @@ public class TimeListEdit { newObject2.put("value", value2); data2.put(index, newObject2); } - if (save != null) save.run(); } catch (JSONException e) { log.error("Unhandled exception", e); } } - public void addItem(int index, int timeAsSeconds, double value1, double value2) { + private void addItem(int index, int timeAsSeconds, double value1, double value2) { + if(itemsCount()>inflatedUntil) { + layout.removeView(finalAdd); + inflateRow(++inflatedUntil); + layout.addView(finalAdd); + } try { // shift data for (int i = data1.length(); i > index; i--) { @@ -320,24 +371,33 @@ public class TimeListEdit { } // add new object editItem(index, timeAsSeconds, value1, value2); - if (save != null) save.run(); } catch (JSONException e) { log.error("Unhandled exception", e); } } - public void removeItem(int index) { + private void removeItem(int index) { data1.remove(index); if (data2 != null) data2.remove(index); + } + + private void log() { + if (log.isDebugEnabled()) { + for (int i = 0; i < data1.length(); i++) { + log.debug(i + ": @" + DateUtil.timeStringFromSeconds(secondFromMidnight(i)) + " " + value1(i) + (data2 != null ? " " + value2(i) : "")); + } + } + } + + private void callSave() { if (save != null) save.run(); } - void log() { - for (int i = 0; i < data1.length(); i++) { - int pos = 0; - log.debug(i + ": @" + DateUtil.timeString(DateUtil.toDate(secondFromMidnight(i))) + " " + value1(i) + (data2 != null ? " " + value2(i) : "")); - } + public void updateLabel(String txt){ + this.label = txt; + if(textlabel!=null) + textlabel.setText(txt); } } 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 0000000000..69e283b5fe Binary files /dev/null and b/app/src/main/jniLibs/arm64-v8a/libBleCommandUtil.so differ 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 0000000000..0c717bc3e8 Binary files /dev/null and b/app/src/main/jniLibs/armeabi-v7a/libBleCommandUtil.so differ diff --git a/app/src/main/jniLibs/armeabi/libBleCommandUtil.so b/app/src/main/jniLibs/armeabi/libBleCommandUtil.so new file mode 100644 index 0000000000..a51a8c7d9a Binary files /dev/null and b/app/src/main/jniLibs/armeabi/libBleCommandUtil.so differ diff --git a/app/src/main/jniLibs/mips/libBleCommandUtil.so b/app/src/main/jniLibs/mips/libBleCommandUtil.so new file mode 100644 index 0000000000..fcff5eb6b2 Binary files /dev/null and b/app/src/main/jniLibs/mips/libBleCommandUtil.so differ diff --git a/app/src/main/jniLibs/mips64/libBleCommandUtil.so b/app/src/main/jniLibs/mips64/libBleCommandUtil.so new file mode 100644 index 0000000000..a8a292ea13 Binary files /dev/null and b/app/src/main/jniLibs/mips64/libBleCommandUtil.so differ diff --git a/app/src/main/jniLibs/x86/libBleCommandUtil.so b/app/src/main/jniLibs/x86/libBleCommandUtil.so new file mode 100644 index 0000000000..638a9def95 Binary files /dev/null and b/app/src/main/jniLibs/x86/libBleCommandUtil.so differ diff --git a/app/src/main/jniLibs/x86_64/libBleCommandUtil.so b/app/src/main/jniLibs/x86_64/libBleCommandUtil.so new file mode 100644 index 0000000000..94873d3732 Binary files /dev/null and b/app/src/main/jniLibs/x86_64/libBleCommandUtil.so differ diff --git a/app/src/main/res/layout/actions_fill_dialog.xml b/app/src/main/res/layout/actions_fill_dialog.xml index e6fb0b05ee..55e44f4bc7 100644 --- a/app/src/main/res/layout/actions_fill_dialog.xml +++ b/app/src/main/res/layout/actions_fill_dialog.xml @@ -6,51 +6,37 @@ android:orientation="vertical" android:padding="10dp"> - - - - - - + android:text="@string/treatments_newtreatment_insulinamount_label" + android:textAppearance="@android:style/TextAppearance.Material.Small" + android:textStyle="bold" /> - + + + android:layout_gravity="center_vertical" + android:gravity="left" + android:minWidth="45dp" + android:paddingLeft="5dp" + android:text="U" + android:textAppearance="?android:attr/textAppearanceSmall" /> + + + + +