Skip to content
Snippets Groups Projects
Commit 10b50651 authored by Pogman's avatar Pogman Committed by GitHub
Browse files

Merge pull request #139 from pazaan/develop

Develop
parents aa364ad9 43612607
No related branches found
No related tags found
No related merge requests found
...@@ -158,6 +158,7 @@ dependencies { ...@@ -158,6 +158,7 @@ dependencies {
compile 'com.android.support:cardview-v7:25.3.1' compile 'com.android.support:cardview-v7:25.3.1'
compile 'org.apache.commons:commons-lang3:3.4' compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.mikepenz:google-material-typeface:2.2.0.1.original@aar' compile 'com.mikepenz:google-material-typeface:2.2.0.1.original@aar'
compile 'com.mikepenz:ionicons-typeface:2.0.1.3@aar'
compile 'uk.co.chrisjenx:calligraphy:2.2.0' compile 'uk.co.chrisjenx:calligraphy:2.2.0'
compile 'com.bugfender.sdk:android:0.7.2' compile 'com.bugfender.sdk:android:0.7.2'
compile 'com.jjoe64:graphview:4.0.1' compile 'com.jjoe64:graphview:4.0.1'
......
...@@ -461,9 +461,9 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc ...@@ -461,9 +461,9 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
} }
private void statusStartup() { private void statusStartup() {
sendStatus("Nightscout 600 Series Uploader"); sendStatus(MedtronicCnlIntentService.ICON_HEART + "Nightscout 600 Series Uploader");
sendStatus("Poll interval: " + (configurationStore.getPollInterval() / 60000) +" minutes"); sendStatus(MedtronicCnlIntentService.ICON_SETTING + "Poll interval: " + (configurationStore.getPollInterval() / 60000) +" minutes");
sendStatus("Low battery poll interval: " + (configurationStore.getLowBatteryPollInterval() / 60000) +" minutes"); sendStatus(MedtronicCnlIntentService.ICON_SETTING + "Low battery poll interval: " + (configurationStore.getLowBatteryPollInterval() / 60000) +" minutes");
} }
private void refreshDisplay() { private void refreshDisplay() {
...@@ -1036,7 +1036,8 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc ...@@ -1036,7 +1036,8 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
if (mEnableCgmService) { if (mEnableCgmService) {
clearDisconnectionNotification(); clearDisconnectionNotification();
} }
sendStatus("⚠ USB plugged in. Contour Next Link connected."); dataStore.clearAllCommsErrors();
sendStatus(MedtronicCnlIntentService.ICON_INFO + "Contour Next Link plugged in.");
if (hasUsbPermission()) { if (hasUsbPermission()) {
// Give the USB a little time to warm up first // Give the USB a little time to warm up first
startCgmServiceDelayed(MedtronicCnlIntentService.USB_WARMUP_TIME_MS); startCgmServiceDelayed(MedtronicCnlIntentService.USB_WARMUP_TIME_MS);
...@@ -1048,7 +1049,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc ...@@ -1048,7 +1049,7 @@ public class MainActivity extends AppCompatActivity implements OnSharedPreferenc
Log.d(TAG, "USB unplugged"); Log.d(TAG, "USB unplugged");
if (mEnableCgmService) { if (mEnableCgmService) {
showDisconnectionNotification("USB Error", "Contour Next Link unplugged."); showDisconnectionNotification("USB Error", "Contour Next Link unplugged.");
sendStatus("⚠ USB error. Contour Next Link unplugged."); sendStatus(MedtronicCnlIntentService.ICON_WARN + "USB error. Contour Next Link unplugged.");
} }
} else if (MedtronicCnlIntentService.Constants.ACTION_NO_USB_PERMISSION.equals(action)) { } else if (MedtronicCnlIntentService.Constants.ACTION_NO_USB_PERMISSION.equals(action)) {
Log.d(TAG, "No permission to read the USB device."); Log.d(TAG, "No permission to read the USB device.");
......
...@@ -51,7 +51,23 @@ public class MedtronicCnlIntentService extends IntentService { ...@@ -51,7 +51,23 @@ public class MedtronicCnlIntentService extends IntentService {
public final static long POLL_GRACE_PERIOD_MS = 30000L; public final static long POLL_GRACE_PERIOD_MS = 30000L;
public final static long POLL_PRE_GRACE_PERIOD_MS = 45000L; public final static long POLL_PRE_GRACE_PERIOD_MS = 45000L;
private final static int ERROR_WARNING = 4; // show warning message after repeated comms errors public static final String ICON_WARN = "{ion-alert-circled} ";
public static final String ICON_BGL = "{ion-waterdrop} ";
public static final String ICON_USB = "{ion-usb} ";
public static final String ICON_INFO = "{ion-information_circled} ";
public static final String ICON_HELP = "{ion-ios-lightbulb} ";
public static final String ICON_SETTING = "{ion-android-settings} ";
public static final String ICON_HEART = "{ion-heart} ";
public static final String ICON_STAR = "{ion-ios-star} ";
// show warning message after repeated errors
private final static int ERROR_COMMS_AT = 4;
private final static int ERROR_CONNECT_AT = 4;
private final static int ERROR_SIGNAL_AT = 4;
private final static float ERROR_UNAVAILABLE_AT = 12; // warning at
private final static float ERROR_UNAVAILABLE_RATE = 12 / 3; // expected per hour / acceptable unavailable per hour
private final static float ERROR_UNAVAILABLE_DECAY = -1; // decay rate for each good sgv received
private static final String TAG = MedtronicCnlIntentService.class.getSimpleName(); private static final String TAG = MedtronicCnlIntentService.class.getSimpleName();
private UsbHidDriver mHidDevice; private UsbHidDriver mHidDevice;
...@@ -141,9 +157,10 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -141,9 +157,10 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
final long timePollStarted = System.currentTimeMillis(); final long timePollStarted = System.currentTimeMillis();
long timeLastGoodSGV = 0; long timeLastGoodSGV = dataStore.getLastPumpStatus().getSgvDate().getTime();
if (dataStore.getLastPumpStatus().getSgv() > 0) { if (dataStore.getLastPumpStatus().getSgv() == 0
timeLastGoodSGV = dataStore.getLastPumpStatus().getSgvDate().getTime(); || timePollStarted - timeLastGoodSGV > 24 * 60 * 60 * 1000) {
timeLastGoodSGV = 0;
} }
final long timePollExpected; final long timePollExpected;
...@@ -164,9 +181,9 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -164,9 +181,9 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
long pollInterval = configurationStore.getPollInterval(); long pollInterval = configurationStore.getPollInterval();
if ((pumpBatteryLevel > 0) && (pumpBatteryLevel <= 25)) { if ((pumpBatteryLevel > 0) && (pumpBatteryLevel <= 25)) {
pollInterval = configurationStore.getLowBatteryPollInterval(); pollInterval = configurationStore.getLowBatteryPollInterval();
sendStatus("⚠ Warning: pump battery low"); sendStatus(ICON_WARN + "Warning: pump battery low");
if (pollInterval != configurationStore.getPollInterval()) { if (pollInterval != configurationStore.getPollInterval()) {
sendStatus("Poll interval: " + (pollInterval / 60000) +" minutes"); sendStatus(ICON_SETTING + "Low battery poll interval: " + (pollInterval / 60000) +" minutes");
} }
} }
...@@ -234,15 +251,25 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -234,15 +251,25 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
byte radioChannel = cnlReader.negotiateChannel(activePump.getLastRadioChannel()); byte radioChannel = cnlReader.negotiateChannel(activePump.getLastRadioChannel());
if (radioChannel == 0) { if (radioChannel == 0) {
sendStatus("⚠ Could not communicate with the pump. Is it nearby?"); sendStatus(ICON_WARN + "Could not communicate with the pump. Is it nearby?");
Log.i(TAG, "Could not communicate with the pump. Is it nearby?"); Log.i(TAG, "Could not communicate with the pump. Is it nearby?");
dataStore.incCommsConnectThreshold();
pollInterval = configurationStore.getPollInterval() / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available pollInterval = configurationStore.getPollInterval() / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available
} else if (cnlReader.getPumpSession().getRadioRSSIpercentage() < 5) { } else if (cnlReader.getPumpSession().getRadioRSSIpercentage() < 5) {
sendStatus(String.format(Locale.getDefault(), "Connected on channel %d RSSI: %d%%", (int) radioChannel, cnlReader.getPumpSession().getRadioRSSIpercentage())); sendStatus(String.format(Locale.getDefault(), "Connected on channel %d RSSI: %d%%", (int) radioChannel, cnlReader.getPumpSession().getRadioRSSIpercentage()));
sendStatus("⚠ Warning: pump signal too weak. Is it nearby?"); sendStatus(ICON_WARN + "Warning: pump signal too weak. Is it nearby?");
Log.i(TAG, "Warning: pump signal too weak. Is it nearby?"); Log.i(TAG, "Warning: pump signal too weak. Is it nearby?");
dataStore.incCommsConnectThreshold();
dataStore.incCommsSignalThreshold();
pollInterval = configurationStore.getPollInterval() / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available pollInterval = configurationStore.getPollInterval() / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); // reduce polling interval to half until pump is available
} else { } else {
dataStore.decCommsConnectThreshold();
if (cnlReader.getPumpSession().getRadioRSSIpercentage() < 20) {
if (dataStore.getCommsSignalThreshold() < ERROR_SIGNAL_AT) dataStore.incCommsSignalThreshold();
} else {
dataStore.decCommsSignalThreshold();
}
dataStore.setActivePumpMac(pumpMAC); dataStore.setActivePumpMac(pumpMAC);
activePump.setLastRadioChannel(radioChannel); activePump.setLastRadioChannel(radioChannel);
...@@ -263,8 +290,9 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -263,8 +290,9 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
Log.d(TAG, "Time offset between pump and device: " + pumpOffset + " millis."); Log.d(TAG, "Time offset between pump and device: " + pumpOffset + " millis.");
if (Math.abs(pumpOffset) > 10 * 60 * 1000) { if (Math.abs(pumpOffset) > 10 * 60 * 1000) {
sendStatus("⚠ Warning: Time difference between Pump and Uploader excessive." sendStatus(ICON_WARN + "Warning: Time difference between Pump and Uploader excessive."
+ " Pump is over " + (Math.abs(pumpOffset) / 60000L) + " minutes " + (pumpOffset > 0 ? "ahead" : "behind") + " of time used by uploader."); + " Pump is over " + (Math.abs(pumpOffset) / 60000L) + " minutes " + (pumpOffset > 0 ? "ahead" : "behind") + " of time used by uploader.");
sendStatus(ICON_HELP + "The uploader phone/device should have the current time provided by network. Pump clock drifts forward and needs to be set to correct time occasionally.");
} }
// TODO - send ACTION to MainActivity to show offset between pump and uploader. // TODO - send ACTION to MainActivity to show offset between pump and uploader.
...@@ -281,11 +309,14 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -281,11 +309,14 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
dataStore.getLastPumpStatus().getSgvDate() != null && dataStore.getLastPumpStatus().getSgvDate() != null &&
pumpRecord.getSgvDate().getTime() - dataStore.getLastPumpStatus().getSgvDate().getTime() < 5000L && pumpRecord.getSgvDate().getTime() - dataStore.getLastPumpStatus().getSgvDate().getTime() < 5000L &&
timePollExpected - timePollStarted < 5000L) { timePollExpected - timePollStarted < 5000L) {
sendStatus("⚠ Pump sent old SGV event"); sendStatus(ICON_WARN + "Pump sent old SGV event");
if (dataStore.getCommsUnavailableThreshold() < ERROR_UNAVAILABLE_AT) dataStore.addCommsUnavailableThreshold(ERROR_UNAVAILABLE_RATE / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L));
// pump may have missed sensor transmission or be delayed in posting to status message // pump may have missed sensor transmission or be delayed in posting to status message
// in most cases the next scheduled poll will have latest sgv, occasionally it is available this period after a delay // in most cases the next scheduled poll will have latest sgv, occasionally it is available this period after a delay
// if user selects double poll option we try again this period or wait until next // if user selects double poll option we try again this period or wait until next
pollInterval = POLL_PERIOD_MS / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L); pollInterval = POLL_PERIOD_MS / (configurationStore.isReducePollOnPumpAway() ? 2L : 1L);
} else {
dataStore.addCommsUnavailableThreshold(ERROR_UNAVAILABLE_DECAY);
} }
dataStore.clearUnavailableSGVCount(); // reset unavailable sgv count dataStore.clearUnavailableSGVCount(); // reset unavailable sgv count
...@@ -299,16 +330,18 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -299,16 +330,18 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
// There should be the 1 record we've already added in this transaction. // There should be the 1 record we've already added in this transaction.
if (checkExistingRecords.size() == 0) { if (checkExistingRecords.size() == 0) {
timeLastGoodSGV = pumpRecord.getSgvDate().getTime();
activePump.getPumpHistory().add(pumpRecord); activePump.getPumpHistory().add(pumpRecord);
dataStore.setLastPumpStatus(pumpRecord); dataStore.setLastPumpStatus(pumpRecord);
if (pumpRecord.getBolusWizardBGL() != 0) { if (pumpRecord.getBolusWizardBGL() != 0) {
sendStatus("☝ Recent finger BG: " + MainActivity.strFormatSGV(pumpRecord.getBolusWizardBGL())); sendStatus(ICON_BGL +"Recent finger BG: " + MainActivity.strFormatSGV(pumpRecord.getBolusWizardBGL()));
} }
} }
} else { } else {
sendStatus("⚠ SGV: unavailable from pump"); sendStatus(ICON_WARN + "SGV: unavailable from pump");
dataStore.incUnavailableSGVCount(); // poll clash detection dataStore.incUnavailableSGVCount(); // poll clash detection
if (dataStore.getCommsUnavailableThreshold() < ERROR_UNAVAILABLE_AT) dataStore.addCommsUnavailableThreshold(ERROR_UNAVAILABLE_RATE);
} }
realm.commitTransaction(); realm.commitTransaction();
...@@ -322,15 +355,15 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -322,15 +355,15 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
pollInterval = 60000L; // retry once during this poll period, this allows for transient radio noise pollInterval = 60000L; // retry once during this poll period, this allows for transient radio noise
Log.e(TAG, "Unexpected Message", e); Log.e(TAG, "Unexpected Message", e);
sendStatus("⚠ Communication Error: " + e.getMessage()); sendStatus(ICON_WARN + "Communication Error: " + e.getMessage());
} catch (TimeoutException e) { } catch (TimeoutException e) {
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
pollInterval = 90000L; // retry once during this poll period, this allows for transient radio noise pollInterval = 90000L; // retry once during this poll period, this allows for transient radio noise
Log.e(TAG, "Timeout communicating with the Contour Next Link.", e); Log.e(TAG, "Timeout communicating with the Contour Next Link.", e);
sendStatus("⚠ Timeout communicating with the Contour Next Link / Pump."); sendStatus(ICON_WARN + "Timeout communicating with the Contour Next Link / Pump.");
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
Log.e(TAG, "Could not determine CNL HMAC", e); Log.e(TAG, "Could not determine CNL HMAC", e);
sendStatus("⚠ Error connecting to Contour Next Link: Hashing error."); sendStatus(ICON_WARN + "Error connecting to Contour Next Link: Hashing error.");
} finally { } finally {
try { try {
cnlReader.closeConnection(); cnlReader.closeConnection();
...@@ -343,23 +376,23 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -343,23 +376,23 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
} catch (IOException e) { } catch (IOException e) {
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
Log.e(TAG, "Error connecting to Contour Next Link.", e); Log.e(TAG, "Error connecting to Contour Next Link.", e);
sendStatus("⚠ Error connecting to Contour Next Link."); sendStatus(ICON_WARN + "Error connecting to Contour Next Link.");
} catch (ChecksumException e) { } catch (ChecksumException e) {
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
Log.e(TAG, "Checksum error getting message from the Contour Next Link.", e); Log.e(TAG, "Checksum error getting message from the Contour Next Link.", e);
sendStatus("⚠ Checksum error getting message from the Contour Next Link."); sendStatus(ICON_WARN + "Checksum error getting message from the Contour Next Link.");
} catch (EncryptionException e) { } catch (EncryptionException e) {
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
Log.e(TAG, "Error decrypting messages from Contour Next Link.", e); Log.e(TAG, "Error decrypting messages from Contour Next Link.", e);
sendStatus("⚠ Error decrypting messages from Contour Next Link."); sendStatus(ICON_WARN + "Error decrypting messages from Contour Next Link.");
} catch (TimeoutException e) { } catch (TimeoutException e) {
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
Log.e(TAG, "Timeout communicating with the Contour Next Link.", e); Log.e(TAG, "Timeout communicating with the Contour Next Link.", e);
sendStatus("⚠ Timeout communicating with the Contour Next Link."); sendStatus(ICON_WARN + "Timeout communicating with the Contour Next Link.");
} catch (UnexpectedMessageException e) { } catch (UnexpectedMessageException e) {
dataStore.incCommsErrorCount(); dataStore.incCommsErrorCount();
Log.e(TAG, "Could not close connection.", e); Log.e(TAG, "Could not close connection.", e);
sendStatus("⚠ Could not close connection: " + e.getMessage()); sendStatus(ICON_WARN + "Could not close connection: " + e.getMessage());
} finally { } finally {
if (!realm.isClosed()) { if (!realm.isClosed()) {
if (realm.isInTransaction()) { if (realm.isInTransaction()) {
...@@ -372,37 +405,62 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -372,37 +405,62 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
uploadPollResults(); uploadPollResults();
scheduleNextPoll(timePollStarted, timeLastGoodSGV, pollInterval); scheduleNextPoll(timePollStarted, timeLastGoodSGV, pollInterval);
if (dataStore.getCommsErrorCount() >= ERROR_WARNING) { // TODO - Refactor warning system
sendStatus("⚠ Warning: multiple comms/timeout errors detected. Try: disconnecting and reconnecting the Contour Next Link to phone / restarting phone / unpair and pair CNL with Pump."); if (dataStore.getCommsErrorCount() >= ERROR_COMMS_AT) {
sendStatus(ICON_WARN + "Warning: multiple comms/timeout errors detected.");
sendStatus(ICON_HELP + "Try: disconnecting and reconnecting the Contour Next Link to phone / restarting phone / check pairing of CNL with Pump.");
}
if (dataStore.getCommsUnavailableThreshold() >= ERROR_UNAVAILABLE_AT) {
dataStore.clearCommsUnavailableThreshold();
sendStatus(ICON_WARN + "Warning: SGV unavailable from pump is happening often. The pump is missing transmissions from the sensor / in warm-up phase / environment radio noise.");
sendStatus(ICON_HELP + "Keep pump on same side of body as sensor. Avoid using body sensor locations that can block radio signal. Sensor may be old / faulty and need changing (check pump graph for gaps).");
}
if (dataStore.getCommsConnectThreshold() >= ERROR_CONNECT_AT * (configurationStore.isReducePollOnPumpAway() ? 2 : 1)) {
dataStore.clearCommsConnectThreshold();
sendStatus(ICON_WARN + "Warning: connecting to pump is failing often.");
sendStatus(ICON_HELP + "Keep pump nearby to uploader phone/device. The body can block radio signals between pump and uploader.");
} }
if (dataStore.getCommsSignalThreshold() >= ERROR_SIGNAL_AT) {
dataStore.clearCommsSignalThreshold();
sendStatus(ICON_WARN + "Warning: RSSI radio signal from pump is generally weak and may increase errors.");
sendStatus(ICON_HELP + "Keep pump nearby to uploader phone/device. The body can block radio signals between pump and uploader.");
}
} }
} finally { } finally {
MedtronicCnlAlarmReceiver.completeWakefulIntent(intent); MedtronicCnlAlarmReceiver.completeWakefulIntent(intent);
} }
} }
// TODO - Refactor polling system and make super clear how polling is calculated and why certain precautions are needed
private void scheduleNextPoll(long timePollStarted, long timeLastGoodSGV, long pollInterval) { private void scheduleNextPoll(long timePollStarted, long timeLastGoodSGV, long pollInterval) {
// smart polling and pump-sensor poll clash detection // smart polling and pump-sensor poll clash detection
long now = System.currentTimeMillis();
long lastActualPollTime = timePollStarted; long lastActualPollTime = timePollStarted;
if (timeLastGoodSGV > 0) { if (timeLastGoodSGV > 0) {
lastActualPollTime = timeLastGoodSGV + POLL_GRACE_PERIOD_MS + (POLL_PERIOD_MS * ((System.currentTimeMillis() - (timeLastGoodSGV + POLL_GRACE_PERIOD_MS)) / POLL_PERIOD_MS)); lastActualPollTime = timeLastGoodSGV + POLL_GRACE_PERIOD_MS + (POLL_PERIOD_MS * ((now - timeLastGoodSGV + POLL_GRACE_PERIOD_MS) / POLL_PERIOD_MS));
} }
long nextActualPollTime = lastActualPollTime + POLL_PERIOD_MS; long nextActualPollTime = lastActualPollTime + POLL_PERIOD_MS;
long nextRequestedPollTime = lastActualPollTime + pollInterval; long nextRequestedPollTime = lastActualPollTime + pollInterval;
// check if request is really needed
if (nextRequestedPollTime - now < 10000L) {
nextRequestedPollTime = nextActualPollTime;
}
// extended unavailable SGV may be due to clash with the current polling time // extended unavailable SGV may be due to clash with the current polling time
// while we wait for a good SGV event, polling is auto adjusted by offsetting the next poll based on miss count // while we wait for a good SGV event, polling is auto adjusted by offsetting the next poll based on miss count
if (dataStore.getUnavailableSGVCount() > 0) { if (dataStore.getUnavailableSGVCount() > 0) {
if (timeLastGoodSGV == 0) { if (timeLastGoodSGV == 0) {
nextRequestedPollTime += POLL_PERIOD_MS / 5L; // if there is a uploader/sensor poll clash on startup then this will push the next attempt out by 60 seconds nextRequestedPollTime += POLL_PERIOD_MS / 5L; // if there is a uploader/sensor poll clash on startup then this will push the next attempt out by 60 seconds
} else if (dataStore.getUnavailableSGVCount() > 2) { } else if (dataStore.getUnavailableSGVCount() > 2) {
sendStatus("⚠ Warning: No SGV available from pump for " + dataStore.getUnavailableSGVCount() + " attempts"); sendStatus(ICON_WARN + "Warning: No SGV available from pump for " + dataStore.getUnavailableSGVCount() + " attempts");
long offsetPollTime = ((long) ((dataStore.getUnavailableSGVCount() - 2) % 5)) * (POLL_PERIOD_MS / 10L); // adjust poll time in 1/10 steps to avoid potential poll clash (max adjustment at 5/10) long offsetPollTime = ((long) ((dataStore.getUnavailableSGVCount() - 2) % 5)) * (POLL_PERIOD_MS / 10L); // adjust poll time in 1/10 steps to avoid potential poll clash (max adjustment at 5/10)
nextRequestedPollTime += offsetPollTime;
sendStatus("Adjusting poll: " + dateFormatter.format(nextRequestedPollTime) + " +" + (offsetPollTime / 1000) + "sec"); sendStatus("Adjusting poll: " + dateFormatter.format(nextRequestedPollTime) + " +" + (offsetPollTime / 1000) + "sec");
nextRequestedPollTime += offsetPollTime;
} }
} }
// check if requested poll time is too close to next actual poll time // check if requested poll time is too close to next actual poll time
if ((nextRequestedPollTime - System.currentTimeMillis()) < (POLL_PRE_GRACE_PERIOD_MS + POLL_GRACE_PERIOD_MS)) { if (nextRequestedPollTime > nextActualPollTime - POLL_GRACE_PERIOD_MS - POLL_PRE_GRACE_PERIOD_MS
&& nextRequestedPollTime < nextActualPollTime) {
nextRequestedPollTime = nextActualPollTime; nextRequestedPollTime = nextActualPollTime;
} }
MedtronicCnlAlarmManager.setAlarm(nextRequestedPollTime); MedtronicCnlAlarmManager.setAlarm(nextRequestedPollTime);
...@@ -414,14 +472,14 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -414,14 +472,14 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
*/ */
private boolean openUsbDevice() { private boolean openUsbDevice() {
if (!hasUsbHostFeature()) { if (!hasUsbHostFeature()) {
sendStatus("⚠ It appears that this device doesn't support USB OTG."); sendStatus(ICON_WARN + "It appears that this device doesn't support USB OTG.");
Log.e(TAG, "Device does not support USB OTG"); Log.e(TAG, "Device does not support USB OTG");
return false; return false;
} }
UsbDevice cnlStick = UsbHidDriver.getUsbDevice(mUsbManager, USB_VID, USB_PID); UsbDevice cnlStick = UsbHidDriver.getUsbDevice(mUsbManager, USB_VID, USB_PID);
if (cnlStick == null) { if (cnlStick == null) {
sendStatus("⚠ USB connection error. Is the Contour Next Link plugged in?"); sendStatus(ICON_WARN + "USB connection error. Is the Contour Next Link plugged in?");
Log.w(TAG, "USB connection error. Is the CNL plugged in?"); Log.w(TAG, "USB connection error. Is the CNL plugged in?");
return false; return false;
} }
...@@ -435,7 +493,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received ...@@ -435,7 +493,7 @@ CNL: unpaired PUMP: unpaired UPLOADER: unregistered = "Invalid message received
try { try {
mHidDevice.open(); mHidDevice.open();
} catch (Exception e) { } catch (Exception e) {
sendStatus("⚠ Unable to open USB device"); sendStatus(ICON_WARN + "Unable to open USB device");
Log.e(TAG, "Unable to open serial device", e); Log.e(TAG, "Unable to open serial device", e);
return false; return false;
} }
......
package info.nightscout.android.utils; package info.nightscout.android.utils;
import org.apache.commons.lang3.time.DateUtils;
import java.util.Date; import java.util.Date;
import info.nightscout.android.model.medtronicNg.PumpStatusEvent; import info.nightscout.android.model.medtronicNg.PumpStatusEvent;
...@@ -20,6 +22,9 @@ public class DataStore { ...@@ -20,6 +22,9 @@ public class DataStore {
private long activePumpMac = 0; private long activePumpMac = 0;
private int commsErrorCount = 0; private int commsErrorCount = 0;
private int commsSuccessCount = 0; private int commsSuccessCount = 0;
private int commsConnectThreshold = 0;
private int commsSignalThreshold = 0;
private float commsUnavailableThreshold = 0;
private DataStore() {} private DataStore() {}
...@@ -29,7 +34,7 @@ public class DataStore { ...@@ -29,7 +34,7 @@ public class DataStore {
// set some initial dummy values // set some initial dummy values
PumpStatusEvent dummyStatus = new PumpStatusEvent(); PumpStatusEvent dummyStatus = new PumpStatusEvent();
dummyStatus.setSgvDate(new Date()); dummyStatus.setSgvDate(DateUtils.addDays(new Date(), -1));
dummyStatus.setSgv(0); dummyStatus.setSgv(0);
// bypass setter to avoid dealing with a real Realm object // bypass setter to avoid dealing with a real Realm object
...@@ -82,12 +87,24 @@ public class DataStore { ...@@ -82,12 +87,24 @@ public class DataStore {
this.lastBolusWizardBGL = lastBolusWizardBGL; this.lastBolusWizardBGL = lastBolusWizardBGL;
} }
public long getActivePumpMac() {
return activePumpMac;
}
public void setActivePumpMac(long activePumpMac) {
this.activePumpMac = activePumpMac;
}
public int getCommsErrorCount() { public int getCommsErrorCount() {
return commsErrorCount; return commsErrorCount;
} }
public int incCommsErrorCount() { return commsErrorCount++; } public int incCommsErrorCount() { return commsErrorCount++; }
public int decCommsErrorThreshold() {
if (commsErrorCount > 0) commsErrorCount--;
return commsErrorCount;}
public void clearCommsErrorCount() { public void clearCommsErrorCount() {
this.commsErrorCount = 0; this.commsErrorCount = 0;
} }
...@@ -98,11 +115,60 @@ public class DataStore { ...@@ -98,11 +115,60 @@ public class DataStore {
public int incCommsSuccessCount() { return commsSuccessCount++; } public int incCommsSuccessCount() { return commsSuccessCount++; }
public long getActivePumpMac() { public int decCommsSuccessCount() {
return activePumpMac; if (commsSuccessCount > 0) commsSuccessCount--;
return commsSuccessCount;}
public void clearCommsSuccessCount() {
this.commsSuccessCount = 0;
} }
public void setActivePumpMac(long activePumpMac) { public int getCommsConnectThreshold() {
this.activePumpMac = activePumpMac; return commsConnectThreshold;
}
public int incCommsConnectThreshold() { return commsConnectThreshold++; }
public int decCommsConnectThreshold() {
if (commsConnectThreshold > 0) commsConnectThreshold--;
return commsConnectThreshold;}
public void clearCommsConnectThreshold() {
this.commsConnectThreshold = 0;
}
public int getCommsSignalThreshold() {
return commsSignalThreshold;
}
public int incCommsSignalThreshold() { return commsSignalThreshold++; }
public int decCommsSignalThreshold() {
if (commsSignalThreshold > 0) commsSignalThreshold--;
return commsSignalThreshold;}
public void clearCommsSignalThreshold() {
this.commsSignalThreshold = 0;
}
public float getCommsUnavailableThreshold() {
return commsUnavailableThreshold;
}
public float addCommsUnavailableThreshold(float value) {
commsUnavailableThreshold+= value;
if (commsUnavailableThreshold < 0) commsUnavailableThreshold = 0;
return commsUnavailableThreshold;}
public void clearCommsUnavailableThreshold() {
this.commsUnavailableThreshold = 0;
}
public void clearAllCommsErrors() {
this.commsErrorCount = 0;
this.commsSuccessCount = 0;
this.commsConnectThreshold = 0;
this.commsSignalThreshold = 0;
this.commsUnavailableThreshold = 0;
} }
} }
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <com.mikepenz.iconics.view.IconicsTextView
android:id="@+id/textview_log" android:id="@+id/textview_log"
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment