[0.4.1-SNAPSHOT]

- little change in scanning
- added error checking into RadioResponse and BasalProfile, also added events
- disabled quick scan
- synchronized RileyLink state changes
- proofed MedtronicConverter
- fixed 10 errors found on fabric
- fixed SetBasalProfile, after merge
This commit is contained in:
Andy Rozman 2018-10-27 14:04:46 +01:00
parent 03e38158f4
commit 5b9bd2adfc
24 changed files with 506 additions and 113 deletions

View file

@ -64,7 +64,7 @@ android {
multiDexEnabled true
versionCode 1500
// dev_version: 2.0i
version "medtronic-0.4.0-snapshot"
version "medtronic-0.4"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "HEAD", '"' + generateGitBuild() + '"'
@ -103,7 +103,7 @@ android {
resValue "string", "app_name", "AndroidAPS"
versionName version
manifestPlaceholders = [
appIcon: "@mipmap/ic_launcher",
appIcon : "@mipmap/ic_launcher",
appIconRound: "@mipmap/ic_launcher_round"
]
}
@ -113,7 +113,7 @@ android {
resValue "string", "app_name", "AndroidAPS"
versionName version
manifestPlaceholders = [
appIcon: "@mipmap/blueowl",
appIcon : "@mipmap/blueowl",
appIconRound: "@null"
]
}
@ -123,7 +123,7 @@ android {
resValue "string", "app_name", "NSClient"
versionName version + "-nsclient"
manifestPlaceholders = [
appIcon: "@mipmap/yellowowl",
appIcon : "@mipmap/yellowowl",
appIconRound: "@null"
]
}
@ -133,7 +133,7 @@ android {
resValue "string", "app_name", "NSClient2"
versionName version + "-nsclient"
manifestPlaceholders = [
appIcon: "@mipmap/yellowowl",
appIcon : "@mipmap/yellowowl",
appIconRound: "@null"
]
}
@ -148,7 +148,7 @@ android {
unitTests.includeAndroidResources = true
}
useLibrary "org.apache.http.legacy"
useLibrary "org.apache.http.legacy"
}
allprojects {

View file

@ -66,7 +66,9 @@
</intent-filter>
</activity>
<activity android:name=".plugins.PumpDanaRS.activities.PairingHelperActivity" />
<activity android:name=".HistoryBrowseActivity" />
<activity android:name=".activities.HistoryBrowseActivity" />
<activity android:name=".plugins.PumpCommon.dialog.RileyLinkBLEScanActivity">
<intent-filter>
<action android:name="info.nightscout.androidaps.plugins.PumpCommon.dialog.RileyLinkBLEScanActivity" />
@ -201,7 +203,8 @@
android:theme="@style/AppTheme.NoActionBar"
android:label="@string/title_activity_setup_wizard" />
<activity android:name=".activities.SingleFragmentActivity"
<activity
android:name=".activities.SingleFragmentActivity"
android:theme="@style/AppTheme" />
<activity android:name=".plugins.Maintenance.activities.LogSettingActivity"></activity>

View file

@ -469,6 +469,11 @@ public class MainApp extends Application {
}
public static boolean isEngineeringMode() {
return engineeringMode;
}
public static boolean isDev() {
return devBranch;
}

View file

@ -222,9 +222,11 @@ public abstract class RileyLinkCommunicationManager {
trial.successes++;
} else {
LOG.warn("Failed to parse radio response: " + ByteUtil.shortHexString(resp.getRaw()));
trial.rssiList.add(-99);
}
} else {
LOG.error("scanForPump: raw response is " + ByteUtil.shortHexString(resp.getRaw()));
trial.rssiList.add(-99);
}
trial.tries++;
}

View file

@ -83,11 +83,6 @@ public class RileyLinkUtil {
}
public static RileyLinkServiceState getServiceState() {
return RileyLinkUtil.rileyLinkServiceData.serviceState;
}
public static void setServiceState(RileyLinkServiceState newState) {
setServiceState(newState, null);
}
@ -98,16 +93,38 @@ public class RileyLinkUtil {
}
public static RileyLinkServiceState getServiceState() {
return workWithServiceState(null, null, false);
}
public static void setServiceState(RileyLinkServiceState newState, RileyLinkError errorCode) {
RileyLinkUtil.rileyLinkServiceData.serviceState = newState;
RileyLinkUtil.rileyLinkServiceData.errorCode = errorCode;
workWithServiceState(newState, errorCode, true);
}
LOG.warn("RileyLink State Changed: {} {}", newState,
errorCode == null ? "" : " - Error State: " + errorCode.name());
RileyLinkUtil.historyRileyLink.add(new RLHistoryItem(RileyLinkUtil.rileyLinkServiceData.serviceState,
RileyLinkUtil.rileyLinkServiceData.errorCode, targetDevice));
MainApp.bus().post(new EventMedtronicDeviceStatusChange(newState, errorCode));
private static synchronized RileyLinkServiceState workWithServiceState(RileyLinkServiceState newState,
RileyLinkError errorCode, boolean set) {
if (set) {
RileyLinkUtil.rileyLinkServiceData.serviceState = newState;
RileyLinkUtil.rileyLinkServiceData.errorCode = errorCode;
LOG.warn("RileyLink State Changed: {} {}", newState, errorCode == null ? "" : " - Error State: "
+ errorCode.name());
RileyLinkUtil.historyRileyLink.add(new RLHistoryItem(RileyLinkUtil.rileyLinkServiceData.serviceState,
RileyLinkUtil.rileyLinkServiceData.errorCode, targetDevice));
MainApp.bus().post(new EventMedtronicDeviceStatusChange(newState, errorCode));
return null;
} else {
return RileyLinkUtil.rileyLinkServiceData.serviceState;
}
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -160,6 +161,63 @@ public class RFTools {
}
public static byte[] encode4b6b_newtest(byte[] data) {
List<Byte> buffer = new ArrayList<Byte>();
int bitAccumulator = 0x0;
int bitcount = 0;
for (byte element : data) {
bitAccumulator <<= 6;
bitAccumulator |= codes[element >> 4];
bitcount += 6;
bitAccumulator <<= 6;
bitAccumulator |= codes[element & 0x0f];
bitcount += 6;
while (bitcount >= 8) {
buffer.add((byte)((bitAccumulator >> (bitcount - 8)) & 0xff));
bitcount -= 8;
bitAccumulator &= (0xffff >> (16 - bitcount));
}
}
if (bitcount > 0) {
bitAccumulator <<= (8 - bitcount);
buffer.add((byte)((bitAccumulator) & 0xff));
}
return ByteUtil.getByteArrayFromList(buffer);
}
// public func encode4b6b() -> [UInt8] {
// var buffer = [UInt8]()
// var bitAccumulator = 0x0
// var bitcount = 0
// for byte in self {
// bitAccumulator <<= 6
// bitAccumulator |= codes[Int(byte >> 4)]
// bitcount += 6
//
// bitAccumulator <<= 6
// bitAccumulator |= codes[Int(byte & 0x0f)]
// bitcount += 6
//
// while bitcount >= 8 {
// buffer.append(UInt8(bitAccumulator >> (bitcount-8)) & 0xff)
// bitcount -= 8
// bitAccumulator &= (0xffff >> (16-bitcount))
// }
// }
// if bitcount > 0 {
// bitAccumulator <<= (8-bitcount)
// buffer.append(UInt8(bitAccumulator) & 0xff)
// }
// return buffer
// }
public static void test() {
/*
* {0xa7} -> {0xa9, 0x60}
@ -272,6 +330,96 @@ public class RFTools {
}
public static DecodeResponseDto decode4b6bWithoutException(byte[] raw) {
/*
* if ((raw.length % 2) != 0) {
* LOG.error("Warning: data is odd number of bytes");
* }
*/
DecodeResponseDto response = new DecodeResponseDto();
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.append("Input data: " + ByteUtil.getHex(raw) + "\n");
if ((raw.length % 2) != 0) {
errorMessageBuilder.append("Warn: odd number of bytes.");
}
byte[] rval = new byte[] {};
int availableBits = 0;
int codingErrors = 0;
int x = 0;
// Log.w(TAG,"decode4b6b: untested code");
// Log.w(TAG,String.format("Decoding %d bytes: %s",raw.length,ByteUtil.shortHexString(raw)));
for (int i = 0; i < raw.length; i++) {
int unsignedValue = raw[i];
if (unsignedValue < 0) {
unsignedValue += 256;
}
x = (x << 8) + unsignedValue;
availableBits += 8;
if (availableBits >= 12) {
// take top six
int highcode = (x >> (availableBits - 6)) & 0x3F;
int highIndex = codeIndex((byte)(highcode));
// take bottom six
int lowcode = (x >> (availableBits - 12)) & 0x3F;
int lowIndex = codeIndex((byte)(lowcode));
// special case at end of transmission on uneven boundaries:
if ((highIndex >= 0) && (lowIndex >= 0)) {
byte decoded = (byte)((highIndex << 4) + lowIndex);
rval = ByteUtil.concat(rval, decoded);
/*
* LOG.debug(String.format(
* "i=%d,x=0x%08X,0x%02X->0x%02X, 0x%02X->0x%02X, result: 0x%02X, %d bits remaining, errors %d, bytes remaining: %s"
* ,
* i,x,highcode,highIndex, lowcode,
* lowIndex,decoded,availableBits,codingErrors,ByteUtil.shortHexString
* (ByteUtil.substring(raw,i+1,raw.length-i-1))));
*/
} else {
// LOG.debug(String.format("i=%d,x=%08X, coding error: highcode=0x%02X, lowcode=0x%02X, %d bits remaining",i,x,highcode,lowcode,availableBits));
errorMessageBuilder.append(String.format(
"decode4b6b: i=%d,x=%08X, coding error: highcode=0x%02X, lowcode=0x%02X, %d bits remaining.\n",
i, x, highcode, lowcode, availableBits));
codingErrors++;
}
availableBits -= 12;
x = x & (0x0000ffff >> (16 - availableBits));
} else {
// LOG.debug(String.format("i=%d, skip: x=0x%08X, available bits %d",i,x,availableBits));
}
}
if (availableBits != 0) {
if ((availableBits == 4) && (x == 0x05)) {
// normal end
} else {
LOG.error("decode4b6b: failed clean decode -- extra bits available (not marker)(" + availableBits + ")");
errorMessageBuilder.append("decode4b6b: failed clean decode -- extra bits available (not marker)("
+ availableBits + ")\n");
codingErrors++;
}
} else {
// also normal end.
}
if (codingErrors > 0) {
LOG.error("decode4b6b: " + codingErrors + " coding errors encountered.");
errorMessageBuilder.append("decode4b6b: " + codingErrors + " coding errors encountered.");
response.errorData = errorMessageBuilder.toString();
} else {
response.data = rval;
}
return response;
}
public static String toHexString(byte[] array) {
return toHexString(array, 0, array.length);
}
@ -290,4 +438,10 @@ public class RFTools {
return new String(buf);
}
public static class DecodeResponseDto {
public byte[] data;
public String errorData;
}
}

View file

@ -16,7 +16,15 @@ public class FrequencyScanResults {
public void sort() {
Collections.sort(trials, (trial1, trial2) -> trial1.averageRSSI.compareTo(trial2.averageRSSI));
Collections.sort(trials, (trial1, trial2) -> {
int res = trial1.averageRSSI.compareTo(trial2.averageRSSI);
if (res == 0) {
return (int)(trial1.frequencyMHz - trial2.frequencyMHz);
} else
return res;
});
}
}

View file

@ -11,6 +11,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.Riley
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkFirmwareVersion;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC;
import info.nightscout.androidaps.plugins.PumpCommon.utils.FabricUtil;
/**
* Created by geoff on 5/30/16.
@ -100,13 +101,19 @@ public class RadioResponse {
decodedPayload = encodedPayload;
break;
case FourByteSixByte:
LOG.debug("encodedPayload: {}", ByteUtil.getHex(encodedPayload));
byte[] decodeThis = RFTools.decode4b6b(encodedPayload);
LOG.debug("decodedPayload: {}", ByteUtil.getHex(decodeThis));
RFTools.DecodeResponseDto decodeResponseDto = RFTools.decode4b6bWithoutException(encodedPayload);
byte[] decodeThis = decodeResponseDto.data;
decodedOK = true;
if (decodeThis == null || decodeThis.length == 0) {
LOG.error("Decoded payload length is zero.");
if (decodeThis == null || decodeThis.length == 0 || decodeResponseDto.errorData != null) {
LOG.error("=============================================================================");
LOG.error(" Decoded payload length is zero.");
LOG.error(" encodedPayload: {}", ByteUtil.getHex(encodedPayload));
LOG.error(" errors: {}", decodeResponseDto.errorData);
LOG.error("=============================================================================");
FabricUtil.createEvent("MedtronicDecode4b6bError", null);
decodedOK = false;
return;
}

View file

@ -1,11 +0,0 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs;
/**
* Created by andy on 5/19/18.
*/
public enum RileyLinkTargetDevice {
MedtronicPump, //
Omnipod, //
;
}

View file

@ -7,11 +7,9 @@ import org.slf4j.LoggerFactory;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst;
@ -19,19 +17,12 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkBLE;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkEncodingType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkFirmwareVersion;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceNotification;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceResult;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceTransport;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.DiscoverGattServicesTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.InitializePumpManagerTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpDeviceState;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.utils.SP;
@ -254,20 +245,22 @@ public abstract class RileyLinkService extends Service {
}
double newFrequency;
if ((lastGoodFrequency > 0.0d) && getRileyLinkCommunicationManager().isValidFrequency(lastGoodFrequency)) {
LOG.info("Checking for pump near last saved frequency of {}MHz", lastGoodFrequency);
// we have an old frequency, so let's start there.
newFrequency = getDeviceCommunicationManager().quickTuneForPump(lastGoodFrequency);
if (newFrequency == 0.0) {
// quick scan failed to find pump. Try full scan
LOG.warn("Failed to find pump near last saved frequency, doing full scan");
newFrequency = getDeviceCommunicationManager().tuneForDevice();
}
} else {
LOG.warn("No saved frequency for pump, doing full scan.");
// we don't have a saved frequency, so do the full scan.
newFrequency = getDeviceCommunicationManager().tuneForDevice();
}
// if ((lastGoodFrequency > 0.0d) && getRileyLinkCommunicationManager().isValidFrequency(lastGoodFrequency)) {
// LOG.info("Checking for pump near last saved frequency of {}MHz", lastGoodFrequency);
// // we have an old frequency, so let's start there.
// newFrequency = getDeviceCommunicationManager().quickTuneForPump(lastGoodFrequency);
// if (newFrequency == 0.0) {
// // quick scan failed to find pump. Try full scan
// LOG.warn("Failed to find pump near last saved frequency, doing full scan");
// newFrequency = getDeviceCommunicationManager().tuneForDevice();
// }
// } else {
// LOG.warn("No saved frequency for pump, doing full scan.");
// // we don't have a saved frequency, so do the full scan.
// newFrequency = getDeviceCommunicationManager().tuneForDevice();
// }
newFrequency = getDeviceCommunicationManager().tuneForDevice();
if ((newFrequency != 0.0) && (newFrequency != lastGoodFrequency)) {
LOG.info("Saving new pump frequency of {}MHz", newFrequency);
@ -277,13 +270,12 @@ public abstract class RileyLinkService extends Service {
rileyLinkServiceData.lastTuneUpTime = System.currentTimeMillis();
}
getRileyLinkCommunicationManager().clearNotConnectedCount();
if (newFrequency == 0.0d) {
// error tuning pump, pump not present ??
RileyLinkUtil
.setServiceState(RileyLinkServiceState.PumpConnectorError, RileyLinkError.TuneUpOfDeviceFailed);
} else {
getRileyLinkCommunicationManager().clearNotConnectedCount();
RileyLinkUtil.setServiceState(RileyLinkServiceState.PumpConnectorReady);
}
}

View file

@ -347,6 +347,9 @@ public class ByteUtil {
public static String getCompactString(byte[] data) {
if (data == null)
return "null";
String vval2 = ByteUtil.getHex(data);
vval2 = vval2.replace(" 0x", "");
vval2 = vval2.replace("0x", "");

View file

@ -0,0 +1,55 @@
package info.nightscout.androidaps.plugins.PumpCommon.utils;
/**
* Created by andy on 10/25/18.
*/
import org.joda.time.LocalDateTime;
/**
* This is simple version of ATechDate, limited only to one format (yyyymmddHHMIss)
*/
public class DateTimeUtil {
/**
* DateTime is packed as long: yyyymmddHHMMss
*
* @param atechDateTime
* @return
*/
public static LocalDateTime toLocalDateTime(long atechDateTime) {
int year = (int)(atechDateTime / 10000000000L);
atechDateTime -= year * 10000000000L;
int month = (int)(atechDateTime / 100000000L);
atechDateTime -= month * 100000000L;
int dayOfMonth = (int)(atechDateTime / 1000000L);
atechDateTime -= dayOfMonth * 1000000L;
int hourOfDay = (int)(atechDateTime / 10000L);
atechDateTime -= hourOfDay * 10000L;
int minute = (int)(atechDateTime / 100L);
atechDateTime -= minute * 100L;
int second = (int)atechDateTime;
return new LocalDateTime(year, month, dayOfMonth, minute, second);
}
public static long toATechDate(LocalDateTime ldt) {
long atechDateTime = 0L;
atechDateTime += ldt.getYear() * 10000000000L;
atechDateTime += ldt.getMonthOfYear() * 100000000L;
atechDateTime += ldt.getDayOfMonth() * 1000000L;
atechDateTime += ldt.getHourOfDay() * 10000L;
atechDateTime += ldt.getMinuteOfHour() * 100L;
atechDateTime += ldt.getSecondOfMinute();
return atechDateTime;
}
}

View file

@ -0,0 +1,51 @@
package info.nightscout.androidaps.plugins.PumpCommon.utils;
import java.util.Map;
import com.crashlytics.android.answers.AnswersEvent;
import com.crashlytics.android.answers.CustomEvent;
import com.google.common.base.Splitter;
import info.nightscout.androidaps.BuildConfig;
import info.nightscout.utils.FabricPrivacy;
/**
* Created by andy on 10/26/18.
*/
public class FabricUtil {
public static void createEvent(String eventName, Map<String, String> map) {
CustomEvent customEvent = new CustomEvent("MedtronicDecode4b6bError") //
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION) //
.putCustomAttribute("version", BuildConfig.VERSION);
int attributes = 2;
boolean interrupted = false;
if (map != null) {
for (Map.Entry<String, String> entry : map.entrySet()) {
int part = 1;
if (interrupted)
break;
for (final String token : Splitter.fixedLength(AnswersEvent.MAX_STRING_LENGTH).split(entry.getValue())) {
if (attributes == AnswersEvent.MAX_NUM_ATTRIBUTES) {
interrupted = true;
break;
}
customEvent.putCustomAttribute(entry.getKey() + "_" + part, token);
attributes++;
}
}
}
FabricPrivacy.getInstance().logCustom(customEvent);
}
}

View file

@ -5,8 +5,6 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -40,8 +38,10 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
import info.nightscout.androidaps.plugins.PumpCommon.utils.DateTimeUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.MedtronicCommunicationManager;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryResult;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui.MedtronicUIComm;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui.MedtronicUITask;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.MedtronicHistoryData;
@ -884,25 +884,52 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void readPumpHistoryLogic() {
Long lastPumpHistoryEntryTime = null;
LocalDateTime targetDate = null;
// TODO read History
// if (lastPumpHistoryEntry == null) {
// lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, null);
// }
if (lastPumpHistoryEntry == null) {
lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, null);
}
if (firstRun) {
DateTime dt = new DateTime();
dt.minus(Hours.hours(36));
Long lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, null);
if (lastPumpHistoryEntry == null && lastPumpHistoryEntryTime == null) {
LocalDateTime timeMinus36h = new LocalDateTime();
timeMinus36h = timeMinus36h.minusHours(36);
if (lastPumpHistoryEntryTime == null) {
targetDate = timeMinus36h;
} else {
LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime);
medtronicHistoryData.setLastHistoryRecordTime(DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime));
lastHistoryRecordTime = lastHistoryRecordTime.minusHours(12); // we get last 12 hours of history to
// determine pump state
// (we don't process that data), we process only
if (timeMinus36h.isAfter(lastHistoryRecordTime)) {
targetDate = timeMinus36h;
}
targetDate = (timeMinus36h.isAfter(lastHistoryRecordTime) ? timeMinus36h : lastHistoryRecordTime);
}
}
// FIXME read history
PumpHistoryResult historyResult = new PumpHistoryResult(null, null);
PumpHistoryEntry latestEntry = historyResult.getLatestEntry();
if (latestEntry == null) // no new history to read
return;
this.lastPumpHistoryEntry = latestEntry;
SP.putLong(MedtronicConst.Statistics.LastPumpHistoryEntry,
DateTimeUtil.toATechDate(latestEntry.getLocalDateTime()));
// determine if first run, if yes detrmine how much of update do we need
// first run:
// get last hiostory entry, if not there download 1.5 days of data

View file

@ -135,7 +135,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
rfSpyResponse.wasTimeout());
} else {
rememberLastGoodDeviceCommunicationTime();
// rememberLastGoodDeviceCommunicationTime();
// radioResponse.rssi;
Object dataResponse = medtronicConverter.convertResponse(MedtronicCommandType.PumpModel,
@ -774,9 +774,9 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel);
if (!MedtronicUtil.isModelSet()) {
MedtronicUtil.setMedtronicPumpModel((MedtronicDeviceType)responseObject);
}
// if (!MedtronicUtil.isModelSet()) {
// MedtronicUtil.setMedtronicPumpModel((MedtronicDeviceType)responseObject);
// }
return responseObject == null ? null : (MedtronicDeviceType)responseObject;
}

View file

@ -34,6 +34,12 @@ public class MedtronicConverter {
public Object convertResponse(MedtronicCommandType commandType, byte[] rawContent) {
if ((rawContent == null || rawContent.length < 1) && commandType != MedtronicCommandType.PumpModel) {
LOG.warn("Content is empty or too shor, no data to convert (type={},isNull={},length={})",
commandType.name(), rawContent == null, rawContent == null ? "-" : rawContent.length);
return null;
}
LOG.debug("Raw response before convert: " + HexDump.toHexStringDisplayable(rawContent));
this.pumpModel = MedtronicUtil.getMedtronicPumpModel();
@ -53,7 +59,7 @@ public class MedtronicConverter {
}
case GetBatteryStatus: {
return decodeBatteryStatus(rawContent);
return decodeBatteryStatus(rawContent); // 1
}
case GetBasalProfileSTD:
@ -63,7 +69,7 @@ public class MedtronicConverter {
}
case ReadTemporaryBasal: {
return new TempBasalPair(rawContent);
return new TempBasalPair(rawContent); // 5
}
case Settings_512: {
@ -75,7 +81,7 @@ public class MedtronicConverter {
}
case SetBolus: {
return rawContent;
return rawContent; // 1
}
default: {
@ -88,12 +94,20 @@ public class MedtronicConverter {
private MedtronicDeviceType decodeModel(byte[] rawContent) {
if ((rawContent == null || rawContent.length < 4)) {
LOG.warn("Error reading PumpModel, returning Unknown_Device");
return MedtronicDeviceType.Unknown_Device;
}
String rawModel = StringUtil.fromBytes(ByteUtil.substring(rawContent, 1, 3));
MedtronicDeviceType pumpModel = MedtronicDeviceType.getByDescription(rawModel);
LOG.debug("PumpModel: [raw={}, resolved={}]", rawModel, pumpModel.name());
if (pumpModel != MedtronicDeviceType.Unknown_Device) {
MedtronicUtil.setMedtronicPumpModel(pumpModel);
if (!MedtronicUtil.isModelSet()) {
MedtronicUtil.setMedtronicPumpModel(pumpModel);
}
}
return pumpModel;

View file

@ -13,7 +13,7 @@ import org.slf4j.LoggerFactory;
*/
/**
* History page contains data, sorted from oldest to newest
* History page contains data, sorted from newest to oldest (0=newest..n=oldest)
*/
public class PumpHistoryResult {
@ -107,6 +107,19 @@ public class PumpHistoryResult {
}
/**
* Return latest entry (entry with highest date time)
*
* @return
*/
public PumpHistoryEntry getLatestEntry() {
if (this.validEntries == null || this.validEntries.size() == 0)
return null;
else
return this.validEntries.get(0);
}
public boolean isSearchRequired() {
return searchType != SearchType.None;
}

View file

@ -119,25 +119,9 @@ public class MedtronicUITask {
case SetBasalProfileSTD:
case SetBasalProfileA: {
BasalProfile profile = (BasalProfile) parameters[0];
BasalProfile profile = (BasalProfile)parameters[0];
returnData = communicationManager.setBasalProfile(profile);
// Float amount = getAmount();
//
// if (amount != null) {
//
// BasalProfile profile = new BasalProfile();
//
// int basalStrokes1 = MedtronicUtil.getBasalStrokesInt(amount);
// int basalStrokes2 = MedtronicUtil.getBasalStrokesInt(amount * 2);
//
// for (int i = 0; i < 24; i++) {
// profile.addEntry(new BasalProfileEntry(i % 2 == 0 ? basalStrokes1 : basalStrokes2, i * 2));
// }
//
// returnData = communicationManager.setBasalProfile(profile);
// }
}
break;
@ -231,6 +215,7 @@ public class MedtronicUITask {
return (responseType == MedtronicUIResponseType.Data);
}
public Object getParameter(int index) {
return parameters[index];
}

View file

@ -3,6 +3,8 @@ package info.nightscout.androidaps.plugins.PumpMedtronic.data;
import java.util.ArrayList;
import java.util.List;
import org.joda.time.LocalDateTime;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry;
/**
@ -15,6 +17,7 @@ public class MedtronicHistoryData {
private boolean suspended = false;
private boolean relevantConfigurationChanged = false;
private boolean basalProfileChanged = true;
private LocalDateTime lastHistoryRecordTime;
public MedtronicHistoryData() {
@ -49,4 +52,15 @@ public class MedtronicHistoryData {
basalProfileChanged = true; // FIXME when this works this should reset to false
}
public void setLastHistoryRecordTime(LocalDateTime lastHistoryRecordTime) {
this.lastHistoryRecordTime = lastHistoryRecordTime;
}
public LocalDateTime getLastHistoryRecordTime() {
return lastHistoryRecordTime;
}
}

View file

@ -7,6 +7,9 @@ import org.joda.time.Instant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpType;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.FabricUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
/**
@ -109,6 +112,22 @@ public class BasalProfile {
}
public String basalProfileToString() {
StringBuffer sb = new StringBuffer("Basal Profile [");
List<BasalProfileEntry> entries = getEntries();
for (int i = 0; i < entries.size(); i++) {
BasalProfileEntry entry = entries.get(i);
String startString = entry.startTime.toString("HH:mm");
sb.append(String.format("%s=%.3f, ", startString, entry.rate));
}
sb.append("]");
return sb.toString();
}
// TODO: this function must be expanded to include changes in which profile is in use.
// and changes to the profiles themselves.
public BasalProfileEntry getEntryForTime(Instant when) {
@ -217,14 +236,27 @@ public class BasalProfile {
public Double[] getProfilesByHour() {
List<BasalProfileEntry> entries = getEntries();
List<BasalProfileEntry> entries = null;
if (entries.size() == 0) {
try {
entries = getEntries();
} catch (Exception ex) {
LOG.error("=============================================================================");
LOG.error(" Error generating entries. Ex.: " + ex, ex);
LOG.error(" rawBasalValues: " + ByteUtil.getHex(this.getRawData()));
LOG.error("=============================================================================");
FabricUtil.createEvent("MedtronicBasalProfileGetByHourError", null);
}
if (entries == null || entries.size() == 0) {
return null;
}
Double[] basalByHour = new Double[24];
PumpType pumpType = MedtronicUtil.getPumpStatus().pumpType;
for (int i = 0; i < entries.size(); i++) {
BasalProfileEntry current = entries.get(i);
@ -247,7 +279,10 @@ public class BasalProfile {
// System.out.println("Current time: " + currentTime + " Next Time: " + lastHour);
for (int j = currentTime; j < lastHour; j++) {
basalByHour[j] = current.rate;
if (pumpType == null)
basalByHour[j] = current.rate;
else
basalByHour[j] = pumpType.determineCorrectBasalSize(current.rate);
}
}
@ -270,6 +305,6 @@ public class BasalProfile {
public String toString() {
return getBasalProfileAsString();
return basalProfileToString();
}
}

View file

@ -156,8 +156,14 @@ public class RileyLinkMedtronicService extends RileyLinkService {
} else {
LOG.info("Using pump ID " + pumpID);
String oldId = rileyLinkServiceData.pumpID;
rileyLinkServiceData.setPumpID(pumpID, pumpIDBytes);
if (oldId != null && !oldId.equals(pumpID)) {
MedtronicUtil.setMedtronicPumpModel(null); // if we change pumpId, model probably changed too
}
return;
}

View file

@ -422,9 +422,9 @@ public class MedtronicUtil extends RileyLinkUtil {
public static void setMedtronicPumpModel(MedtronicDeviceType medtronicPumpModel) {
if (medtronicPumpModel != null && medtronicPumpModel != MedtronicDeviceType.Unknown_Device) {
MedtronicUtil.medtronicPumpModel = medtronicPumpModel;
}
// if (medtronicPumpModel != null && medtronicPumpModel != MedtronicDeviceType.Unknown_Device) {
MedtronicUtil.medtronicPumpModel = medtronicPumpModel;
// }
}

View file

@ -1,5 +1,7 @@
package info.nightscout.utils;
import java.util.Date;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
import com.crashlytics.android.answers.CustomEvent;
@ -10,14 +12,12 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.interfaces.PluginBase;
import java.util.Date;
/**
* Created by jamorham on 21/02/2018.
* <p>
* Some users do not wish to be tracked, Fabric Answers and Crashlytics do not provide an easy way
* to disable them and make calls from a potentially invalid singleton reference. This wrapper
* emulates the methods but ignores the request if the instance is null or invalid.
* Some users do not wish to be tracked, Fabric Answers and Crashlytics do not provide an easy way to disable them and
* make calls from a potentially invalid singleton reference. This wrapper emulates the methods but ignores the request
* if the instance is null or invalid.
*/
public class FabricPrivacy {
@ -33,12 +33,14 @@ public class FabricPrivacy {
return instance;
}
private static synchronized void initSelf() {
if (instance == null) {
instance = new FabricPrivacy();
}
}
// Crashlytics logException
public static void logException(Throwable throwable) {
try {
@ -49,6 +51,7 @@ public class FabricPrivacy {
}
}
// Crashlytics log
public static void log(String msg) {
try {
@ -59,6 +62,7 @@ public class FabricPrivacy {
}
}
// Crashlytics log
public static void log(int priority, String tag, String msg) {
try {
@ -69,10 +73,15 @@ public class FabricPrivacy {
}
}
public static boolean fabricEnabled() {
if (MainApp.isEngineeringMode())
return true;
return SP.getBoolean("enable_fabric", true);
}
// Answers logCustom
public void logCustom(CustomEvent event) {
try {
@ -87,8 +96,10 @@ public class FabricPrivacy {
}
}
public static void uploadDailyStats() {
if (!fabricEnabled()) return;
if (!fabricEnabled())
return;
long lastUploadDay = SP.getLong(MainApp.gs(R.string.key_plugin_stats_report_timestamp), 0L);
@ -106,11 +117,12 @@ public class FabricPrivacy {
}
}
private static void uploadPluginStats() {
CustomEvent pluginStats = new CustomEvent("PluginStats");
pluginStats.putCustomAttribute("version", BuildConfig.VERSION);
pluginStats.putCustomAttribute("HEAD", BuildConfig.HEAD);
pluginStats.putCustomAttribute("language", SP.getString(R.string.key_language,"default"));
pluginStats.putCustomAttribute("language", SP.getString(R.string.key_language, "default"));
for (PluginBase plugin : MainApp.getPluginsList()) {
if (plugin.isEnabled(plugin.getType()) && !plugin.pluginDescription.alwaysEnabled) {
// Fabric allows no more than 20 attributes attached to an event. By reporting disabled plugins as
@ -123,6 +135,7 @@ public class FabricPrivacy {
getInstance().logCustom(pluginStats);
}
private static void uploadAppUsageType() {
CustomEvent type = new CustomEvent("AppUsageType");
if (Config.NSCLIENT)

View file

@ -3,7 +3,7 @@ RileyLinkAAPS
Medtronic
- set basal profile (try to get to work - see new Loop code)
+ set basal profile (try to get to work - see new Loop code)
- read history