Medtronic 0.5

- added DailyTotalsDTO and started with work on parsing (522 done)
- split encoding into 3 classes, and added exception when encoding fails
- added code for retries, when in communication with pump
- added analysis of history data for several occassions (profile changed, configuration changed, etc)
- little refactoring all arround
This commit is contained in:
Andy Rozman 2018-12-09 14:44:48 +00:00
parent 3fdbc0400e
commit adc80d5cc7
38 changed files with 2315 additions and 646 deletions

View file

@ -7,18 +7,20 @@
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- daily rollover. Make sure the path matches the one in the file element or else <!-- daily rollover. Make sure the path matches the one in the file element or else
the rollover logs are placed in the working directory. --> the rollover logs are placed in the working directory. -->
<fileNamePattern>${EXT_FILES_DIR}/AndroidAPS._%d{yyyy-MM-dd}_%d{HH-mm-ss, aux}_.%i.zip <fileNamePattern>${EXT_FILES_DIR}/AndroidAPS._%d{yyyy-MM-dd}_%d{HH-mm}_.%i.zip
</fileNamePattern> </fileNamePattern>
<timeBasedFileNamingAndTriggeringPolicy <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
<maxFileSize>5MB</maxFileSize> <maxFileSize>500KB</maxFileSize>
</timeBasedFileNamingAndTriggeringPolicy> </timeBasedFileNamingAndTriggeringPolicy>
<!-- keep 30 days' worth of history --> <!-- keep 30 days' worth of history -->
<maxHistory>120</maxHistory> <maxHistory>240</maxHistory>
</rollingPolicy> </rollingPolicy>
<encoder> <encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %.-1level/%logger: [%class{0}.%M\(\):%line]: %msg%n</pattern> <pattern>%d{HH:mm:ss.SSS} [%thread] %.-1level/%logger: [%class{0}.%M\(\):%line]:
%msg%n
</pattern>
</encoder> </encoder>
</appender> </appender>

View file

@ -27,6 +27,7 @@ import info.nightscout.androidaps.interfaces.PluginBase;
import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PumpDescription; import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface; import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress; import info.nightscout.androidaps.plugins.Overview.events.EventOverviewBolusProgress;
import info.nightscout.androidaps.plugins.PumpCommon.data.PumpStatus; import info.nightscout.androidaps.plugins.PumpCommon.data.PumpStatus;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpDriverState; import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpDriverState;
@ -141,40 +142,40 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
public boolean isConnected() { public boolean isConnected() {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("isConnected [PumpPluginAbstract]."); LOG.warn("isConnected [PumpPluginAbstract].");
return PumpDriverState.isConnected(pumpState); return PumpDriverState.isConnected(pumpState);
} }
public boolean isConnecting() { public boolean isConnecting() {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("isConnecting [PumpPluginAbstract]."); LOG.warn("isConnecting [PumpPluginAbstract].");
return pumpState == PumpDriverState.Connecting; return pumpState == PumpDriverState.Connecting;
} }
public void connect(String reason) { public void connect(String reason) {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("connect (reason={}) [PumpPluginAbstract] - default (empty) implementation.", reason); LOG.warn("connect (reason={}) [PumpPluginAbstract] - default (empty) implementation.", reason);
} }
public void disconnect(String reason) { public void disconnect(String reason) {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation.", reason); LOG.warn("disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation.", reason);
} }
public void stopConnecting() { public void stopConnecting() {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("stopConnecting [PumpPluginAbstract] - default (empty) implementation."); LOG.warn("stopConnecting [PumpPluginAbstract] - default (empty) implementation.");
} }
@Override @Override
public boolean isHandshakeInProgress() { public boolean isHandshakeInProgress() {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation."); LOG.warn("isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation.");
return false; return false;
} }
@ -182,50 +183,57 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
@Override @Override
public void finishHandshaking() { public void finishHandshaking() {
if (displayConnectionMessages) if (displayConnectionMessages && isLoggingEnabled())
LOG.warn("finishHandshaking [PumpPluginAbstract] - default (empty) implementation."); LOG.warn("finishHandshaking [PumpPluginAbstract] - default (empty) implementation.");
} }
public void getPumpStatus() { public void getPumpStatus() {
LOG.warn("getPumpStatus [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("getPumpStatus [PumpPluginAbstract] - Not implemented.");
} }
// Upload to pump new basal profile // Upload to pump new basal profile
public PumpEnactResult setNewBasalProfile(Profile profile) { public PumpEnactResult setNewBasalProfile(Profile profile) {
LOG.warn("setNewBasalProfile [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("setNewBasalProfile [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
public boolean isThisProfileSet(Profile profile) { public boolean isThisProfileSet(Profile profile) {
LOG.warn("isThisProfileSet [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("isThisProfileSet [PumpPluginAbstract] - Not implemented.");
return true; return true;
} }
public long lastDataTime() { public long lastDataTime() {
LOG.warn("lastDataTime [PumpPluginAbstract]."); if (isLoggingEnabled())
LOG.warn("lastDataTime [PumpPluginAbstract].");
return pumpStatus.lastConnection; return pumpStatus.lastConnection;
} }
public double getBaseBasalRate() { public double getBaseBasalRate() {
LOG.warn("getBaseBasalRate [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("getBaseBasalRate [PumpPluginAbstract] - Not implemented.");
return 0.0d; return 0.0d;
} // base basal rate, not temp basal } // base basal rate, not temp basal
public void stopBolusDelivering() { public void stopBolusDelivering() {
LOG.warn("stopBolusDelivering [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("stopBolusDelivering [PumpPluginAbstract] - Not implemented.");
} }
@Override @Override
public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile, public PumpEnactResult setTempBasalAbsolute(Double absoluteRate, Integer durationInMinutes, Profile profile,
boolean enforceNew) { boolean enforceNew) {
LOG.warn("setTempBasalAbsolute [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("setTempBasalAbsolute [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
@ -233,13 +241,15 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
@Override @Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) { boolean enforceNew) {
LOG.warn("setTempBasalPercent [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("setTempBasalPercent [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
LOG.warn("setExtendedBolus [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("setExtendedBolus [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
@ -248,13 +258,15 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
// when the cancel request is requested by the user (forced), the pump should always do a real cancel // when the cancel request is requested by the user (forced), the pump should always do a real cancel
public PumpEnactResult cancelTempBasal(boolean enforceNew) { public PumpEnactResult cancelTempBasal(boolean enforceNew) {
LOG.warn("cancelTempBasal [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("cancelTempBasal [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
public PumpEnactResult cancelExtendedBolus() { public PumpEnactResult cancelExtendedBolus() {
LOG.warn("cancelExtendedBolus [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("cancelExtendedBolus [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
@ -266,7 +278,8 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
// } // }
public String deviceID() { public String deviceID() {
LOG.warn("deviceID [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("deviceID [PumpPluginAbstract] - Not implemented.");
return "FakeDevice"; return "FakeDevice";
} }
@ -281,14 +294,16 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
// Short info for SMS, Wear etc // Short info for SMS, Wear etc
public boolean isFakingTempsByExtendedBoluses() { public boolean isFakingTempsByExtendedBoluses() {
LOG.warn("isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented.");
return false; return false;
} }
@Override @Override
public PumpEnactResult loadTDDs() { public PumpEnactResult loadTDDs() {
LOG.warn("loadTDDs [PumpPluginAbstract] - Not implemented."); if (isLoggingEnabled())
LOG.warn("loadTDDs [PumpPluginAbstract] - Not implemented.");
return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver);
} }
@ -383,7 +398,8 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
try { try {
if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) { if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) {
// neither carbs nor bolus requested // neither carbs nor bolus requested
LOG.error("deliverTreatment: Invalid input"); if (isLoggingEnabled())
LOG.error("deliverTreatment: Invalid input");
return new PumpEnactResult().success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d) return new PumpEnactResult().success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d)
.comment(MainApp.gs(R.string.danar_invalidinput)); .comment(MainApp.gs(R.string.danar_invalidinput));
} else if (detailedBolusInfo.insulin > 0) { } else if (detailedBolusInfo.insulin > 0) {
@ -399,7 +415,8 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
bolusingEvent.percent = 100; bolusingEvent.percent = 100;
MainApp.bus().post(bolusingEvent); MainApp.bus().post(bolusingEvent);
LOG.debug("deliverTreatment: Carb only treatment."); if (isLoggingEnabled())
LOG.debug("deliverTreatment: Carb only treatment.");
return new PumpEnactResult().success(true).enacted(true).bolusDelivered(0d) return new PumpEnactResult().success(true).enacted(true).bolusDelivered(0d)
.carbsDelivered(detailedBolusInfo.carbs).comment(MainApp.gs(R.string.virtualpump_resultok)); .carbsDelivered(detailedBolusInfo.carbs).comment(MainApp.gs(R.string.virtualpump_resultok));
@ -411,6 +428,11 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
} }
public boolean isLoggingEnabled() {
return L.isEnabled(L.PUMP);
}
protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo); protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo);

View file

@ -7,6 +7,7 @@ import android.content.Context;
import info.nightscout.androidaps.plugins.PumpCommon.data.PumpStatus; import info.nightscout.androidaps.plugins.PumpCommon.data.PumpStatus;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.FrequencyScanResults; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.FrequencyScanResults;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.FrequencyTrial; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.FrequencyTrial;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RFSpyResponse; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RFSpyResponse;
@ -14,7 +15,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RLMes
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioPacket; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioPacket;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioResponse; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioResponse;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RLMessageType; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RLMessageType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkBLEError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkServiceData; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkServiceData;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor; 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.hw.rileylink.service.tasks.WakeAndTuneTask;
@ -42,9 +43,9 @@ public abstract class RileyLinkCommunicationManager {
protected long lastGoodReceiverCommunicationTime = 0; protected long lastGoodReceiverCommunicationTime = 0;
protected PumpStatus pumpStatus; protected PumpStatus pumpStatus;
protected RileyLinkServiceData rileyLinkServiceData; protected RileyLinkServiceData rileyLinkServiceData;
protected RileyLinkTargetFrequency targetFrequency; // protected RileyLinkTargetFrequency targetFrequency;
private long nextWakeUpRequired = 0L; private long nextWakeUpRequired = 0L;
private double[] scanFrequencies; // private double[] scanFrequencies;
// internal flag // internal flag
private boolean showPumpMessages = true; private boolean showPumpMessages = true;
@ -54,8 +55,8 @@ public abstract class RileyLinkCommunicationManager {
public RileyLinkCommunicationManager(Context context, RFSpy rfspy) { public RileyLinkCommunicationManager(Context context, RFSpy rfspy) {
this.context = context; this.context = context;
this.rfspy = rfspy; this.rfspy = rfspy;
this.targetFrequency = RileyLinkUtil.getRileyLinkTargetFrequency(); // this.targetFrequency = RileyLinkUtil.getRileyLinkTargetFrequency();
this.scanFrequencies = targetFrequency.getScanFrequencies(); // this.scanFrequencies = targetFrequency.getScanFrequencies();
this.rileyLinkServiceData = RileyLinkUtil.getRileyLinkServiceData(); this.rileyLinkServiceData = RileyLinkUtil.getRileyLinkServiceData();
RileyLinkUtil.setRileyLinkCommunicationManager(this); RileyLinkUtil.setRileyLinkCommunicationManager(this);
@ -66,17 +67,17 @@ public abstract class RileyLinkCommunicationManager {
protected abstract void configurePumpSpecificSettings(); protected abstract void configurePumpSpecificSettings();
public void refreshRileyLinkTargetFrequency() { // public void refreshRileyLinkTargetFrequency() {
if (this.targetFrequency != RileyLinkUtil.getRileyLinkTargetFrequency()) { // if (this.targetFrequency != RileyLinkUtil.getRileyLinkTargetFrequency()) {
this.targetFrequency = RileyLinkUtil.getRileyLinkTargetFrequency(); // this.targetFrequency = RileyLinkUtil.getRileyLinkTargetFrequency();
this.scanFrequencies = targetFrequency.getScanFrequencies(); // this.scanFrequencies = targetFrequency.getScanFrequencies();
} // }
//
} // }
// All pump communications go through this function. // All pump communications go through this function.
protected <E extends RLMessage> E sendAndListen(RLMessage msg, int timeout_ms, Class<E> clazz) { protected <E extends RLMessage> E sendAndListen(RLMessage msg, int timeout_ms, Class<E> clazz)
throws RileyLinkCommunicationException {
if (showPumpMessages) { if (showPumpMessages) {
LOG.info("Sent:" + ByteUtil.shortHexString(msg.getTxData())); LOG.info("Sent:" + ByteUtil.shortHexString(msg.getTxData()));
@ -84,6 +85,8 @@ public abstract class RileyLinkCommunicationManager {
RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(msg.getTxData()), timeout_ms); RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(msg.getTxData()), timeout_ms);
RadioResponse radioResponse = rfSpyResponse.getRadioResponse();
E response = createResponseMessage(rfSpyResponse.getRadioResponse().getPayload(), clazz); E response = createResponseMessage(rfSpyResponse.getRadioResponse().getPayload(), clazz);
if (response.isValid()) { if (response.isValid()) {
@ -103,6 +106,10 @@ public abstract class RileyLinkCommunicationManager {
ServiceTaskExecutor.startTask(new WakeAndTuneTask()); ServiceTaskExecutor.startTask(new WakeAndTuneTask());
timeoutCount = 0; timeoutCount = 0;
} }
throw new RileyLinkCommunicationException(RileyLinkBLEError.Timeout);
} else if (rfSpyResponse.wasInterrupted()) {
throw new RileyLinkCommunicationException(RileyLinkBLEError.Interrupted);
} }
} }
@ -127,18 +134,17 @@ public abstract class RileyLinkCommunicationManager {
} }
public boolean changeTargetFrequency(RileyLinkTargetFrequency targetFrequency) { // public boolean changeTargetFrequency(RileyLinkTargetFrequency targetFrequency) {
//
if (this.targetFrequency == targetFrequency) { // if (this.targetFrequency == targetFrequency) {
return false; // return false;
} // }
//
this.targetFrequency = targetFrequency; // this.targetFrequency = targetFrequency;
this.scanFrequencies = targetFrequency.getScanFrequencies(); // this.scanFrequencies = targetFrequency.getScanFrequencies();
//
return true; // return true;
} // }
// FIXME change wakeup // FIXME change wakeup
// TODO we might need to fix this. Maybe make pump awake for shorter time (battery factor for pump) - Andy // TODO we might need to fix this. Maybe make pump awake for shorter time (battery factor for pump) - Andy
@ -188,7 +194,7 @@ public abstract class RileyLinkCommunicationManager {
public double tuneForDevice() { public double tuneForDevice() {
return scanForDevice(scanFrequencies); return scanForDevice(RileyLinkUtil.getRileyLinkTargetFrequency().getScanFrequencies());
} }
@ -201,10 +207,13 @@ public abstract class RileyLinkCommunicationManager {
* @return * @return
*/ */
public boolean isValidFrequency(double frequency) { public boolean isValidFrequency(double frequency) {
double[] scanFrequencies = RileyLinkUtil.getRileyLinkTargetFrequency().getScanFrequencies();
if (scanFrequencies.length == 1) { if (scanFrequencies.length == 1) {
return RileyLinkUtil.isSame(scanFrequencies[0], frequency); return RileyLinkUtil.isSame(scanFrequencies[0], frequency);
} else { } else {
return (this.scanFrequencies[0] <= frequency && this.scanFrequencies[scanFrequencies.length - 1] >= frequency); return (scanFrequencies[0] <= frequency && scanFrequencies[scanFrequencies.length - 1] >= frequency);
} }
} }
@ -238,15 +247,26 @@ public abstract class RileyLinkCommunicationManager {
if (resp.wasTimeout()) { if (resp.wasTimeout()) {
LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]); LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]);
} else if (resp.looksLikeRadioPacket()) { } else if (resp.looksLikeRadioPacket()) {
RadioResponse radioResponse = new RadioResponse(resp.getRaw()); RadioResponse radioResponse = new RadioResponse();
if (radioResponse.isValid()) {
sumRSSI += radioResponse.rssi; try {
trial.rssiList.add(radioResponse.rssi);
trial.successes++; radioResponse.init(resp.getRaw());
} else {
LOG.warn("Failed to parse radio response: " + ByteUtil.shortHexString(resp.getRaw())); if (radioResponse.isValid()) {
sumRSSI += radioResponse.rssi;
trial.rssiList.add(radioResponse.rssi);
trial.successes++;
} else {
LOG.warn("Failed to parse radio response: " + ByteUtil.shortHexString(resp.getRaw()));
trial.rssiList.add(-99);
}
} catch (RileyLinkCommunicationException rle) {
LOG.warn("Failed to decode radio response: " + ByteUtil.shortHexString(resp.getRaw()));
trial.rssiList.add(-99); trial.rssiList.add(-99);
} }
} else { } else {
LOG.error("scanForPump: raw response is " + ByteUtil.shortHexString(resp.getRaw())); LOG.error("scanForPump: raw response is " + ByteUtil.shortHexString(resp.getRaw()));
trial.rssiList.add(-99); trial.rssiList.add(-99);
@ -302,15 +322,23 @@ public abstract class RileyLinkCommunicationManager {
if (resp.wasTimeout()) { if (resp.wasTimeout()) {
LOG.warn("tune_tryFrequency: no pump response at frequency {}", freqMHz); LOG.warn("tune_tryFrequency: no pump response at frequency {}", freqMHz);
} else if (resp.looksLikeRadioPacket()) { } else if (resp.looksLikeRadioPacket()) {
RadioResponse radioResponse = new RadioResponse(resp.getRaw()); RadioResponse radioResponse = new RadioResponse();
if (radioResponse.isValid()) { try {
LOG.warn("tune_tryFrequency: saw response level {} at frequency {}", radioResponse.rssi, freqMHz); radioResponse.init(resp.getRaw());
return radioResponse.rssi;
} else { if (radioResponse.isValid()) {
LOG.warn("tune_tryFrequency: invalid radio response:" LOG.warn("tune_tryFrequency: saw response level {} at frequency {}", radioResponse.rssi, freqMHz);
+ ByteUtil.shortHexString(radioResponse.getPayload())); return radioResponse.rssi;
} else {
LOG.warn("tune_tryFrequency: invalid radio response:"
+ ByteUtil.shortHexString(radioResponse.getPayload()));
}
} catch (RileyLinkCommunicationException e) {
LOG.warn("Failed to decode radio response: " + ByteUtil.shortHexString(resp.getRaw()));
} }
} }
return 0; return 0;
} }

View file

@ -12,7 +12,7 @@ public class RileyLinkConst {
public static final String RileyLinkReady = Prefix + "RileyLink_Ready"; public static final String RileyLinkReady = Prefix + "RileyLink_Ready";
public static final String RileyLinkGattFailed = Prefix + "RileyLink_Gatt_Failed"; public static final String RileyLinkGattFailed = Prefix + "RileyLink_Gatt_Failed";
// public static final String RileyLinkError = Prefix + "RileyLink_Ready"; // public static final String RileyLinkBLEError = Prefix + "RileyLink_Ready";
public static final String BluetoothConnected = Prefix + "Bluetooth_Connected"; public static final String BluetoothConnected = Prefix + "Bluetooth_Connected";
public static final String BluetoothReconnected = Prefix + "Bluetooth_Reconnected"; public static final String BluetoothReconnected = Prefix + "Bluetooth_Reconnected";

View file

@ -16,6 +16,8 @@ import android.support.v4.content.LocalBroadcastManager;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkBLE; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkBLE;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding.Encoding4b6b;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding.Encoding4b6bGeoff;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkEncodingType; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkEncodingType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.data.BleAdvertisedData; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.data.BleAdvertisedData;
@ -59,6 +61,7 @@ public class RileyLinkUtil {
private static RileyLinkTargetDevice targetDevice; private static RileyLinkTargetDevice targetDevice;
private static RileyLinkEncodingType encoding; private static RileyLinkEncodingType encoding;
private static RileyLinkSelectPreference rileyLinkSelectPreference; private static RileyLinkSelectPreference rileyLinkSelectPreference;
private static Encoding4b6b encoding4b6b;
public static void setContext(Context contextIn) { public static void setContext(Context contextIn) {
@ -74,6 +77,10 @@ public class RileyLinkUtil {
public static void setEncoding(RileyLinkEncodingType encoding) { public static void setEncoding(RileyLinkEncodingType encoding) {
RileyLinkUtil.encoding = encoding; RileyLinkUtil.encoding = encoding;
if (encoding == RileyLinkEncodingType.FourByteSixByte) {
RileyLinkUtil.encoding4b6b = new Encoding4b6bGeoff();
}
} }
@ -316,4 +323,8 @@ public class RileyLinkUtil {
return rileyLinkSelectPreference; return rileyLinkSelectPreference;
} }
public static Encoding4b6b getEncoding4b6b() {
return RileyLinkUtil.encoding4b6b;
}
} }

View file

@ -39,7 +39,8 @@ import info.nightscout.androidaps.plugins.PumpCommon.utils.ThreadUtil;
*/ */
public class RileyLinkBLE { public class RileyLinkBLE {
private static final Logger LOG = LoggerFactory.getLogger(RFTools.class); private static final Logger LOG = LoggerFactory.getLogger(RileyLinkBLE.class);
private final Context context; private final Context context;
public boolean gattDebugEnabled = true; public boolean gattDebugEnabled = true;
boolean manualDisconnect = false; boolean manualDisconnect = false;

View file

@ -0,0 +1,30 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkBLEError;
/**
* Created by andy on 11/23/18.
*/
public class RileyLinkCommunicationException extends Throwable {
String extendedErrorText;
private RileyLinkBLEError errorCode;
public RileyLinkCommunicationException(RileyLinkBLEError errorCode, String extendedErrorText) {
super(errorCode.getDescription());
this.errorCode = errorCode;
this.extendedErrorText = extendedErrorText;
}
public RileyLinkCommunicationException(RileyLinkBLEError errorCode) {
super(errorCode.getDescription());
this.errorCode = errorCode;
// this.extendedErrorText = extendedErrorText;
}
}

View file

@ -87,7 +87,7 @@ public class SendAndListen extends RileyLinkCommand {
bytes.add(preambleBuf[3]); bytes.add(preambleBuf[3]);
} }
return ByteUtil.concat(ByteUtil.fromByteArray(bytes), packetToSend.getEncoded()); return ByteUtil.concat(ByteUtil.getByteArrayFromList(bytes), packetToSend.getEncoded());
} }
} }

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data; package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.command.RileyLinkCommand; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.command.RileyLinkCommand;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RFSpyRLResponse; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RFSpyRLResponse;
@ -47,9 +48,10 @@ public class RFSpyResponse {
} }
public RadioResponse getRadioResponse() { public RadioResponse getRadioResponse() throws RileyLinkCommunicationException {
if (looksLikeRadioPacket()) { if (looksLikeRadioPacket()) {
radioResponse = new RadioResponse(command, raw); radioResponse = new RadioResponse(command);
radioResponse.init(raw);
} else { } else {
radioResponse = new RadioResponse(); radioResponse = new RadioResponse();
} }

View file

@ -3,7 +3,6 @@ package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data;
import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.NotImplementedException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFTools;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC; import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC;
@ -42,7 +41,7 @@ public class RadioPacket {
case FourByteSixByte: { case FourByteSixByte: {
byte[] withCRC = getWithCRC(); byte[] withCRC = getWithCRC();
byte[] encoded = RFTools.encode4b6b(withCRC); byte[] encoded = RileyLinkUtil.getEncoding4b6b().encode4b6b(withCRC);
return ByteUtil.concat(encoded, (byte)0); return ByteUtil.concat(encoded, (byte)0);
} }

View file

@ -5,13 +5,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFTools; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.command.RileyLinkCommand; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.command.RileyLinkCommand;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkCommandType; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkCommandType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkFirmwareVersion; 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.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC; import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC;
import info.nightscout.androidaps.plugins.PumpCommon.utils.FabricUtil;
/** /**
* Created by geoff on 5/30/16. * Created by geoff on 5/30/16.
@ -33,14 +32,13 @@ public class RadioResponse {
} }
public RadioResponse(byte[] rxData) { // public RadioResponse(byte[] rxData) {
init(rxData); // init(rxData);
} // }
public RadioResponse(RileyLinkCommand command /* , byte[] raw */) {
public RadioResponse(RileyLinkCommand command, byte[] raw) {
this.command = command; this.command = command;
init(raw); // init(raw);
} }
@ -63,7 +61,7 @@ public class RadioResponse {
} }
public void init(byte[] rxData) { public void init(byte[] rxData) throws RileyLinkCommunicationException {
if (rxData == null) { if (rxData == null) {
return; return;
@ -101,23 +99,9 @@ public class RadioResponse {
decodedPayload = encodedPayload; decodedPayload = encodedPayload;
break; break;
case FourByteSixByte: case FourByteSixByte:
RFTools.DecodeResponseDto decodeResponseDto = RFTools.decode4b6bWithoutException(encodedPayload); byte[] decodeThis = RileyLinkUtil.getEncoding4b6b().decode4b6b(encodedPayload);
byte[] decodeThis = decodeResponseDto.data;
decodedOK = true; decodedOK = true;
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;
}
decodedPayload = ByteUtil.substring(decodeThis, 0, decodeThis.length - 1); decodedPayload = ByteUtil.substring(decodeThis, 0, decodeThis.length - 1);
receivedCRC = decodeThis[decodeThis.length - 1]; receivedCRC = decodeThis[decodeThis.length - 1];
byte calculatedCRC = CRC.crc8(decodedPayload); byte calculatedCRC = CRC.crc8(decodedPayload);

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
/**
* Created by andy on 11/24/18.
*/
public interface Encoding4b6b {
byte[] encode4b6b(byte[] data);
byte[] decode4b6b(byte[] data) throws RileyLinkCommunicationException;
}

View file

@ -0,0 +1,68 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding;
import org.slf4j.Logger;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.FabricUtil;
/**
* Created by andy on 11/24/18.
*/
public abstract class Encoding4b6bAbstract implements Encoding4b6b {
/**
* encode4b6bMap is an ordered list of translations 6bits -> 4 bits, in order from 0x0 to 0xF
* The 6 bit codes are what is used on the RF side of the RileyLink to communicate
* with a Medtronic pump.
*/
public static final byte[] encode4b6bList = new byte[] {
0x15, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x16, 0x1a, 0x19, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x1c };
// 21, 49, 50, 35, 52, 37, 38, 22, 26, 25, 42, 11, 44, 13, 14, 28
public abstract byte[] encode4b6b(byte[] data);
public abstract byte[] decode4b6b(byte[] data) throws RileyLinkCommunicationException;
protected short convertUnsigned(byte x) {
short ss = x;
if (ss < 0) {
ss += 256;
}
return ss;
}
/* O(n) lookup. Run on an O(n) translation of a byte-stream, gives O(n**2) performance. Sigh. */
public static int encode4b6bListIndex(byte b) {
for (int i = 0; i < encode4b6bList.length; i++) {
if (b == encode4b6bList[i]) {
return i;
}
}
return -1;
}
public void writeError(Logger LOG, byte[] raw, String errorData) {
LOG.error("=============================================================================");
LOG.error(" Decoded payload length is zero.");
LOG.error(" encodedPayload: {}", ByteUtil.getHex(raw));
LOG.error(" errors: {}", errorData);
LOG.error("=============================================================================");
FabricUtil.createEvent("MedtronicDecode4b6bError", null);
return;
}
}

View file

@ -0,0 +1,249 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding;
import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkBLEError;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
/**
* Created by andy on 11/24/18.
*/
public class Encoding4b6bGeoff extends Encoding4b6bAbstract {
public static final Logger LOG = LoggerFactory.getLogger(Encoding4b6bGeoff.class);
public byte[] encode4b6b(byte[] data) {
// if ((data.length % 2) != 0) {
// LOG.error("Warning: data is odd number of bytes");
// }
// use arraylists because byte[] is annoying.
List<Byte> inData = ByteUtil.getListFromByteArray(data);
List<Byte> outData = new ArrayList<>();
int acc = 0;
int bitcount = 0;
int i;
for (i = 0; i < inData.size(); i++) {
acc <<= 6;
acc |= encode4b6bList[(inData.get(i) >> 4) & 0x0f];
bitcount += 6;
acc <<= 6;
acc |= encode4b6bList[inData.get(i) & 0x0f];
bitcount += 6;
while (bitcount >= 8) {
byte outByte = (byte)(acc >> (bitcount - 8) & 0xff);
outData.add(outByte);
bitcount -= 8;
acc &= (0xffff >> (16 - bitcount));
}
}
if (bitcount > 0) {
acc <<= 6;
acc |= 0x14; // marks uneven packet boundary.
bitcount += 6;
if (bitcount >= 8) {
byte outByte = (byte)((acc >> (bitcount - 8)) & 0xff);
outData.add(outByte);
bitcount -= 8;
// acc &= (0xffff >> (16 - bitcount));
}
while (bitcount >= 8) {
outData.add((byte)0);
bitcount -= 8;
}
}
// convert back to byte[]
byte[] rval = ByteUtil.getByteArrayFromList(outData);
return rval;
}
/**
* Decode by Geoff
*
* @param raw
* @return
* @throws NumberFormatException
*/
public byte[] decode4b6b(byte[] raw) throws RileyLinkCommunicationException {
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.append("Input data: " + ByteUtil.getHex(raw) + "\n");
if ((raw.length % 2) != 0) {
errorMessageBuilder.append("Warn: odd number of bytes.\n");
}
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 = encode4b6bListIndex((byte)(highcode));
// take bottom six
int lowcode = (x >> (availableBits - 12)) & 0x3F;
int lowIndex = encode4b6bListIndex((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));
}
}
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.");
writeError(LOG, raw, errorMessageBuilder.toString());
throw new RileyLinkCommunicationException(RileyLinkBLEError.CodingErrors, errorMessageBuilder.toString());
}
return rval;
}
// public static RFTools.DecodeResponseDto decode4b6bWithoutException(byte[] raw) {
// /*
// * if ((raw.length % 2) != 0) {
// * LOG.error("Warning: data is odd number of bytes");
// * }
// */
//
// RFTools.DecodeResponseDto response = new RFTools.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 = encode4b6bListIndex((byte)(highcode));
// // take bottom six
// int lowcode = (x >> (availableBits - 12)) & 0x3F;
// int lowIndex = encode4b6bListIndex((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;
// }
}

View file

@ -0,0 +1,163 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkBLEError;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
/**
* Created by andy on 11/24/18.
*/
public class Encoding4b6bGo extends Encoding4b6bAbstract {
public static final Logger LOG = LoggerFactory.getLogger(Encoding4b6bGo.class);
private static Map<Short, Short> decodeGoMap;
public byte[] encode4b6b(byte[] src) {
// 2 input bytes produce 3 output bytes.
// Odd final input byte, if any, produces 2 output bytes.
int n = src.length;
byte[] dst = new byte[3 * (n / 2) + 2 * (n % 2)];
int j = 0;
for (int i = 0; i < n; i += 2, j = j + 3) {
short x = convertUnsigned(src[i]);
short a = encode4b6bList[hi(4, x)];
short b = encode4b6bList[lo(4, x)];
dst[j] = (byte)(a << 2 | hi(4, b));
if (i + 1 < n) {
short y = convertUnsigned(src[i + 1]);
short c = encode4b6bList[hi(4, y)];
short d = encode4b6bList[lo(4, y)];
dst[j + 1] = (byte)(lo(4, b) << 4 | hi(6, c));
dst[j + 2] = (byte)(lo(2, c) << 6 | d);
} else {
// Fill final nibble with 5 to match pump behavior.
dst[j + 1] = (byte)(lo(4, b) << 4 | 0x5);
}
}
return dst;
}
/**
* Decode from Go code by ecc1. NOT WORKING
*
* @param src
* @return
*/
public byte[] decode4b6b(byte[] src) throws RileyLinkCommunicationException {
int n = src.length;
if (decodeGoMap == null)
initDecodeGo();
StringBuilder errorMessageBuilder = new StringBuilder();
errorMessageBuilder.append("Input data: " + ByteUtil.getHex(src) + "\n");
int codingErrors = 0;
// Check for valid packet length.
if (n % 3 == 1) {
errorMessageBuilder.append("Invalid package length " + n);
codingErrors++;
// return nil, ErrDecoding
}
// 3 input bytes produce 2 output bytes.
// Final 2 input bytes, if any, produce 1 output byte.
byte[] dst = new byte[2 * (n / 3) + (n % 3) / 2];
int j = 0;
for (int i = 0; i < n; i = i + 3, j = j + 2) {
if (i + 1 >= n) {
errorMessageBuilder.append("Overflow in i (" + i + ")");
}
short x = convertUnsigned(src[i]);
short y = convertUnsigned(src[i + 1]);
short a = decode6b_goMap(hi(6, x));
short b = decode6b_goMap(lo(2, x) << 4 | hi(4, y));
if (a == 0xFF || b == 0xFF) {
errorMessageBuilder.append("Error decoding ");
codingErrors++;
}
dst[j] = (byte)(a << 4 | b);
if (i + 2 < n) {
short z = convertUnsigned(src[i + 2]);
short c = decode6b_goMap(lo(4, y) << 2 | hi(2, z));
short d = decode6b_goMap(lo(6, z));
if (c == 0xFF || d == 0xFF) {
errorMessageBuilder.append("Error decoding ");
codingErrors++;
}
dst[j + 1] = (byte)(c << 4 | d);
}
}
if (codingErrors > 0) {
errorMessageBuilder.append("decode4b6b: " + codingErrors + " coding errors encountered.");
writeError(LOG, dst, errorMessageBuilder.toString());
throw new RileyLinkCommunicationException(RileyLinkBLEError.CodingErrors, errorMessageBuilder.toString());
}
return dst;
}
static short hi(int n, short x) {
// x = convertUnsigned(x);
return (short)(x >> (8 - n));
}
static short lo(int n, short x) {
// byte b = (byte)x;
return (short)(x & ((1 << n) - 1));
}
public static void initDecodeGo() {
decodeGoMap = new HashMap<>();
putToMap(0x0B, 0x0B);
putToMap(0x0D, 0x0D);
putToMap(0x0E, 0x0E);
putToMap(0x15, 0x00);
putToMap(0x16, 0x07);
putToMap(0x19, 0x09);
putToMap(0x1A, 0x08);
putToMap(0x1C, 0x0F);
putToMap(0x23, 0x03);
putToMap(0x25, 0x05);
putToMap(0x26, 0x06);
putToMap(0x2A, 0x0A);
putToMap(0x2C, 0x0C);
putToMap(0x31, 0x01);
putToMap(0x32, 0x02);
putToMap(0x34, 0x04);
}
private static short decode6b_goMap(int value) {
short val = (short)value;
if (decodeGoMap.containsKey(val))
return decodeGoMap.get(val);
else
return (short)0xff;
}
private static void putToMap(int val1, int val2) {
decodeGoMap.put((short)val1, (short)val2);
}
}

View file

@ -0,0 +1,136 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.encoding;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
/**
* Created by andy on 11/24/18.
*/
public class Encoding4b6bLoop extends Encoding4b6bAbstract {
public static final Logger LOG = LoggerFactory.getLogger(Encoding4b6bLoop.class);
public Map<Integer, Byte> codesRev = null;
public Encoding4b6bLoop() {
createCodeRev();
}
/**
* This method is almost 1:1 with same method from Loop, only change is unsigning of element and |05 added for
* last byte. It should work better than original one, which is really different than this one.
*
* @param data
* @return
*/
public byte[] encode4b6b(byte[] data) {
List<Byte> buffer = new ArrayList<Byte>();
int bitAccumulator = 0x0;
int bitcount = 0;
for (byte element : data) {
short element2 = element;
if (element2 < 0) {
element2 += 256;
}
bitAccumulator <<= 6;
bitAccumulator |= encode4b6bList[element2 >> 4];
bitcount += 6;
bitAccumulator <<= 6;
bitAccumulator |= encode4b6bList[element2 & 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 | 0x5) & 0xff));
}
return ByteUtil.getByteArrayFromList(buffer);
}
/**
* DOESN'T WORK YET
*
* @param data
* @return
* @throws RileyLinkCommunicationException
*/
public byte[] decode4b6b(byte[] data) throws RileyLinkCommunicationException {
List<Byte> buffer = new ArrayList<Byte>();
int availBits = 0;
int bitAccumulator = 0;
for (byte element2 : data) {
short element = convertUnsigned(element2);
// if (element < 0) {
// element += 255;
// }
if (element == 0) {
break;
}
bitAccumulator = (bitAccumulator << 8) + element;
availBits += 8;
if (availBits >= 12) {
int hiNibble;
int loNibble;
try {
int index = (bitAccumulator >> (availBits - 6));
int index2 = ((bitAccumulator >> (availBits - 12)) & 0b111111);
hiNibble = codesRev.get((bitAccumulator >> (availBits - 6)));
loNibble = codesRev.get(((bitAccumulator >> (availBits - 12)) & 0b111111));
} catch (Exception ex) {
System.out.println("Exception: " + ex.getMessage());
ex.printStackTrace();
return null;
}
int decoded = ((hiNibble << 4) + loNibble);
buffer.add((byte)decoded);
availBits -= 12;
bitAccumulator = bitAccumulator & (0xffff >> (16 - availBits));
}
}
return ByteUtil.getByteArrayFromList(buffer);
}
private void createCodeRev() {
codesRev = new HashMap<>();
for (int i = 0; i < encode4b6bList.length; i++) {
codesRev.put(i, encode4b6bList[i]);
}
}
}

View file

@ -0,0 +1,24 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs;
/**
* Created by andy on 11/24/18.
*/
public enum RileyLinkBLEError {
CodingErrors("Coding Errors encpountered during decode of RileyLink packet."), //
Timeout("Timeout"), //
Interrupted("Interrupted");
private String description;
RileyLinkBLEError(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}

View file

@ -81,7 +81,7 @@ public enum RileyLinkServiceState {
this == RileyLinkServiceState.BluetoothReady || // this == RileyLinkServiceState.BluetoothReady || //
this == RileyLinkServiceState.RileyLinkInitializing || // this == RileyLinkServiceState.RileyLinkInitializing || //
this == RileyLinkReady this == RileyLinkReady
// this == RileyLinkServiceState.RileyLinkError // this == RileyLinkServiceState.RileyLinkBLEError
); );
} }

View file

@ -147,7 +147,7 @@ public class RileyLinkBroadcastReceiver extends BroadcastReceiver {
if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) { if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) {
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) { if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
RileyLinkUtil RileyLinkUtil
.setServiceState(RileyLinkServiceState.BluetoothReady, RileyLinkError.RileyLinkUnreachable); .setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.RileyLinkUnreachable);
} else { } else {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled); RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled);
} }
@ -173,15 +173,6 @@ public class RileyLinkBroadcastReceiver extends BroadcastReceiver {
ServiceTaskExecutor.startTask(task); ServiceTaskExecutor.startTask(task);
LOG.info("Announcing RileyLink open For business"); LOG.info("Announcing RileyLink open For business");
return true;
} else if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) {
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
RileyLinkUtil
.setServiceState(RileyLinkServiceState.BluetoothReady, RileyLinkError.RileyLinkUnreachable);
} else {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled);
}
return true; return true;
} else if (action.equals(RileyLinkConst.Intents.RileyLinkNewAddressSet)) { } else if (action.equals(RileyLinkConst.Intents.RileyLinkNewAddressSet)) {
String RileylinkBLEAddress = SP.getString(RileyLinkConst.Prefs.RileyLinkAddress, ""); String RileylinkBLEAddress = SP.getString(RileyLinkConst.Prefs.RileyLinkAddress, "");

View file

@ -8,6 +8,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLink
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState; 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.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceTransport; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceTransport;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
/** /**
@ -40,6 +41,11 @@ public class InitializePumpManagerTask extends ServiceTask {
RileyLinkUtil.getRileyLinkServiceData().lastGoodFrequency = lastGoodFrequency; RileyLinkUtil.getRileyLinkServiceData().lastGoodFrequency = lastGoodFrequency;
if (RileyLinkUtil.getRileyLinkTargetFrequency() == null) {
String pumpFrequency = SP.getString(MedtronicConst.Prefs.PumpFrequency, null);
}
if ((lastGoodFrequency > 0.0d) if ((lastGoodFrequency > 0.0d)
&& RileyLinkUtil.getRileyLinkCommunicationManager().isValidFrequency(lastGoodFrequency)) { && RileyLinkUtil.getRileyLinkCommunicationManager().isValidFrequency(lastGoodFrequency)) {

View file

@ -137,21 +137,41 @@ public class ByteUtil {
} }
public static byte[] fromByteArray(List<Byte> byteArray) { // public static byte[] fromByteList(List<Byte> byteArray) {
byte[] rval = new byte[byteArray.size()]; // byte[] rval = new byte[byteArray.size()];
for (int i = 0; i < byteArray.size(); i++) { // for (int i = 0; i < byteArray.size(); i++) {
rval[i] = byteArray.get(i); // rval[i] = byteArray.get(i);
// }
// return rval;
// }
// public static List<Byte> toByteList(byte[] data) {
// ArrayList<Byte> rval = new ArrayList<>(data.length);
// for (int i = 0; i < data.length; i++) {
// rval.add(i, new Byte(data[i]));
// }
// return rval;
// }
public static List<Byte> getListFromByteArray(byte[] array) {
List<Byte> listOut = new ArrayList<Byte>();
for (byte val : array) {
listOut.add(val);
} }
return rval;
return listOut;
} }
public static ArrayList<Byte> toByteArray(byte[] data) { public static byte[] getByteArrayFromList(List<Byte> list) {
ArrayList<Byte> rval = new ArrayList<>(data.length); byte[] out = new byte[list.size()];
for (int i = 0; i < data.length; i++) {
rval.add(i, new Byte(data[i])); for (int i = 0; i < list.size(); i++) {
out[i] = list.get(i);
} }
return rval;
return out;
} }
@ -233,17 +253,6 @@ public class ByteUtil {
} }
public static List<Byte> getListFromByteArray(byte[] array) {
List<Byte> listOut = new ArrayList<Byte>();
for (byte val : array) {
listOut.add(val);
}
return listOut;
}
public static int makeUnsignedShort(int i, int j) { public static int makeUnsignedShort(int i, int j) {
int k = (i & 0xff) << 8 | j & 0xff; int k = (i & 0xff) << 8 | j & 0xff;
return k; return k;
@ -275,19 +284,20 @@ public class ByteUtil {
} }
public static byte[] getByteArrayFromList(List<Byte> list) { public static String getHex(byte abyte0[]) {
byte[] out = new byte[list.size()]; return abyte0 != null ? getHex(abyte0, abyte0.length) : null;
for (int i = 0; i < list.size(); i++) {
out[i] = list.get(i);
}
return out;
} }
public static String getHex(byte abyte0[]) { public static String getString(short abyte0[]) {
return abyte0 != null ? getHex(abyte0, abyte0.length) : null; StringBuilder sb = new StringBuilder();
for (short i : abyte0) {
sb.append(i);
sb.append(" ");
}
return sb.toString();
} }
@ -370,12 +380,17 @@ public class ByteUtil {
} }
public static byte[] createByteArray(String dataFull, int startIndex) { public static byte[] createByteArrayFromCompactString(String dataFull) {
return createByteArray(dataFull, startIndex, dataFull.length()); return createByteArrayFromCompactString(dataFull, 0, dataFull.length());
} }
public static byte[] createByteArray(String dataFull, int startIndex, int length) { public static byte[] createByteArrayFromCompactString(String dataFull, int startIndex) {
return createByteArrayFromCompactString(dataFull, startIndex, dataFull.length());
}
public static byte[] createByteArrayFromCompactString(String dataFull, int startIndex, int length) {
String data = dataFull.substring(startIndex); String data = dataFull.substring(startIndex);

View file

@ -231,7 +231,15 @@ public class MedtronicFragment extends SubscriberFragment {
} else if (pumpStatus.rileyLinkServiceState.isConnecting()) { } else if (pumpStatus.rileyLinkServiceState.isConnecting()) {
rileyLinkStatus.setText("{fa-bluetooth-b spin} " + getTranslation(resourceId)); rileyLinkStatus.setText("{fa-bluetooth-b spin} " + getTranslation(resourceId));
} else if (pumpStatus.rileyLinkServiceState.isError()) { } else if (pumpStatus.rileyLinkServiceState.isError()) {
rileyLinkStatus.setText("{fa-bluetooth-b} " + getTranslation(resourceId));
RileyLinkError rileyLinkError = RileyLinkUtil.getError();
if (rileyLinkError == null)
rileyLinkStatus.setText("{fa-bluetooth-b} " + getTranslation(resourceId));
else
rileyLinkStatus.setText("{fa-bluetooth-b} "
+ getTranslation(rileyLinkError.getResourceId(RileyLinkTargetDevice.MedtronicPump)));
rileyLinkStatus.setTextColor(Color.RED); rileyLinkStatus.setTextColor(Color.RED);
} else { } else {
rileyLinkStatus.setText("{fa-bluetooth-b} " + getTranslation(resourceId)); rileyLinkStatus.setText("{fa-bluetooth-b} " + getTranslation(resourceId));
@ -274,8 +282,27 @@ public class MedtronicFragment extends SubscriberFragment {
if (cmd == null) if (cmd == null)
pumpStatusIconView.setText(" " + MainApp.gs(pumpStatus.pumpDeviceState.getResourceId())); pumpStatusIconView.setText(" " + MainApp.gs(pumpStatus.pumpDeviceState.getResourceId()));
else else {
pumpStatusIconView.setText(" " + cmd.name()); Integer resourceId = cmd.getResourceId();
if (cmd == MedtronicCommandType.GetHistoryData) {
if (resourceId == null) {
pumpStatusIconView.setText(String.format(" Get History - Page %d (%d/16)",
MedtronicUtil.pageNumber, MedtronicUtil.frameNumber));
} else {
pumpStatusIconView.setText(MainApp.gs(resourceId, MedtronicUtil.pageNumber,
MedtronicUtil.frameNumber));
}
} else {
if (resourceId == null) {
pumpStatusIconView.setText(" " + cmd.name());
} else {
pumpStatusIconView.setText(" " + getTranslation(resourceId));
}
}
}
} }
break; break;

View file

@ -118,13 +118,15 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
serviceConnection = new ServiceConnection() { serviceConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) { public void onServiceDisconnected(ComponentName name) {
LOG.debug("RileyLinkMedtronicService is disconnected"); if (isLoggingEnabled())
LOG.debug("RileyLinkMedtronicService is disconnected");
medtronicService = null; medtronicService = null;
} }
public void onServiceConnected(ComponentName name, IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
LOG.debug("RileyLinkMedtronicService is connected"); if (isLoggingEnabled())
LOG.debug("RileyLinkMedtronicService is connected");
RileyLinkMedtronicService.LocalBinder mLocalBinder = (RileyLinkMedtronicService.LocalBinder)service; RileyLinkMedtronicService.LocalBinder mLocalBinder = (RileyLinkMedtronicService.LocalBinder)service;
medtronicService = mLocalBinder.getServiceInstance(); medtronicService = mLocalBinder.getServiceInstance();
@ -134,7 +136,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
SystemClock.sleep(5000); SystemClock.sleep(5000);
if (MedtronicUtil.getPumpStatus() != null) { if (MedtronicUtil.getPumpStatus() != null) {
LOG.debug("Starting Medtronic-RileyLink service"); if (isLoggingEnabled())
LOG.debug("Starting Medtronic-RileyLink service");
if (MedtronicUtil.getPumpStatus().setNotInPreInit()) { if (MedtronicUtil.getPumpStatus().setNotInPreInit()) {
break; break;
} }
@ -170,7 +173,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
pumpStatusLocal.refreshConfiguration(); pumpStatusLocal.refreshConfiguration();
LOG.debug("initPumpStatusData: {}", this.pumpStatusLocal); if (isLoggingEnabled())
LOG.debug("initPumpStatusData: {}", this.pumpStatusLocal);
this.pumpStatus = pumpStatusLocal; this.pumpStatus = pumpStatusLocal;
@ -182,6 +186,17 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
SP.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis()); SP.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis());
} }
migrateSettings();
}
private void migrateSettings() {
if ("US (916 MHz)".equals(SP.getString(MedtronicConst.Prefs.PumpFrequency, null))) {
SP.putString(MedtronicConst.Prefs.PumpFrequency, MainApp.gs(R.string.medtronic_pump_frequency_us_ca));
}
} }
@ -193,7 +208,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
do { do {
SystemClock.sleep(60000); SystemClock.sleep(60000);
if (doWeHaveAnyStatusNeededRefereshing()) { Map<MedtronicStatusRefreshType, Long> statusRefresh = workWithStatusRefresh(
StatusRefreshAction.GetData, null, null);
if (doWeHaveAnyStatusNeededRefereshing(statusRefresh)) {
ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Scheduled Status Refresh", null); ConfigBuilderPlugin.getPlugin().getCommandQueue().readStatus("Scheduled Status Refresh", null);
} }
@ -230,7 +248,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override @Override
public boolean isInitialized() { public boolean isInitialized() {
// TODO remove // TODO remove
LOG.debug("MedtronicPumpPlugin::isInitialized"); if (isLoggingEnabled())
LOG.debug("MedtronicPumpPlugin::isInitialized");
return isServiceSet() && isInitialized; return isServiceSet() && isInitialized;
} }
@ -245,7 +264,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override @Override
public boolean isBusy() { public boolean isBusy() {
// TODO remove // TODO remove
LOG.debug("MedtronicPumpPlugin::isBusy"); if (isLoggingEnabled())
LOG.debug("MedtronicPumpPlugin::isBusy");
return isServiceSet() && medtronicService.isBusy(); return isServiceSet() && medtronicService.isBusy();
} }
@ -253,7 +273,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override @Override
public boolean isConnected() { public boolean isConnected() {
// TODO remove // TODO remove
LOG.debug("MedtronicPumpPlugin::isConnected"); if (isLoggingEnabled())
LOG.debug("MedtronicPumpPlugin::isConnected");
return isServiceSet() && medtronicService.isInitialized(); return isServiceSet() && medtronicService.isInitialized();
} }
@ -261,7 +282,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override @Override
public boolean isConnecting() { public boolean isConnecting() {
// TODO remove // TODO remove
LOG.debug("MedtronicPumpPlugin::isConnecting"); if (isLoggingEnabled())
LOG.debug("MedtronicPumpPlugin::isConnecting");
return !isServiceSet() || !medtronicService.isInitialized(); return !isServiceSet() || !medtronicService.isInitialized();
} }
@ -294,7 +316,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (rileyLinkServiceState != RileyLinkServiceState.PumpConnectorReady // if (rileyLinkServiceState != RileyLinkServiceState.PumpConnectorReady //
&& rileyLinkServiceState != RileyLinkServiceState.RileyLinkReady // && rileyLinkServiceState != RileyLinkServiceState.RileyLinkReady //
&& rileyLinkServiceState != RileyLinkServiceState.TuneUpDevice) { && rileyLinkServiceState != RileyLinkServiceState.TuneUpDevice) {
LOG.error("RileyLink unreachable."); if (isLoggingEnabled())
LOG.error("RileyLink unreachable.");
return false; return false;
} }
@ -304,14 +327,18 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void refreshAnyStatusThatNeedsToBeRefreshed() { private void refreshAnyStatusThatNeedsToBeRefreshed() {
if (!doWeHaveAnyStatusNeededRefereshing()) { Map<MedtronicStatusRefreshType, Long> statusRefresh = workWithStatusRefresh(StatusRefreshAction.GetData, null,
null);
if (!doWeHaveAnyStatusNeededRefereshing(statusRefresh)) {
return; return;
} }
boolean resetTime = false; boolean resetTime = false;
if (isPumpNotReachable()) { if (isPumpNotReachable()) {
LOG.error("Pump unreachable."); if (isLoggingEnabled())
LOG.error("Pump unreachable.");
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable); MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable);
return; return;
@ -322,7 +349,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Set<MedtronicStatusRefreshType> refreshTypesNeededToReschedule = new HashSet<>(); Set<MedtronicStatusRefreshType> refreshTypesNeededToReschedule = new HashSet<>();
// execute // execute
for (Map.Entry<MedtronicStatusRefreshType, Long> refreshType : statusRefreshMap.entrySet()) { for (Map.Entry<MedtronicStatusRefreshType, Long> refreshType : statusRefresh.entrySet()) {
if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) { if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) {
@ -361,9 +388,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
} }
private boolean doWeHaveAnyStatusNeededRefereshing() { private boolean doWeHaveAnyStatusNeededRefereshing(Map<MedtronicStatusRefreshType, Long> statusRefresh) {
for (Map.Entry<MedtronicStatusRefreshType, Long> refreshType : statusRefreshMap.entrySet()) { for (Map.Entry<MedtronicStatusRefreshType, Long> refreshType : statusRefresh.entrySet()) {
if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) { if (refreshType.getValue() > 0 && System.currentTimeMillis() > refreshType.getValue()) {
return true; return true;
@ -381,7 +408,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void initializePump(boolean realInit) { private void initializePump(boolean realInit) {
LOG.info(getLogPrefix() + "initializePump - start"); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "initializePump - start");
if (medtronicCommunicationManager == null) { if (medtronicCommunicationManager == null) {
medtronicCommunicationManager = MedtronicCommunicationManager.getInstance(); medtronicCommunicationManager = MedtronicCommunicationManager.getInstance();
@ -394,7 +422,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (isRefresh) { if (isRefresh) {
if (isPumpNotReachable()) { if (isPumpNotReachable()) {
LOG.error(getLogPrefix() + "initializePump::Pump unreachable."); if (isLoggingEnabled())
LOG.error(getLogPrefix() + "initializePump::Pump unreachable.");
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable); MedtronicUtil.sendNotification(MedtronicNotificationType.PumpUnreachable);
setRefreshButtonEnabled(true); setRefreshButtonEnabled(true);
@ -410,7 +439,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
medtronicUIComm.executeCommand(MedtronicCommandType.PumpModel); medtronicUIComm.executeCommand(MedtronicCommandType.PumpModel);
} else { } else {
if (pumpStatusLocal.medtronicDeviceType != MedtronicUtil.getMedtronicPumpModel()) { if (pumpStatusLocal.medtronicDeviceType != MedtronicUtil.getMedtronicPumpModel()) {
LOG.warn(getLogPrefix() + "Configured pump is not the same as one detected."); if (isLoggingEnabled())
LOG.warn(getLogPrefix() + "Configured pump is not the same as one detected.");
MedtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame); MedtronicUtil.sendNotification(MedtronicNotificationType.PumpTypeNotSame);
} }
} }
@ -443,7 +473,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
int errorCount = medtronicUIComm.getInvalidResponsesCount(); int errorCount = medtronicUIComm.getInvalidResponsesCount();
if (errorCount >= 5) { if (errorCount >= 5) {
LOG.error("Number of error counts was 5 or more. Starting tunning."); if (isLoggingEnabled())
LOG.error("Number of error counts was 5 or more. Starting tunning.");
setRefreshButtonEnabled(true); setRefreshButtonEnabled(true);
ServiceTaskExecutor.startTask(new WakeAndTuneTask()); ServiceTaskExecutor.startTask(new WakeAndTuneTask());
return; return;
@ -523,15 +554,18 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
} }
if (!invalid) { if (!invalid) {
LOG.debug("Basal profile is same as AAPS one."); if (isLoggingEnabled())
LOG.debug("Basal profile is same as AAPS one.");
basalProfileChanged = false; basalProfileChanged = false;
} else { } else {
LOG.debug("Basal profile on Pump is different than the AAPS one."); if (isLoggingEnabled())
LOG.debug("Basal profile on Pump is different than the AAPS one.");
} }
} else { } else {
invalid = true; invalid = true;
LOG.debug("Basal profile NO DATA"); if (isLoggingEnabled())
LOG.debug("Basal profile NO DATA");
} }
isBasalProfileInvalid = invalid; isBasalProfileInvalid = invalid;
@ -563,7 +597,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private MedtronicPumpStatus getMDTPumpStatus() { private MedtronicPumpStatus getMDTPumpStatus() {
if (pumpStatusLocal == null) { if (pumpStatusLocal == null) {
// FIXME I don't know why this happens // FIXME I don't know why this happens
LOG.warn("!!!! Reset Pump Status Local"); if (isLoggingEnabled())
LOG.warn("!!!! Reset Pump Status Local");
pumpStatusLocal = MedtronicUtil.getPumpStatus(); pumpStatusLocal = MedtronicUtil.getPumpStatus();
} }
@ -602,6 +637,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// TODO display bolus // TODO display bolus
setRefreshButtonEnabled(true);
if (response) { if (response) {
// FIXME this needs to be fixed to read info from history // FIXME this needs to be fixed to read info from history
boolean treatmentCreated = TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true); boolean treatmentCreated = TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo, true);
@ -613,14 +650,17 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
incrementStatistics(detailedBolusInfo.isSMB ? MedtronicConst.Statistics.SMBBoluses incrementStatistics(detailedBolusInfo.isSMB ? MedtronicConst.Statistics.SMBBoluses
: MedtronicConst.Statistics.StandardBoluses); : MedtronicConst.Statistics.StandardBoluses);
return new PumpEnactResult().success(response) //
.enacted(response) //
.bolusDelivered(detailedBolusInfo.insulin) //
.carbsDelivered(detailedBolusInfo.carbs);
} else {
return new PumpEnactResult().success(false).enacted(false) //
.comment(MainApp.gs(R.string.medtronic_cmd_bolus_could_not_be_delivered));
} }
// readPumpHistory();
setRefreshButtonEnabled(true);
return new PumpEnactResult().success(response).enacted(response);
// pump.activity = MainApp.gs(R.string.combo_pump_action_bolusing, detailedBolusInfo.insulin); // pump.activity = MainApp.gs(R.string.combo_pump_action_bolusing, detailedBolusInfo.insulin);
// MainApp.bus().post(new EventComboPumpUpdateGUI()); // MainApp.bus().post(new EventComboPumpUpdateGUI());
// //
@ -769,19 +809,22 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
getMDTPumpStatus(); getMDTPumpStatus();
LOG.info(getLogPrefix() + "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "setTempBasalAbsolute: rate: {}, duration={}", absoluteRate, durationInMinutes);
// read current TBR // read current TBR
TempBasalPair tbrCurrent = readTBR(); TempBasalPair tbrCurrent = readTBR();
if (tbrCurrent == null) { if (tbrCurrent == null) {
LOG.warn(getLogPrefix() + "setTempBasalAbsolute - Could not read current TBR, canceling operation."); if (isLoggingEnabled())
LOG.warn(getLogPrefix() + "setTempBasalAbsolute - Could not read current TBR, canceling operation.");
finishAction("TBR"); finishAction("TBR");
return new PumpEnactResult().success(false).enacted(false) return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_cant_read_tbr)); .comment(MainApp.gs(R.string.medtronic_cmd_cant_read_tbr));
} else { } else {
LOG.info(getLogPrefix() + "setTempBasalAbsolute: Current Basal: duration: {} min, rate={}", if (isLoggingEnabled())
tbrCurrent.getDurationMinutes(), tbrCurrent.getInsulinRate()); LOG.info(getLogPrefix() + "setTempBasalAbsolute: Current Basal: duration: {} min, rate={}",
tbrCurrent.getDurationMinutes(), tbrCurrent.getInsulinRate());
} }
if (!enforceNew) { if (!enforceNew) {
@ -795,7 +838,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
} }
if (sameRate) { if (sameRate) {
LOG.info(getLogPrefix() + "setTempBasalAbsolute - No enforceNew and same rate. Exiting."); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "setTempBasalAbsolute - No enforceNew and same rate. Exiting.");
finishAction("TBR"); finishAction("TBR");
return new PumpEnactResult().success(true).enacted(false); return new PumpEnactResult().success(true).enacted(false);
} }
@ -805,7 +849,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// if TBR is running we will cancel it. // if TBR is running we will cancel it.
if (tbrCurrent.getInsulinRate() != 0.0f && tbrCurrent.getDurationMinutes() > 0) { if (tbrCurrent.getInsulinRate() != 0.0f && tbrCurrent.getDurationMinutes() > 0) {
LOG.info(getLogPrefix() + "setTempBasalAbsolute - TBR running - so canceling it."); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "setTempBasalAbsolute - TBR running - so canceling it.");
// CANCEL // CANCEL
@ -814,14 +859,16 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask2.returnData; Boolean response = (Boolean)responseTask2.returnData;
if (response) { if (response) {
LOG.info(getLogPrefix() + "setTempBasalAbsolute - Current TBR cancelled."); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "setTempBasalAbsolute - Current TBR cancelled.");
} else { } else {
LOG.error(getLogPrefix() + "setTempBasalAbsolute - Cancel TBR failed."); if (isLoggingEnabled())
LOG.error(getLogPrefix() + "setTempBasalAbsolute - Cancel TBR failed.");
finishAction("TBR"); finishAction("TBR");
return new PumpEnactResult().success(false).enacted(false) return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_cant_cancel_tbr)); .comment(MainApp.gs(R.string.medtronic_cmd_cant_cancel_tbr_stop_op));
} }
} }
@ -831,7 +878,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask.returnData; Boolean response = (Boolean)responseTask.returnData;
LOG.info(getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + response); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "setTempBasalAbsolute - setTBR. Response: " + response);
if (response) { if (response) {
// FIXME put this into UIPostProcessor // FIXME put this into UIPostProcessor
@ -848,13 +896,19 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStart); TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStart);
incrementStatistics(MedtronicConst.Statistics.TBRsSet); incrementStatistics(MedtronicConst.Statistics.TBRsSet);
finishAction("TBR");
return new PumpEnactResult().success(response).enacted(response) //
.absolute(absoluteRate).duration(durationInMinutes);
} else {
finishAction("TBR");
return new PumpEnactResult().success(response).enacted(response) //
.comment(MainApp.gs(R.string.medtronic_cmd_tbr_could_not_be_delivered));
} }
finishAction("TBR");
setRefreshButtonEnabled(true);
return new PumpEnactResult().success(response).enacted(response);
} }
@ -871,7 +925,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void readPumpHistory() { private void readPumpHistory() {
LOG.error(getLogPrefix() + "readPumpHistory WIP."); if (isLoggingEnabled())
LOG.error(getLogPrefix() + "readPumpHistory WIP.");
readPumpHistoryLogic(); readPumpHistoryLogic();
@ -894,12 +949,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (medtronicHistoryData.isPumpSuspended(this.pumpState == PumpDriverState.Suspended)) { if (medtronicHistoryData.isPumpSuspended(this.pumpState == PumpDriverState.Suspended)) {
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1); scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, -1);
this.pumpState = PumpDriverState.Suspended; this.pumpState = PumpDriverState.Suspended;
LOG.debug(getLogPrefix() + "isPumpSuspended: true"); if (isLoggingEnabled())
LOG.debug(getLogPrefix() + "isPumpSuspended: true");
} else { } else {
if (previousState == PumpDriverState.Suspended) { if (previousState == PumpDriverState.Suspended) {
this.pumpState = PumpDriverState.Ready; this.pumpState = PumpDriverState.Ready;
} }
LOG.debug(getLogPrefix() + "isPumpSuspended: false"); if (isLoggingEnabled())
LOG.debug(getLogPrefix() + "isPumpSuspended: false");
} }
List<PumpHistoryEntry> tdds = medtronicHistoryData.getTDDs(); List<PumpHistoryEntry> tdds = medtronicHistoryData.getTDDs();
@ -910,6 +967,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
List<PumpHistoryEntry> tdds2 = medtronicHistoryData.getTDDs2(); List<PumpHistoryEntry> tdds2 = medtronicHistoryData.getTDDs2();
// FIXME
LOG.debug("TDDs2: {}", gsonInstancePretty.toJson(tdds2)); LOG.debug("TDDs2: {}", gsonInstancePretty.toJson(tdds2));
List<PumpHistoryEntry> treatments = medtronicHistoryData.getTreatments(); List<PumpHistoryEntry> treatments = medtronicHistoryData.getTreatments();
@ -954,7 +1012,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (lastPumpHistoryEntry == null) { if (lastPumpHistoryEntry == null) {
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: null"); if (isLoggingEnabled())
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: null");
Long lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L); Long lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L);
@ -963,14 +1022,16 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
medtronicHistoryData.setIsInInit(true); medtronicHistoryData.setIsInInit(true);
if (lastPumpHistoryEntryTime == 0L) { if (lastPumpHistoryEntryTime == 0L) {
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: 0L - targetDate: " if (isLoggingEnabled())
+ targetDate); LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: 0L - targetDate: "
+ targetDate);
targetDate = timeMinus36h; targetDate = timeMinus36h;
} else { } else {
LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime); LocalDateTime lastHistoryRecordTime = DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime);
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: {} - targetDate: {}", if (isLoggingEnabled())
lastHistoryRecordTime, targetDate); LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntryTime: {} - targetDate: {}",
lastHistoryRecordTime, targetDate);
medtronicHistoryData.setLastHistoryRecordTime(DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime)); medtronicHistoryData.setLastHistoryRecordTime(DateTimeUtil.toLocalDateTime(lastPumpHistoryEntryTime));
@ -984,11 +1045,13 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
targetDate = (timeMinus36h.isAfter(lastHistoryRecordTime) ? timeMinus36h : lastHistoryRecordTime); targetDate = (timeMinus36h.isAfter(lastHistoryRecordTime) ? timeMinus36h : lastHistoryRecordTime);
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): targetDate: " + targetDate); if (isLoggingEnabled())
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): targetDate: " + targetDate);
} }
} else { } else {
LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - {}", if (isLoggingEnabled())
gsonInstancePretty.toJson(lastPumpHistoryEntry)); LOG.debug(getLogPrefix() + "readPumpHistoryLogic(): lastPumpHistoryEntry: not null - {}",
gsonInstancePretty.toJson(lastPumpHistoryEntry));
medtronicHistoryData.setIsInInit(false); medtronicHistoryData.setIsInInit(false);
medtronicHistoryData.setLastHistoryRecordTime(null); medtronicHistoryData.setLastHistoryRecordTime(null);
} }
@ -1000,7 +1063,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
PumpHistoryEntry latestEntry = historyResult.getLatestEntry(); PumpHistoryEntry latestEntry = historyResult.getLatestEntry();
LOG.debug(getLogPrefix() + "Last entry: " + latestEntry); if (isLoggingEnabled())
LOG.debug(getLogPrefix() + "Last entry: " + latestEntry);
if (latestEntry == null) // no new history to read if (latestEntry == null) // no new history to read
return; return;
@ -1053,20 +1117,50 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
else else
min = 15; min = 15;
statusRefreshMap.put(refreshType, getTimeInFutureFromMinutes(min)); workWithStatusRefresh(StatusRefreshAction.Add, refreshType, getTimeInFutureFromMinutes(min));
} }
break; break;
case PumpTime: case PumpTime:
case Configuration: case Configuration:
case PumpHistory: { case PumpHistory: {
statusRefreshMap.put(refreshType, getTimeInFutureFromMinutes(refreshType.getRefreshTime() workWithStatusRefresh(StatusRefreshAction.Add, refreshType,
+ additionalTimeInMinutes)); getTimeInFutureFromMinutes(refreshType.getRefreshTime() + additionalTimeInMinutes));
} }
break; break;
} }
} }
private enum StatusRefreshAction {
Add, //
GetData;
}
private synchronized Map<MedtronicStatusRefreshType, Long> workWithStatusRefresh(StatusRefreshAction action,
MedtronicStatusRefreshType statusRefreshType, Long time) {
switch (action) {
case Add: {
statusRefreshMap.put(statusRefreshType, time);
return null;
}
case GetData: {
Map<MedtronicStatusRefreshType, Long> shallowCopy = new HashMap<>();
shallowCopy.putAll(statusRefreshMap);
return shallowCopy;
}
default:
return null;
}
}
private long getTimeInFutureFromMinutes(int minutes) { private long getTimeInFutureFromMinutes(int minutes) {
return System.currentTimeMillis() + getTimeInMs(minutes); return System.currentTimeMillis() + getTimeInMs(minutes);
@ -1099,7 +1193,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override @Override
public PumpEnactResult cancelTempBasal(boolean enforceNew) { public PumpEnactResult cancelTempBasal(boolean enforceNew) {
LOG.info(getLogPrefix() + "cancelTempBasal - started"); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "cancelTempBasal - started");
if (isPumpNotReachable()) { if (isPumpNotReachable()) {
@ -1118,12 +1213,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (tbrCurrent != null) { if (tbrCurrent != null) {
if (tbrCurrent.getInsulinRate() == 0.0f && tbrCurrent.getDurationMinutes() == 0) { if (tbrCurrent.getInsulinRate() == 0.0f && tbrCurrent.getDurationMinutes() == 0) {
LOG.info(getLogPrefix() + "cancelTempBasal - TBR already canceled."); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "cancelTempBasal - TBR already canceled.");
finishAction("TBR"); finishAction("TBR");
return new PumpEnactResult().success(true).enacted(false); return new PumpEnactResult().success(true).enacted(false);
} }
} else { } else {
LOG.warn(getLogPrefix() + "cancelTempBasal - Could not read currect TBR, canceling operation."); if (isLoggingEnabled())
LOG.warn(getLogPrefix() + "cancelTempBasal - Could not read currect TBR, canceling operation.");
finishAction("TBR"); finishAction("TBR");
return new PumpEnactResult().success(false).enacted(false) return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_cant_read_tbr)); .comment(MainApp.gs(R.string.medtronic_cmd_cant_read_tbr));
@ -1133,22 +1230,35 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask2.returnData; Boolean response = (Boolean)responseTask2.returnData;
if (response) {
LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR successful.");
} else {
LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR failed.");
}
finishAction("TBR"); finishAction("TBR");
return new PumpEnactResult().success(response).enacted(response); if (response) {
if (isLoggingEnabled())
LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR successful.");
TemporaryBasal tempBasal = new TemporaryBasal() //
.date(System.currentTimeMillis()) //
.duration(0) //
.source(Source.USER);
TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempBasal);
return new PumpEnactResult().success(response).enacted(response) //
.isTempCancel(true);
} else {
if (isLoggingEnabled())
LOG.info(getLogPrefix() + "cancelTempBasal - Cancel TBR failed.");
return new PumpEnactResult().success(response).enacted(response) //
.comment(MainApp.gs(R.string.medtronic_cmd_cant_cancel_tbr));
}
} }
@Override @Override
public PumpEnactResult setNewBasalProfile(Profile profile) { public PumpEnactResult setNewBasalProfile(Profile profile) {
LOG.error(getLogPrefix() + "setNewBasalProfile - WIP."); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "setNewBasalProfile");
setRefreshButtonEnabled(false); setRefreshButtonEnabled(false);
@ -1180,9 +1290,15 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean)responseTask.returnData; Boolean response = (Boolean)responseTask.returnData;
LOG.info(getLogPrefix() + "Basal Profile was set: " + response); if (isLoggingEnabled())
LOG.info(getLogPrefix() + "Basal Profile was set: " + response);
return new PumpEnactResult().success(response).enacted(response); if (response) {
return new PumpEnactResult().success(response).enacted(response);
} else {
return new PumpEnactResult().success(response).enacted(response) //
.comment(MainApp.gs(R.string.medtronic_cmd_basal_profile_could_not_be_set));
}
} }
@ -1205,7 +1321,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
} }
return stringBuilder.length() == 0 ? null : stringBuilder.toString(); return stringBuilder.length() == 0 ? null : stringBuilder.toString();
} }
@ -1236,28 +1351,26 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// OPERATIONS not supported by Pump or Plugin // OPERATIONS not supported by Pump or Plugin
@Override // @Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) { // public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
LOG.error("MedtronicPumpPlugin::setExtendedBolus NOT SUPPORTED."); // LOG.error("MedtronicPumpPlugin::setExtendedBolus NOT SUPPORTED.");
return OPERATION_NOT_SUPPORTED; // return OPERATION_NOT_SUPPORTED;
} // }
//
//
@Override // @Override
public PumpEnactResult cancelExtendedBolus() { // public PumpEnactResult cancelExtendedBolus() {
LOG.warn("cancelExtendedBolus - operation not supported."); // LOG.warn("cancelExtendedBolus - operation not supported.");
return getOperationNotSupportedWithCustomText(R.string.medtronic_cmd_cancel_bolus_not_supported); // return getOperationNotSupportedWithCustomText(R.string.medtronic_cmd_cancel_bolus_not_supported);
} // }
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
boolean enforceNew) {
LOG.error("setTempBasalPercent NOT IMPLEMENTED.");
// we will never come here unless somebody has played with configuration in PumpType
return OPERATION_NOT_SUPPORTED;
}
// @Override
// public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile,
// boolean enforceNew) {
// LOG.error("setTempBasalPercent NOT IMPLEMENTED.");
// // we will never come here unless somebody has played with configuration in PumpType
// return OPERATION_NOT_SUPPORTED;
// }
// // we don't loadTDD. TDD is read from Pump History // // we don't loadTDD. TDD is read from Pump History
// @Override // @Override

View file

@ -13,6 +13,7 @@ import android.os.SystemClock;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkCommunicationException;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RFSpyResponse; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RFSpyResponse;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RLMessage; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RLMessage;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioPacket; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RadioPacket;
@ -22,12 +23,10 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil; import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump; import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.Page;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RawHistoryPage; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.RawHistoryPage;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry; 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.history.pump.PumpHistoryResult;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.ButtonPressCarelinkMessageBody;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkLongMessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkLongMessageBody;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkShortMessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.CarelinkShortMessageBody;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.GetHistoryPageCarelinkMessageBody; import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.GetHistoryPageCarelinkMessageBody;
@ -42,7 +41,6 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType; import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicDeviceType; import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicDeviceType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpDeviceState; import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpDeviceState;
import info.nightscout.androidaps.plugins.PumpMedtronic.service.RileyLinkMedtronicService;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil; import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.utils.SP; import info.nightscout.utils.SP;
@ -54,8 +52,9 @@ import info.nightscout.utils.SP;
public class MedtronicCommunicationManager extends RileyLinkCommunicationManager { public class MedtronicCommunicationManager extends RileyLinkCommunicationManager {
private static final Logger LOG = LoggerFactory.getLogger(MedtronicCommunicationManager.class); private static final Logger LOG = LoggerFactory.getLogger(MedtronicCommunicationManager.class);
private static final int MAX_COMMAND_RETRIES = 2; private static final int MAX_COMMAND_TRIES = 3;
private static final int DEFAULT_TIMEOUT = 2000; private static final int DEFAULT_TIMEOUT = 2000;
private static final long RILEYLINK_TIMEOUT = 15 * 60 * 1000; // 15 min
static MedtronicCommunicationManager medtronicCommunicationManager; static MedtronicCommunicationManager medtronicCommunicationManager;
String errorMessage; String errorMessage;
@ -121,17 +120,51 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
for (int retry = 0; retry < 5; retry++) { for (int retry = 0; retry < 5; retry++) {
LOG.error("isDeviceReachable. Waking pump... " + (retry != 0 ? " (retry " + retry + ")" : "")); LOG.debug("isDeviceReachable. Waking pump... " + (retry != 0 ? " (retry " + retry + ")" : ""));
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData); // simple boolean connected = connectToDevice();
RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte)0,
(byte)200, (byte)0, (byte)0, 25000, (byte)0); if (connected)
LOG.info("wakeup: raw response is " + ByteUtil.shortHexString(rfSpyResponse.getRaw())); return true;
SystemClock.sleep(1000);
}
if (state != PumpDeviceState.PumpUnreachable)
MedtronicUtil.setPumpDeviceState(PumpDeviceState.PumpUnreachable);
if (!canPreventTuneUp) {
long diff = System.currentTimeMillis() - MedtronicUtil.getPumpStatus().lastConnection;
if (diff > RILEYLINK_TIMEOUT) {
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
}
}
return false;
}
private boolean connectToDevice() {
PumpDeviceState state = MedtronicUtil.getPumpDeviceState();
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData); // simple
RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte)0, (byte)200,
(byte)0, (byte)0, 25000, (byte)0);
LOG.info("wakeup: raw response is " + ByteUtil.shortHexString(rfSpyResponse.getRaw()));
if (rfSpyResponse.wasTimeout()) {
LOG.error("isDeviceReachable. Failed to find pump (timeout).");
} else if (rfSpyResponse.looksLikeRadioPacket()) {
RadioResponse radioResponse = new RadioResponse();
try {
radioResponse.init(rfSpyResponse.getRaw());
if (rfSpyResponse.wasTimeout()) {
LOG.error("isDeviceReachable. Failed to find pump (timeout).");
} else if (rfSpyResponse.looksLikeRadioPacket()) {
RadioResponse radioResponse = new RadioResponse(rfSpyResponse.getRaw());
if (radioResponse.isValid()) { if (radioResponse.isValid()) {
PumpMessage pumpResponse = createResponseMessage(radioResponse.getPayload(), PumpMessage.class); PumpMessage pumpResponse = createResponseMessage(radioResponse.getPayload(), PumpMessage.class);
@ -175,20 +208,16 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.warn("isDeviceReachable. Failed to parse radio response: " LOG.warn("isDeviceReachable. Failed to parse radio response: "
+ ByteUtil.shortHexString(rfSpyResponse.getRaw())); + ByteUtil.shortHexString(rfSpyResponse.getRaw()));
} }
} else {
LOG.warn("isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.getRaw())); } catch (RileyLinkCommunicationException e) {
LOG.warn("isDeviceReachable. Failed to decode radio response: "
+ ByteUtil.shortHexString(rfSpyResponse.getRaw()));
} }
SystemClock.sleep(1000); } else {
LOG.warn("isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.getRaw()));
} }
if (state != PumpDeviceState.PumpUnreachable)
MedtronicUtil.setPumpDeviceState(PumpDeviceState.PumpUnreachable);
if (!canPreventTuneUp)
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
return false; return false;
} }
@ -242,7 +271,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
// FIXME remove debugs - Andy // FIXME remove debugs - Andy
private PumpMessage runCommandWithArgs(PumpMessage msg) { private PumpMessage runCommandWithArgs(PumpMessage msg) throws RileyLinkCommunicationException {
if (debugSetCommands) if (debugSetCommands)
LOG.debug("Run command with Args: "); LOG.debug("Run command with Args: ");
@ -267,75 +296,75 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
} }
@Deprecated // @Deprecated
private PumpMessage runCommandWithArgsLong(MedtronicCommandType commandType, byte[] content) { // private PumpMessage runCommandWithArgsLong(MedtronicCommandType commandType, byte[] content) {
//
// LOG.debug("Run command with Args (Long): {}", commandType.name());
//
// PumpMessage rval = null;
// PumpMessage shortMessage = makePumpMessage(commandType, new CarelinkShortMessageBody(new byte[] { 0 }));
// // look for ack from short message
// PumpMessage shortResponse = sendAndListen(shortMessage);
//
// if (shortResponse.commandType != MedtronicCommandType.CommandACK) {
// LOG.error("runCommandWithArgs: Pump did not ack Attention packet");
//
// return new PumpMessage("No ACK after start message.");
// }
//
// int start = 0;
// int frameNr = 1;
// int len = 0;
//
// do {
//
// if (start == 0)
// LOG.debug("Run command with Args(Long): Got ACK response for Attention packet");
// else
// LOG.debug("Run command with Args(Long): Got ACK response for frame #{}", (frameNr - 1));
//
// if (start + 64 > content.length) {
// len = content.length - start;
//
// if (len == 0)
// break;
// } else {
// len = 64;
// }
//
// byte frame[] = new byte[65];
//
// frame[0] = (byte)frameNr;
//
// System.arraycopy(content, start, frame, 1, len);
//
// PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(frame));
//
// rval = sendAndListen(msg);
//
// if (rval.commandType != MedtronicCommandType.CommandACK) {
// LOG.error("runCommandWithArgs(Long): Pump did not ACK frame #{}", frameNr);
//
// return new PumpMessage("No ACK after frame #" + frameNr);
// }
//
// if (len != 64) {
// LOG.debug("Run command with Args(Long): Got ACK response for frame #{}", (frameNr));
// break;
// }
//
// start += 64;
// frameNr++;
//
// } while (true);
//
// return rval;
//
// // return new PumpMessage("No ACK");
// }
LOG.debug("Run command with Args (Long): {}", commandType.name()); private PumpMessage runCommandWithFrames(MedtronicCommandType commandType, List<List<Byte>> frames)
throws RileyLinkCommunicationException {
PumpMessage rval = null;
PumpMessage shortMessage = makePumpMessage(commandType, new CarelinkShortMessageBody(new byte[] { 0 }));
// look for ack from short message
PumpMessage shortResponse = sendAndListen(shortMessage);
if (shortResponse.commandType != MedtronicCommandType.CommandACK) {
LOG.error("runCommandWithArgs: Pump did not ack Attention packet");
return new PumpMessage("No ACK after start message.");
}
int start = 0;
int frameNr = 1;
int len = 0;
do {
if (start == 0)
LOG.debug("Run command with Args(Long): Got ACK response for Attention packet");
else
LOG.debug("Run command with Args(Long): Got ACK response for frame #{}", (frameNr - 1));
if (start + 64 > content.length) {
len = content.length - start;
if (len == 0)
break;
} else {
len = 64;
}
byte frame[] = new byte[65];
frame[0] = (byte)frameNr;
System.arraycopy(content, start, frame, 1, len);
PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(frame));
rval = sendAndListen(msg);
if (rval.commandType != MedtronicCommandType.CommandACK) {
LOG.error("runCommandWithArgs(Long): Pump did not ACK frame #{}", frameNr);
return new PumpMessage("No ACK after frame #" + frameNr);
}
if (len != 64) {
LOG.debug("Run command with Args(Long): Got ACK response for frame #{}", (frameNr));
break;
}
start += 64;
frameNr++;
} while (true);
return rval;
// return new PumpMessage("No ACK");
}
private PumpMessage runCommandWithFrames(MedtronicCommandType commandType, List<List<Byte>> frames) {
LOG.debug("Run command with Frames: {}", commandType.name()); LOG.debug("Run command with Frames: {}", commandType.name());
@ -390,6 +419,7 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.debug("Current command: " + MedtronicUtil.getCurrentCommand()); LOG.debug("Current command: " + MedtronicUtil.getCurrentCommand());
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Active); MedtronicUtil.setPumpDeviceState(PumpDeviceState.Active);
boolean doneWithError = false;
for (int pageNumber = 0; pageNumber < 16; pageNumber++) { for (int pageNumber = 0; pageNumber < 16; pageNumber++) {
@ -401,7 +431,27 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.info("getPumpHistory: Page {}", pageNumber); LOG.info("getPumpHistory: Page {}", pageNumber);
// LOG.info("getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData())); // LOG.info("getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData()));
// Ask the pump to transfer history (we get first frame?) // Ask the pump to transfer history (we get first frame?)
PumpMessage firstResponse = runCommandWithArgs(getHistoryMsg);
PumpMessage firstResponse = null;
boolean failed = false;
for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) {
try {
firstResponse = runCommandWithArgs(getHistoryMsg);
failed = false;
break;
} catch (RileyLinkCommunicationException e) {
LOG.error("First call for PumpHistory failed (retry={})", retries);
failed = true;
}
}
if (failed) {
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping);
return pumpTotalResult;
}
// LOG.info("getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); // LOG.info("getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents()));
PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody());
@ -426,6 +476,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
rawHistoryPage.appendData(currentResponse.getFrameData()); rawHistoryPage.appendData(currentResponse.getFrameData());
// RileyLinkMedtronicService.getInstance().announceProgress( // RileyLinkMedtronicService.getInstance().announceProgress(
// ((100 / 16) * currentResponse.getFrameNumber() + 1)); // ((100 / 16) * currentResponse.getFrameNumber() + 1));
MedtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber,
currentResponse.getFrameNumber());
LOG.info("getPumpHistory: Got frame {} of Page {}", currentResponse.getFrameNumber(), pageNumber); LOG.info("getPumpHistory: Got frame {} of Page {}", currentResponse.getFrameNumber(), pageNumber);
// Do we need to ask for the next frame? // Do we need to ask for the next frame?
@ -449,26 +501,49 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
"getPumpHistory: 6 failures in attempting to download frame {} of page {}, giving up.", "getPumpHistory: 6 failures in attempting to download frame {} of page {}, giving up.",
expectedFrameNum, pageNumber); expectedFrameNum, pageNumber);
done = true; // failure completion. done = true; // failure completion.
doneWithError = true;
} }
} }
if (!done) { if (!done) {
// ask for next frame // ask for next frame
PumpMessage nextMsg = sendAndListen(ackMsg); PumpMessage nextMsg = null;
currentResponse = new GetHistoryPageCarelinkMessageBody(nextMsg.getMessageBody().getTxData());
for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) {
try {
nextMsg = sendAndListen(ackMsg);
break;
} catch (RileyLinkCommunicationException e) {
LOG.error("Problem acknowledging frame response. (retry={})", retries);
}
}
if (nextMsg != null)
currentResponse = new GetHistoryPageCarelinkMessageBody(nextMsg.getMessageBody().getTxData());
else
LOG.error("We couldn't acknowledge frame from pump, aborting operation.");
} }
} }
if (rawHistoryPage.getLength() != 1024) { if (rawHistoryPage.getLength() != 1024) {
LOG.warn("getPumpHistory: short page. Expected length of 1024, found length of " LOG.warn("getPumpHistory: short page. Expected length of 1024, found length of "
+ rawHistoryPage.getLength()); + rawHistoryPage.getLength());
doneWithError = true;
} }
if (!rawHistoryPage.isChecksumOK()) { if (!rawHistoryPage.isChecksumOK()) {
LOG.error("getPumpHistory: checksum is wrong"); LOG.error("getPumpHistory: checksum is wrong");
doneWithError = true;
} }
// TODO handle error states // TODO handle error states
if (doneWithError) {
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping);
return pumpTotalResult;
}
rawHistoryPage.dumpToDebug(); rawHistoryPage.dumpToDebug();
List<PumpHistoryEntry> medtronicHistoryEntries = pumpHistoryDecoder.processPageAndCreateRecords( List<PumpHistoryEntry> medtronicHistoryEntries = pumpHistoryDecoder.processPageAndCreateRecords(
@ -496,86 +571,85 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
} }
@Deprecated // @Deprecated
public Page getPumpHistoryPage(int pageNumber) { // public Page getPumpHistoryPage(int pageNumber) {
RawHistoryPage rval = new RawHistoryPage(); // RawHistoryPage rval = new RawHistoryPage();
//
if (doWakeUpBeforeCommand) // if (doWakeUpBeforeCommand)
wakeUp(receiverDeviceAwakeForMinutes, false); // wakeUp(receiverDeviceAwakeForMinutes, false);
//
PumpMessage getHistoryMsg = makePumpMessage(MedtronicCommandType.GetHistoryData, // PumpMessage getHistoryMsg = makePumpMessage(MedtronicCommandType.GetHistoryData,
new GetHistoryPageCarelinkMessageBody(pageNumber)); // new GetHistoryPageCarelinkMessageBody(pageNumber));
// LOG.info("getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData())); // // LOG.info("getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData()));
// Ask the pump to transfer history (we get first frame?) // // Ask the pump to transfer history (we get first frame?)
PumpMessage firstResponse = runCommandWithArgs(getHistoryMsg); // PumpMessage firstResponse = runCommandWithArgs(getHistoryMsg);
// LOG.info("getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); // // LOG.info("getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents()));
//
PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); // PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody());
GetHistoryPageCarelinkMessageBody currentResponse = new GetHistoryPageCarelinkMessageBody(firstResponse // GetHistoryPageCarelinkMessageBody currentResponse = new GetHistoryPageCarelinkMessageBody(firstResponse
.getMessageBody().getTxData()); // .getMessageBody().getTxData());
int expectedFrameNum = 1; // int expectedFrameNum = 1;
boolean done = false; // boolean done = false;
// while (expectedFrameNum == currentResponse.getFrameNumber()) { // // while (expectedFrameNum == currentResponse.getFrameNumber()) {
int failures = 0; // int failures = 0;
while (!done) { // while (!done) {
// examine current response for problems. // // examine current response for problems.
byte[] frameData = currentResponse.getFrameData(); // byte[] frameData = currentResponse.getFrameData();
if ((frameData != null) && (frameData.length > 0) && currentResponse.getFrameNumber() == expectedFrameNum) { // if ((frameData != null) && (frameData.length > 0) && currentResponse.getFrameNumber() == expectedFrameNum) {
// success! got a frame. // // success! got a frame.
if (frameData.length != 64) { // if (frameData.length != 64) {
LOG.warn("Expected frame of length 64, got frame of length " + frameData.length); // LOG.warn("Expected frame of length 64, got frame of length " + frameData.length);
// but append it anyway? // // but append it anyway?
} // }
// handle successful frame data // // handle successful frame data
rval.appendData(currentResponse.getFrameData()); // rval.appendData(currentResponse.getFrameData());
RileyLinkMedtronicService.getInstance().announceProgress( // RileyLinkMedtronicService.getInstance().announceProgress(
((100 / 16) * currentResponse.getFrameNumber() + 1)); // ((100 / 16) * currentResponse.getFrameNumber() + 1));
LOG.info("getPumpHistoryPage: Got frame " + currentResponse.getFrameNumber()); // LOG.info("getPumpHistoryPage: Got frame " + currentResponse.getFrameNumber());
// Do we need to ask for the next frame? // // Do we need to ask for the next frame?
if (expectedFrameNum < 16) { // This number may not be correct for pumps other than 522/722 // if (expectedFrameNum < 16) { // This number may not be correct for pumps other than 522/722
expectedFrameNum++; // expectedFrameNum++;
} else { // } else {
done = true; // successful completion // done = true; // successful completion
} // }
} else { // } else {
if (frameData == null) { // if (frameData == null) {
LOG.error("null frame data, retrying"); // LOG.error("null frame data, retrying");
} else if (currentResponse.getFrameNumber() != expectedFrameNum) { // } else if (currentResponse.getFrameNumber() != expectedFrameNum) {
LOG.warn("Expected frame number {}, received {} (retrying)", expectedFrameNum, // LOG.warn("Expected frame number {}, received {} (retrying)", expectedFrameNum,
currentResponse.getFrameNumber()); // currentResponse.getFrameNumber());
} else if (frameData.length == 0) { // } else if (frameData.length == 0) {
LOG.warn("Frame has zero length, retrying"); // LOG.warn("Frame has zero length, retrying");
} // }
failures++; // failures++;
if (failures == 6) { // if (failures == 6) {
LOG.error("6 failures in attempting to download frame {} of page {}, giving up.", expectedFrameNum, // LOG.error("6 failures in attempting to download frame {} of page {}, giving up.", expectedFrameNum,
pageNumber); // pageNumber);
done = true; // failure completion. // done = true; // failure completion.
} // }
} // }
if (!done) { // if (!done) {
// ask for next frame // // ask for next frame
PumpMessage nextMsg = sendAndListen(ackMsg); // PumpMessage nextMsg = sendAndListen(ackMsg);
currentResponse = new GetHistoryPageCarelinkMessageBody(nextMsg.getMessageBody().getTxData()); // currentResponse = new GetHistoryPageCarelinkMessageBody(nextMsg.getMessageBody().getTxData());
} // }
} // }
if (rval.getLength() != 1024) { // if (rval.getLength() != 1024) {
LOG.warn("getPumpHistoryPage: short page. Expected length of 1024, found length of " + rval.getLength()); // LOG.warn("getPumpHistoryPage: short page. Expected length of 1024, found length of " + rval.getLength());
} // }
if (!rval.isChecksumOK()) { // if (!rval.isChecksumOK()) {
LOG.error("getPumpHistoryPage: checksum is wrong"); // LOG.error("getPumpHistoryPage: checksum is wrong");
} // }
//
rval.dumpToDebug(); // rval.dumpToDebug();
//
Page page = new Page(); // Page page = new Page();
// page.parseFrom(rval.getData(),PumpModel.MM522); // // page.parseFrom(rval.getData(),PumpModel.MM522);
// FIXME // // FIXME
page.parseFrom(rval.getData(), MedtronicDeviceType.Medtronic_522); // page.parseFrom(rval.getData(), MedtronicDeviceType.Medtronic_522);
//
return page; // return page;
} // }
// public ArrayList<Page> getAllHistoryPages() { // public ArrayList<Page> getAllHistoryPages() {
// ArrayList<Page> pages = new ArrayList<>(); // ArrayList<Page> pages = new ArrayList<>();
@ -607,18 +681,17 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
// See ButtonPressCarelinkMessageBody // See ButtonPressCarelinkMessageBody
public void pressButton(int which) { // public void pressButton(int which) {
if (doWakeUpBeforeCommand) // if (doWakeUpBeforeCommand)
wakeUp(receiverDeviceAwakeForMinutes, false); // wakeUp(receiverDeviceAwakeForMinutes, false);
//
PumpMessage pressButtonMessage = makePumpMessage(MedtronicCommandType.PushButton, // PumpMessage pressButtonMessage = makePumpMessage(MedtronicCommandType.PushButton,
new ButtonPressCarelinkMessageBody(which)); // new ButtonPressCarelinkMessageBody(which));
PumpMessage resp = sendAndListen(pressButtonMessage); // PumpMessage resp = sendAndListen(pressButtonMessage);
if (resp.commandType != MedtronicCommandType.CommandACK) { // if (resp.commandType != MedtronicCommandType.CommandACK) {
LOG.error("Pump did not ack button press."); // LOG.error("Pump did not ack button press.");
} // }
} // }
@Override @Override
public byte[] createPumpMessageContent(RLMessageType type) { public byte[] createPumpMessageContent(RLMessageType type) {
@ -652,23 +725,22 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
} }
private PumpMessage sendAndGetResponse(MedtronicCommandType commandType) { private PumpMessage sendAndGetResponse(MedtronicCommandType commandType) throws RileyLinkCommunicationException {
return sendAndGetResponse(commandType, null, DEFAULT_TIMEOUT); return sendAndGetResponse(commandType, null, DEFAULT_TIMEOUT);
} }
private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, int timeoutMs) { // private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, int timeoutMs) {
//
return sendAndGetResponse(commandType, null, timeoutMs); // return sendAndGetResponse(commandType, null, timeoutMs);
} // }
//
//
private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, byte[] bodyData) { // private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, byte[] bodyData) {
//
return sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT); // return sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT);
} // }
/** /**
* Main wrapper method for sending data - (for getting responses) * Main wrapper method for sending data - (for getting responses)
@ -678,7 +750,8 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
* @param timeoutMs * @param timeoutMs
* @return * @return
*/ */
private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, byte[] bodyData, int timeoutMs) { private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, byte[] bodyData, int timeoutMs)
throws RileyLinkCommunicationException {
// wakeUp // wakeUp
if (doWakeUpBeforeCommand) if (doWakeUpBeforeCommand)
wakeUp(receiverDeviceAwakeForMinutes, false); wakeUp(receiverDeviceAwakeForMinutes, false);
@ -702,13 +775,13 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
} }
protected PumpMessage sendAndListen(RLMessage msg) { protected PumpMessage sendAndListen(RLMessage msg) throws RileyLinkCommunicationException {
return sendAndListen(msg, 4000); // 2000 return sendAndListen(msg, 4000); // 2000
} }
// All pump communications go through this function. // All pump communications go through this function.
protected PumpMessage sendAndListen(RLMessage msg, int timeout_ms) { protected PumpMessage sendAndListen(RLMessage msg, int timeout_ms) throws RileyLinkCommunicationException {
return sendAndListen(msg, timeout_ms, PumpMessage.class); return sendAndListen(msg, timeout_ms, PumpMessage.class);
} }
@ -721,23 +794,30 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData) { private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData) {
for (int retries = 0; retries < MAX_COMMAND_RETRIES; retries++) { for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) {
PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT try {
+ (DEFAULT_TIMEOUT * retries)); PumpMessage response = null;
String check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength); response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries));
if (check == null) { String check = checkResponseContent(response, commandType.commandDescription,
commandType.expectedLength);
Object dataResponse = medtronicConverter.convertResponse(commandType, response.getRawContent()); if (check == null) {
LOG.debug("Converted response for {} is {}.", commandType.name(), dataResponse); Object dataResponse = medtronicConverter.convertResponse(commandType, response.getRawContent());
return dataResponse; LOG.debug("Converted response for {} is {}.", commandType.name(), dataResponse);
} else {
this.errorMessage = check; return dataResponse;
// return null; } else {
this.errorMessage = check;
// return null;
}
} catch (RileyLinkCommunicationException e) {
LOG.warn("Error getting response from RileyLink (error={}, retry={})", e.getMessage(), retries + 1);
} }
} }
@ -809,65 +889,74 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
MedtronicCommandType commandType = MedtronicCommandType.GetBasalProfileSTD; MedtronicCommandType commandType = MedtronicCommandType.GetBasalProfileSTD;
for (int retries = 0; retries <= MAX_COMMAND_RETRIES; retries++) { for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) {
// create message try {
PumpMessage msg; // create message
PumpMessage msg;
// if (bodyData == null) // if (bodyData == null)
msg = makePumpMessage(commandType); msg = makePumpMessage(commandType);
// send and wait for response // send and wait for response
PumpMessage response = sendAndListen(msg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); PumpMessage response = null;
// LOG.debug("1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); response = sendAndListen(msg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries));
// LOG.debug("1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData()));
String check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength); // LOG.debug("1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent()));
// LOG.debug("1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData()));
byte[] data = null; String check = checkResponseContent(response, commandType.commandDescription,
commandType.expectedLength);
int runs = 1; byte[] data = null;
if (check == null) { int runs = 1;
data = response.getRawContent(); if (check == null) {
PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); data = response.getRawContent();
while (checkIfWeHaveMoreData(commandType, response, data)) { PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody());
runs++; while (checkIfWeHaveMoreData(commandType, response, data)) {
PumpMessage response2 = sendAndListen(ackMsg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); runs++;
// LOG.debug("{} Response: {}", runs, HexDump.toHexStringDisplayable(response2.getRawContent())); PumpMessage response2 = sendAndListen(ackMsg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries));
// LOG.debug("{} Response: {}", runs,
// HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData()));
String check2 = checkResponseContent(response2, commandType.commandDescription, // LOG.debug("{} Response: {}", runs,
commandType.expectedLength); // HexDump.toHexStringDisplayable(response2.getRawContent()));
// LOG.debug("{} Response: {}", runs,
// HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData()));
if (check2 == null) { String check2 = checkResponseContent(response2, commandType.commandDescription,
commandType.expectedLength);
data = ByteUtil.concat(data, ByteUtil.substring(response2.getMessageBody().getTxData(), 1)); if (check2 == null) {
} else { data = ByteUtil.concat(data, ByteUtil.substring(response2.getMessageBody().getTxData(), 1));
this.errorMessage = check;
} else {
this.errorMessage = check;
}
} }
} else {
errorMessage = check;
} }
} else { BasalProfile basalProfile = (BasalProfile)medtronicConverter.convertResponse(commandType, data);
errorMessage = check;
LOG.debug("Converted response for {} is {}.", commandType.name(), basalProfile);
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping);
return basalProfile;
} catch (RileyLinkCommunicationException e) {
LOG.warn("Error getting response from RileyLink (error={}, retry={})", e.getMessage(), retries + 1);
} }
BasalProfile basalProfile = (BasalProfile)medtronicConverter.convertResponse(commandType, data);
LOG.debug("Converted response for {} is {}.", commandType.name(), basalProfile);
MedtronicUtil.setPumpDeviceState(PumpDeviceState.Sleeping);
return basalProfile;
} }
LOG.warn("Error reading profile in max retries."); LOG.warn("Error reading profile in max retries.");
@ -933,45 +1022,46 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.info("setBolus: " + units); LOG.info("setBolus: " + units);
if (this.doWakeUpBeforeCommand) return setCommand(MedtronicCommandType.SetBolus, MedtronicUtil.getBolusStrokes(units));
wakeUp(false);
byte[] body = MedtronicUtil.getBolusStrokes(units);
if (debugSetCommands)
LOG.debug("Set Bolus: Body - {}", HexDump.toHexStringDisplayable(body));
PumpMessage msg = makePumpMessage(MedtronicCommandType.SetBolus, //
new CarelinkLongMessageBody(body));
PumpMessage pumpMessage = runCommandWithArgs(msg);
if (debugSetCommands)
LOG.debug("Set Bolus: {}", pumpMessage.getResponseContent());
return pumpMessage.commandType == MedtronicCommandType.CommandACK;
} }
public boolean setTBR(TempBasalPair tbr) { public boolean setTBR(TempBasalPair tbr) {
if (this.doWakeUpBeforeCommand) LOG.info("setTBR: " + tbr.getDescription());
wakeUp(false);
byte[] body = tbr.getAsRawData(); return setCommand(MedtronicCommandType.SetTemporaryBasal, tbr.getAsRawData());
}
if (debugSetCommands)
LOG.debug("Set TBR: Body - {}", HexDump.toHexStringDisplayable(body));
PumpMessage msg = makePumpMessage(MedtronicCommandType.SetTemporaryBasal, // private boolean setCommand(MedtronicCommandType commandType, byte[] body) {
new CarelinkLongMessageBody(tbr.getAsRawData()));
PumpMessage pumpMessage = runCommandWithArgs(msg); for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) {
if (debugSetCommands) try {
LOG.debug("Set TBR: {}", pumpMessage.getResponseContent()); if (this.doWakeUpBeforeCommand)
wakeUp(false);
return pumpMessage.commandType == MedtronicCommandType.CommandACK; if (debugSetCommands)
LOG.debug("{}: Body - {}", commandType.getCommandDescription(),
HexDump.toHexStringDisplayable(body));
PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(body));
PumpMessage pumpMessage = runCommandWithArgs(msg);
if (debugSetCommands)
LOG.debug("{}: {}", commandType.getCommandDescription(), pumpMessage.getResponseContent());
return pumpMessage.commandType == MedtronicCommandType.CommandACK;
} catch (RileyLinkCommunicationException e) {
LOG.warn("Error getting response from RileyLink (error={}, retry={})", e.getMessage(), retries + 1);
}
}
return false;
} }
@ -992,11 +1082,23 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
List<List<Byte>> basalProfileFrames = MedtronicUtil.getBasalProfileFrames(basalProfile.getRawData()); List<List<Byte>> basalProfileFrames = MedtronicUtil.getBasalProfileFrames(basalProfile.getRawData());
PumpMessage responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, basalProfileFrames); for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) {
// LOG.debug("Set Basal Profile: {}", HexDump.toHexStringDisplayable(responseMessage.getRawContent())); // PumpMessage responseMessage = null;
try {
PumpMessage responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD,
basalProfileFrames);
return responseMessage.commandType == MedtronicCommandType.CommandACK; return responseMessage.commandType == MedtronicCommandType.CommandACK;
} catch (RileyLinkCommunicationException e) {
LOG.warn("Error getting response from RileyLink (error={}, retry={})", e.getMessage(), retries + 1);
}
// LOG.debug("Set Basal Profile: {}", HexDump.toHexStringDisplayable(responseMessage.getRawContent()));
}
return false;
} }
@ -1006,33 +1108,31 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
// TODO test // TODO test
// TODO remove, we will see state from History // TODO remove, we will see state from History
public PumpMessage getPumpState() { // public PumpMessage getPumpState() {
PumpMessage response = sendAndGetResponse(MedtronicCommandType.PumpState); // PumpMessage response = sendAndGetResponse(MedtronicCommandType.PumpState);
//
byte[] data = response.getRawContent(); // byte[] data = response.getRawContent();
//
LOG.debug("Pump State: {}", HexDump.toHexStringDisplayable(data)); // LOG.debug("Pump State: {}", HexDump.toHexStringDisplayable(data));
//
// 3 TBR running ? // // 3 TBR running ?
//
return null; // return null;
} // }
// TODO remove, we will see bolus status from History // TODO remove, we will see bolus status from History
public PumpMessage getBolusStatus() { // public PumpMessage getBolusStatus() {
PumpMessage response = sendAndGetResponse(MedtronicCommandType.SetBolus, new byte[] { 0x03, 0x00, 0x00, 0x00 }, // PumpMessage response = sendAndGetResponse(MedtronicCommandType.SetBolus, new byte[] { 0x03, 0x00, 0x00, 0x00 },
4000); // 4000);
//
byte[] data = response.getRawContent(); // byte[] data = response.getRawContent();
//
LOG.debug("Detect bolus: {}", HexDump.toHexStringDisplayable(data)); // LOG.debug("Detect bolus: {}", HexDump.toHexStringDisplayable(data));
//
// 3 TBR running ? // // 3 TBR running ?
//
return null; // return null;
} // }
public PumpMessage cancelBolus() { public PumpMessage cancelBolus() {
// ? maybe suspend and resume // ? maybe suspend and resume

View file

@ -248,7 +248,7 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
return decodeDailyTotals(entry); // Not supported at the moment return decodeDailyTotals(entry); // Not supported at the moment
case SelectBasalProfile: case SelectBasalProfile:
return RecordDecodeStatus.Ignored; // Not supported at the moment return RecordDecodeStatus.OK; // Not supported at the moment
// WORK IN PROGRESS // WORK IN PROGRESS
@ -782,6 +782,10 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
int dayOfMonth = dt[0] & 0x1F; int dayOfMonth = dt[0] & 0x1F;
int year = 2000 + (ByteUtil.asUINT8(dt[1]) & 0x7F); int year = 2000 + (ByteUtil.asUINT8(dt[1]) & 0x7F);
int hour = 0;
int minutes = 0;
int seconds = 0;
// LocalDate rval = new LocalDate(year, month, dayOfMonth); // LocalDate rval = new LocalDate(year, month, dayOfMonth);
// int dayOfMonth = dt[0] & 0x1F; // int dayOfMonth = dt[0] & 0x1F;
@ -794,17 +798,22 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
if (dayOfMonth == 32) { if (dayOfMonth == 32) {
// FIXME remove // FIXME remove
LOG.debug("Entry: {} = [{}] {}", entry.getEntryType().name(), ByteUtil.getHex(entry.getRawData()), LOG.debug("Entry: Day 32 {} = [{}] {}", entry.getEntryType().name(),
entry); ByteUtil.getHex(entry.getRawData()), entry);
} }
if (entry.getEntryType() == PumpHistoryEntryType.EndResultTotals) { if (entry.getEntryType() == PumpHistoryEntryType.EndResultTotals) {
atdate = new LocalDateTime(year, month, dayOfMonth, 23, 59, 59); atdate = new LocalDateTime(year, month, dayOfMonth, 23, 59, 59);
hour = 23;
minutes = 59;
seconds = 59;
} else { } else {
atdate = new LocalDateTime(year, month, dayOfMonth, 0, 0); atdate = new LocalDateTime(year, month, dayOfMonth, 0, 0);
} }
entry.setLocalDateTime(atdate); entry.setLocalDateTime(atdate);
entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds));
} else { } else {
LOG.warn("Unknown datetime format: " + entry.getDateTimeLength()); LOG.warn("Unknown datetime format: " + entry.getDateTimeLength());
} }
@ -824,16 +833,4 @@ public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder {
return year; return year;
} }
// WRITE DATA
// private void writeData(PumpBaseType baseType, CodeEnumWithTranslation subType, ATechDate aTechDate) {
// this.pumpValuesWriter.writeObject(baseType.name() + "_" + subType.getName(), aTechDate);
// }
//
//
// private void writeData(PumpBaseType baseType, CodeEnumWithTranslation subType, String value, ATechDate aTechDate)
// {
// this.pumpValuesWriter.writeObject(baseType.name() + "_" + subType.getName(), aTechDate, value);
// }
} }

View file

@ -193,14 +193,14 @@ public class MedtronicUIPostprocessor {
checkValue = settings.get("PCFG_MAX_BOLUS"); checkValue = settings.get("PCFG_MAX_BOLUS");
if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), pumpStatus.maxBolus)) { if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), pumpStatus.maxBolus)) {
LOG.error("Wrong Max Bolus set on Pump (must be {}).", pumpStatus.maxBolus); LOG.error("Wrong Max Bolus set on Pump (current={}, required={}).", checkValue.value, pumpStatus.maxBolus);
sendNotification(MedtronicNotificationType.PumpWrongMaxBolusSet, pumpStatus.maxBolus); sendNotification(MedtronicNotificationType.PumpWrongMaxBolusSet, pumpStatus.maxBolus);
} }
checkValue = settings.get("PCFG_MAX_BASAL"); checkValue = settings.get("PCFG_MAX_BASAL");
if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), pumpStatus.maxBasal)) { if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), pumpStatus.maxBasal)) {
LOG.error("Wrong Max Basal set on Pump (must be {}).", pumpStatus.maxBasal); LOG.error("Wrong Max Basal set on Pump (current={}, required={}).", checkValue.value, pumpStatus.maxBasal);
sendNotification(MedtronicNotificationType.PumpWrongMaxBasalSet, pumpStatus.maxBasal); sendNotification(MedtronicNotificationType.PumpWrongMaxBasalSet, pumpStatus.maxBasal);
} }

View file

@ -88,11 +88,11 @@ public class MedtronicUITask {
} }
break; break;
case PumpState: { // case PumpState: {
// TODO maybe remove this, data returned is almost useless // // TODO maybe remove this, data returned is almost useless
returnData = communicationManager.getPumpState(); // returnData = communicationManager.getPumpState();
} // }
break; // break;
// case "RefreshData.GetBolus": { // case "RefreshData.GetBolus": {
// returnData = communicationManager.getBolusStatus(); // returnData = communicationManager.getBolusStatus();

View file

@ -109,6 +109,7 @@ public class MedtronicHistoryData {
} }
// FIXME not just 50 records, last 24 hours
public void finalizeNewHistoryRecords() { public void finalizeNewHistoryRecords() {
List<PumpHistoryEntry> filteredListByLastRecord = getFilteredListByLastRecord((PumpHistoryEntryType)null); List<PumpHistoryEntry> filteredListByLastRecord = getFilteredListByLastRecord((PumpHistoryEntryType)null);
@ -151,6 +152,13 @@ public class MedtronicHistoryData {
// TODO This logic might not be working correctly // TODO This logic might not be working correctly
public boolean isPumpSuspended(Boolean wasPumpSuspended) { public boolean isPumpSuspended(Boolean wasPumpSuspended) {
if (true)
return false;
List<PumpHistoryEntry> newAndAll = new ArrayList<>();
newAndAll.addAll(this.allHistory);
newAndAll.addAll(this.newHistory);
if (wasPumpSuspended == null) { // suspension status not known if (wasPumpSuspended == null) { // suspension status not known
List<PumpHistoryEntry> items = getFilteredItems(PumpHistoryEntryType.Bolus, // List<PumpHistoryEntry> items = getFilteredItems(PumpHistoryEntryType.Bolus, //
@ -200,6 +208,9 @@ public class MedtronicHistoryData {
} else { } else {
if (items.size() == 0)
return wasPumpSuspended == null ? false : wasPumpSuspended;
PumpHistoryEntry pumpHistoryEntry = items.get(0); PumpHistoryEntry pumpHistoryEntry = items.get(0);
if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.NoDeliveryAlarm || // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.NoDeliveryAlarm || //

View file

@ -115,6 +115,61 @@ public class DailyTotalsDTO {
private void decodeData523(byte[] data) { private void decodeData523(byte[] data) {
LOG.debug("Can't decode DailyTotals523: Body={}", ByteUtil.getHex(data)); LOG.debug("Can't decode DailyTotals523: Body={}", ByteUtil.getHex(data));
// 0x6E 0xB1 0x92
// 0x05 0x00 0x80 0x00 0x00 0x01 0x00 0x00 0x00 0x9A 0x00 0x50 0x34 0x00 0x4A 0x30 0x00 0x0B 0x00
// 0x24 0x00 0x00 0x00 0x00 0x00 0x26 0x01 0x00 0x00 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x05 0x00 0x80 0x00 0x00 0x01 0x00 0x00 0x00 0x9A 0x00 0x50 0x34 0x00 0x4A 0x30 0x00 0x0B 0x00
// 0x24 0x00 0x00 0x00 0x00 0x00 0x26 0x01 0x00 0x00
// 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 19:31:40.314 [Thread-47]
// D/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.decodeDailyTotals():447]: PumpHistoryRecord [type=DailyTotals523 [110, 0x6E],
// DT: 16.11.2018 00:00:00, length=1,2,49(52), data={Raw Data=0x6E 0xB0 0x92 0x05 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x00 0x55 0x00 0x55 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}]
// 19:31:40.318 [Thread-47] D/info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.DailyTotalsDTO:
// [DailyTotalsDTO.decodeData523():117]: Can't decode DailyTotals523: Body=0x05 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x00 0x55 0x00 0x55 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 19:31:40.320 [Thread-47]
// W/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.createRecords():181]: #0 WIP PumpHistoryRecord [type=DailyTotals523 [110, 0x6E],
// DT: 16.11.2018 00:00:00, length=1,2,49(52), data={Raw Data=0x6E 0xB0 0x92 0x05 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x00 0x55 0x00 0x55 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}]
// 19:31:40.341 [Thread-47]
// D/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.decodeDateTime():793]: DT: 2018 11 17
// 19:31:40.342 [Thread-47]
// D/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.decodeDateTime():793]: DT: 2018 11 17
// 19:31:40.342 [Thread-47]
// D/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.decodeDailyTotals():446]: DailyTotals523 - 0x6E 0xB1 0x92 0x05 0x00 0x80 0x00
// 0x00 0x01 0x00 0x00 0x00 0x9A 0x00 0x50 0x34 0x00 0x4A 0x30 0x00 0x0B 0x00 0x24 0x00 0x00 0x00 0x00 0x00 0x26
// 0x01 0x00 0x00 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00
// 19:31:40.343 [Thread-47]
// D/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.decodeDailyTotals():447]: PumpHistoryRecord [type=DailyTotals523 [110, 0x6E],
// DT: 17.11.2018 00:00:00, length=1,2,49(52), data={Raw Data=0x6E 0xB1 0x92 0x05 0x00 0x80 0x00 0x00 0x01 0x00
// 0x00 0x00 0x9A 0x00 0x50 0x34 0x00 0x4A 0x30 0x00 0x0B 0x00 0x24 0x00 0x00 0x00 0x00 0x00 0x26 0x01 0x00 0x00
// 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}]
// 19:31:40.343 [Thread-47] D/info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.DailyTotalsDTO:
// [DailyTotalsDTO.decodeData523():117]: Can't decode DailyTotals523: Body=0x05 0x00 0x80 0x00 0x00 0x01 0x00
// 0x00 0x00 0x9A 0x00 0x50 0x34 0x00 0x4A 0x30 0x00 0x0B 0x00 0x24 0x00 0x00 0x00 0x00 0x00 0x26 0x01 0x00 0x00
// 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 19:31:40.344 [Thread-47]
// W/info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.MedtronicPumpHistoryDecoder:
// [MedtronicPumpHistoryDecoder.createRecords():181]: #60 WIP PumpHistoryRecord [type=DailyTotals523 [110,
// 0x6E], DT: 17.11.2018 00:00:00, length=1,2,49(52), data={Raw Data=0x6E 0xB1 0x92 0x05 0x00 0x80 0x00 0x00
// 0x01 0x00 0x00 0x00 0x9A 0x00 0x50 0x34 0x00 0x4A 0x30 0x00 0x0B 0x00 0x24 0x00 0x00 0x00 0x00 0x00 0x26 0x01
// 0x00 0x00 0x05 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x00
// 0x00}]
} }

View file

@ -142,6 +142,22 @@ public class TempBasalPair {
} }
public String getDescription() {
String desc = "";
if (isPercent) {
desc = "Rate=" + insulinRate + "%";
} else {
desc = "Rate=" + insulinRate + " U";
}
desc += ", Duration=" + durationMinutes + " min";
return desc;
}
@Override @Override
public String toString() { public String toString() {
return "TempBasalPair [" + "Rate=" + insulinRate + ", DurationMinutes=" + durationMinutes + ", IsPercent=" return "TempBasalPair [" + "Rate=" + insulinRate + ", DurationMinutes=" + durationMinutes + ", IsPercent="

View file

@ -43,10 +43,10 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
PushButton(0x5b, "Push Button", MinimedTargetType.ActionCommand, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // 91 PushButton(0x5b, "Push Button", MinimedTargetType.ActionCommand, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // 91
RFPowerOn(93, "RF Power On", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray( RFPowerOn(93, "RF Power On", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(
1, 10)), // 1, 10)), //
RFPowerOff(93, "RF Power Off", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray( RFPowerOff(93, "RF Power Off", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(
0, 0)), // 0, 0)), //
SetSuspend(77, "Set Suspend", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(1)), // SetSuspend(77, "Set Suspend", MinimedTargetType.InitCommand, MedtronicDeviceType.All, MinimedCommandParameterType.FixedParameters, getByteArray(1)), //
@ -58,7 +58,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
// 511 (InitCommand = 2, Config 7, Data = 1(+3) // 511 (InitCommand = 2, Config 7, Data = 1(+3)
DetectBolus(75, "Detect Bolus", MinimedTargetType.InitCommand, MedtronicDeviceType.Medtronic_511, MinimedCommandParameterType.FixedParameters, getByteArray( DetectBolus(75, "Detect Bolus", MinimedTargetType.InitCommand, MedtronicDeviceType.Medtronic_511, MinimedCommandParameterType.FixedParameters, getByteArray(
0, 0, 0)), // 0, 0, 0)), //
RemoteControlIds(118, "Remote Control Ids", MinimedTargetType.PumpConfiguration_NA, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), // RemoteControlIds(118, "Remote Control Ids", MinimedTargetType.PumpConfiguration_NA, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), //
@ -79,7 +79,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
ReadTemporaryBasal(0x98, "Read Temporary Basal", MinimedTargetType.InitCommand, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 5), // 152 ReadTemporaryBasal(0x98, "Read Temporary Basal", MinimedTargetType.InitCommand, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 5), // 152
SetTemporaryBasal(76, "Set Temp Basal Rate (bolus detection only)", MinimedTargetType.InitCommand, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, getByteArray( SetTemporaryBasal(76, "Set Temp Basal Rate (bolus detection only)", MinimedTargetType.InitCommand, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, getByteArray(
0, 0, 0)), 0, 0, 0)),
// util.getCommand(MinimedCommand.SET_TEMPORARY_BASAL).allowedRetries // util.getCommand(MinimedCommand.SET_TEMPORARY_BASAL).allowedRetries
// = 0; // = 0;
@ -109,10 +109,10 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
GetBasalProfileSTD(146, "Get Profile Standard", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 8, 1), // 146 GetBasalProfileSTD(146, "Get Profile Standard", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 8, 1), // 146
GetBasalProfileA(147, "Get Profile A", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 9), // 147 GetBasalProfileA(147, "Get Profile A", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 9), // 147
// FIXME // FIXME
GetBasalProfileB(148, "Get Profile B", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 10), // 148 GetBasalProfileB(148, "Get Profile B", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 10), // 148
// FIXME // FIXME
SetBasalProfileSTD(0x6f, "Set Profile Standard", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 8), // 111 SetBasalProfileSTD(0x6f, "Set Profile Standard", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.Medtronic_512andHigher, MinimedCommandParameterType.NoParameters, 192, 1, 8), // 111
@ -154,7 +154,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
// Fake Commands // Fake Commands
CancelTBR(), ; CancelTBR(),;
static Map<Byte, MedtronicCommandType> mapByCode; static Map<Byte, MedtronicCommandType> mapByCode;
@ -176,6 +176,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
public byte[] commandParameters = null; public byte[] commandParameters = null;
public int commandParametersCount = 0; public int commandParametersCount = 0;
public int maxRecords = 1; public int maxRecords = 1;
private Integer resourceId;
public int command_type = 0; public int command_type = 0;
public int allowedRetries = 2; public int allowedRetries = 2;
public int maxAllowedTime = 2000; public int maxAllowedTime = 2000;
@ -193,33 +194,33 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType) { MinimedCommandParameterType parameterType) {
this(code, description, targetType, devices, parameterType, 64, 1, 0, 0, 0, 0); this(code, description, targetType, devices, parameterType, 64, 1, 0, 0, 0, 0);
} }
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType, int expectedLength) { MinimedCommandParameterType parameterType, int expectedLength) {
this(code, description, targetType, devices, parameterType, 64, 1, 0, 0, 0, expectedLength); this(code, description, targetType, devices, parameterType, 64, 1, 0, 0, 0, expectedLength);
} }
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType) { MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType) {
this(code, description, targetType, devices, parameterType, recordLength, maxRecords, 0, 0, commandType, 0); this(code, description, targetType, devices, parameterType, recordLength, maxRecords, 0, 0, commandType, 0);
} }
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType, MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType,
int expectedLength) { int expectedLength) {
this(code, description, targetType, devices, parameterType, recordLength, maxRecords, 0, 0, commandType, this(code, description, targetType, devices, parameterType, recordLength, maxRecords, 0, 0, commandType,
expectedLength); expectedLength);
} }
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType, byte[] cmd_params) { MinimedCommandParameterType parameterType, byte[] cmd_params) {
this(code, description, targetType, devices, parameterType, 0, 1, 0, 0, 11, 0); this(code, description, targetType, devices, parameterType, 0, 1, 0, 0, 11, 0);
this.commandParameters = cmd_params; this.commandParameters = cmd_params;
@ -228,7 +229,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType, byte[] cmd_params, int expectedLength) { MinimedCommandParameterType parameterType, byte[] cmd_params, int expectedLength) {
this(code, description, targetType, devices, parameterType, 0, 1, 0, 0, 11, expectedLength); this(code, description, targetType, devices, parameterType, 0, 1, 0, 0, 11, expectedLength);
this.commandParameters = cmd_params; this.commandParameters = cmd_params;
@ -237,7 +238,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // MedtronicCommandType(int code, String description, MedtronicDeviceType devices, //
MinimedCommandParameterType parameterType) { MinimedCommandParameterType parameterType) {
this(code, description, devices, parameterType, 64, 1, 0, null); this(code, description, devices, parameterType, 64, 1, 0, null);
} }
@ -245,35 +246,36 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
// NEW // NEW
MedtronicCommandType(int code, String description, MedtronicDeviceType devices, MedtronicCommandType(int code, String description, MedtronicDeviceType devices,
MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType) { MinimedCommandParameterType parameterType, int recordLength, int maxRecords, int commandType) {
this(code, description, devices, parameterType, recordLength, maxRecords, 0, null); this(code, description, devices, parameterType, recordLength, maxRecords, 0, null);
} }
// NEW // NEW
MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // MedtronicCommandType(int code, String description, MedtronicDeviceType devices, //
MinimedCommandParameterType parameterType, int expectedLength) { MinimedCommandParameterType parameterType, int expectedLength) {
this(code, description, devices, parameterType, 64, 1, expectedLength, null); this(code, description, devices, parameterType, 64, 1, expectedLength, null);
} }
// NEW // NEW
MedtronicCommandType(int code, String description, MedtronicDeviceType devices, // MedtronicCommandType(int code, String description, MedtronicDeviceType devices, //
MinimedCommandParameterType parameterType, int expectedLength, int resourceId) { MinimedCommandParameterType parameterType, int expectedLength, int resourceId) {
this(code, description, devices, parameterType, 64, 1, expectedLength, resourceId); this(code, description, devices, parameterType, 64, 1, expectedLength, resourceId);
} }
// NEW // NEW
MedtronicCommandType(int code, String description, MedtronicCommandType(int code, String description,
MedtronicDeviceType devices, // MedtronicDeviceType devices, //
MinimedCommandParameterType parameterType, int recordLength, int max_recs, int expectedLength, MinimedCommandParameterType parameterType, int recordLength, int max_recs, int expectedLength,
Integer resourceId) { Integer resourceId) {
this.commandCode = (byte)code; this.commandCode = (byte) code;
this.commandDescription = description; this.commandDescription = description;
this.devices = devices; this.devices = devices;
this.recordLength = recordLength; this.recordLength = recordLength;
this.maxRecords = max_recs; this.maxRecords = max_recs;
this.resourceId = resourceId;
this.commandParametersCount = 0; this.commandParametersCount = 0;
this.allowedRetries = 2; this.allowedRetries = 2;
@ -289,9 +291,9 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
@Deprecated @Deprecated
MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, // MedtronicCommandType(int code, String description, MinimedTargetType targetType, MedtronicDeviceType devices, //
MinimedCommandParameterType parameterType, int recordLength, int max_recs, int addy, // MinimedCommandParameterType parameterType, int recordLength, int max_recs, int addy, //
int addy_len, int cmd_type, int expectedLength) { int addy_len, int cmd_type, int expectedLength) {
this.commandCode = (byte)code; this.commandCode = (byte) code;
this.commandDescription = description; this.commandDescription = description;
this.targetType = targetType; this.targetType = targetType;
this.devices = devices; this.devices = devices;
@ -326,7 +328,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
byte[] array = new byte[data.length]; byte[] array = new byte[data.length];
for (int i = 0; i < data.length; i++) { for (int i = 0; i < data.length; i++) {
array[i] = (byte)data[i]; array[i] = (byte) data[i];
} }
return array; return array;
@ -398,7 +400,7 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
*/ */
public String getFullCommandDescription() { public String getFullCommandDescription() {
return "Command [name=" + this.name() + ", id=" + this.commandCode + ",description=" + this.commandDescription return "Command [name=" + this.name() + ", id=" + this.commandCode + ",description=" + this.commandDescription
+ "] "; + "] ";
} }
@ -446,6 +448,15 @@ public enum MedtronicCommandType implements Serializable // , MinimedCommandType
return name(); return name();
} }
public String getCommandDescription() {
return this.commandDescription;
}
public Integer getResourceId() {
return resourceId;
}
public enum MinimedCommandParameterType { public enum MinimedCommandParameterType {
NoParameters, // NoParameters, //
FixedParameters, // FixedParameters, //

View file

@ -124,7 +124,7 @@ public class MedtronicPumpStatus extends PumpStatus {
medtronicPumpMap.put("754", PumpType.Medtronic_554_754_Veo); medtronicPumpMap.put("754", PumpType.Medtronic_554_754_Veo);
frequencies = new String[2]; frequencies = new String[2];
frequencies[0] = MainApp.gs(R.string.medtronic_pump_frequency_us); frequencies[0] = MainApp.gs(R.string.medtronic_pump_frequency_us_ca);
frequencies[1] = MainApp.gs(R.string.medtronic_pump_frequency_worldwide); frequencies[1] = MainApp.gs(R.string.medtronic_pump_frequency_worldwide);
} }
@ -139,6 +139,8 @@ public class MedtronicPumpStatus extends PumpStatus {
if (this.medtronicDeviceTypeMap == null) if (this.medtronicDeviceTypeMap == null)
createMedtronicDeviceTypeMap(); createMedtronicDeviceTypeMap();
this.errorDescription = "-";
String serialNr = SP.getString(MedtronicConst.Prefs.PumpSerial, null); String serialNr = SP.getString(MedtronicConst.Prefs.PumpSerial, null);
if (serialNr == null) { if (serialNr == null) {
@ -188,6 +190,7 @@ public class MedtronicPumpStatus extends PumpStatus {
this.errorDescription = MainApp.gs(R.string.medtronic_error_pump_frequency_invalid); this.errorDescription = MainApp.gs(R.string.medtronic_error_pump_frequency_invalid);
return; return;
} else { } else {
// if (this.pumpFrequency == null || !this.pumpFrequency.equals(pumpFrequency))
this.pumpFrequency = pumpFrequency; this.pumpFrequency = pumpFrequency;
this.isFrequencyUS = pumpFrequency.equals(frequencies[0]); this.isFrequencyUS = pumpFrequency.equals(frequencies[0]);
@ -195,9 +198,10 @@ public class MedtronicPumpStatus extends PumpStatus {
RileyLinkTargetFrequency.Medtronic_US RileyLinkTargetFrequency.Medtronic_US
: RileyLinkTargetFrequency.Medtronic_WorldWide; : RileyLinkTargetFrequency.Medtronic_WorldWide;
if (targetFrequency == newTargetFrequency) { if (targetFrequency != newTargetFrequency) {
RileyLinkUtil.setRileyLinkTargetFrequency(newTargetFrequency); RileyLinkUtil.setRileyLinkTargetFrequency(newTargetFrequency);
targetFrequencyChanged = true; targetFrequency = newTargetFrequency;
// targetFrequencyChanged = true;
} }
} }
@ -206,11 +210,13 @@ public class MedtronicPumpStatus extends PumpStatus {
String rileyLinkAddress = SP.getString(RileyLinkConst.Prefs.RileyLinkAddress, null); String rileyLinkAddress = SP.getString(RileyLinkConst.Prefs.RileyLinkAddress, null);
if (rileyLinkAddress == null) { if (rileyLinkAddress == null) {
LOG.debug("RileyLink address invalid: null");
this.errorDescription = MainApp.gs(R.string.medtronic_error_rileylink_address_invalid); this.errorDescription = MainApp.gs(R.string.medtronic_error_rileylink_address_invalid);
return; return;
} else { } else {
if (!rileyLinkAddress.matches(regexMac)) { if (!rileyLinkAddress.matches(regexMac)) {
this.errorDescription = MainApp.gs(R.string.medtronic_error_rileylink_address_invalid); this.errorDescription = MainApp.gs(R.string.medtronic_error_rileylink_address_invalid);
LOG.debug("RileyLink address invalid: {}", rileyLinkAddress);
} else { } else {
if (!rileyLinkAddress.equals(this.rileyLinkAddress)) { if (!rileyLinkAddress.equals(this.rileyLinkAddress)) {
this.rileyLinkAddress = rileyLinkAddress; this.rileyLinkAddress = rileyLinkAddress;
@ -248,13 +254,13 @@ public class MedtronicPumpStatus extends PumpStatus {
rileyLinkAddressChanged = false; rileyLinkAddressChanged = false;
} }
if (targetFrequencyChanged && !inPreInit && MedtronicUtil.getMedtronicService() != null) { // if (targetFrequencyChanged && !inPreInit && MedtronicUtil.getMedtronicService() != null) {
RileyLinkUtil.setRileyLinkTargetFrequency(targetFrequency); // RileyLinkUtil.setRileyLinkTargetFrequency(targetFrequency);
RileyLinkUtil.getRileyLinkCommunicationManager().refreshRileyLinkTargetFrequency(); // // RileyLinkUtil.getRileyLinkCommunicationManager().refreshRileyLinkTargetFrequency();
targetFrequencyChanged = false; // targetFrequencyChanged = false;
} // }
return (!rileyLinkAddressChanged && !serialChanged && !targetFrequencyChanged); return (!rileyLinkAddressChanged && !serialChanged); // && !targetFrequencyChanged);
} }
@ -271,7 +277,7 @@ public class MedtronicPumpStatus extends PumpStatus {
} }
if (val > defaultValueDouble) { if (val > defaultValueDouble) {
SP.putString(MedtronicConst.Prefs.MaxBolus, defaultValue); SP.putString(key, defaultValue);
val = defaultValueDouble; val = defaultValueDouble;
} }

View file

@ -10,14 +10,12 @@ import android.os.Binder;
import android.os.IBinder; import android.os.IBinder;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil; 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.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkBLE; 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.RileyLinkEncodingType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState; 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.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkService; import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkService;
@ -86,15 +84,16 @@ public class RileyLinkMedtronicService extends RileyLinkService {
} }
// FIXME remove this, it needs to be set in PumpConfiguration not here
@Override @Override
protected void determineRileyLinkTargetFrequency() { protected void determineRileyLinkTargetFrequency() {
boolean hasUSFrequency = SP.getString(MedtronicConst.Prefs.PumpFrequency, // boolean hasUSFrequency = SP.getString(MedtronicConst.Prefs.PumpFrequency,
MainApp.gs(R.string.medtronic_pump_frequency_us)).equals(MainApp.gs(R.string.medtronic_pump_frequency_us)); // MainApp.gs(R.string.medtronic_pump_frequency_us)).equals(MainApp.gs(R.string.medtronic_pump_frequency_us));
//
if (hasUSFrequency) // if (hasUSFrequency)
RileyLinkUtil.setRileyLinkTargetFrequency(RileyLinkTargetFrequency.Medtronic_US); // RileyLinkUtil.setRileyLinkTargetFrequency(RileyLinkTargetFrequency.Medtronic_US);
else // else
RileyLinkUtil.setRileyLinkTargetFrequency(RileyLinkTargetFrequency.Medtronic_WorldWide); // RileyLinkUtil.setRileyLinkTargetFrequency(RileyLinkTargetFrequency.Medtronic_WorldWide);
} }

View file

@ -1,15 +1,15 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.util; package info.nightscout.androidaps.plugins.PumpMedtronic.util;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.ByteOrder; import java.nio.ByteOrder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.joda.time.LocalTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.Overview.events.EventDismissNotification;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
@ -71,8 +71,8 @@ public class MedtronicUtil extends RileyLinkUtil {
public static byte[] getByteArrayFromUnsignedShort(int shortValue, boolean returnFixedSize) { public static byte[] getByteArrayFromUnsignedShort(int shortValue, boolean returnFixedSize) {
byte highByte = (byte)(shortValue >> 8 & 0xFF); byte highByte = (byte) (shortValue >> 8 & 0xFF);
byte lowByte = (byte)(shortValue & 0xFF); byte lowByte = (byte) (shortValue & 0xFF);
if (highByte > 0) { if (highByte > 0) {
return createByteArray(highByte, lowByte); return createByteArray(highByte, lowByte);
@ -106,7 +106,7 @@ public class MedtronicUtil extends RileyLinkUtil {
public static double decodeBasalInsulin(int i) { public static double decodeBasalInsulin(int i) {
return (double)i / 40.0d; return (double) i / 40.0d;
} }
@ -149,7 +149,7 @@ public class MedtronicUtil extends RileyLinkUtil {
scrollRate = 1; scrollRate = 1;
} }
int strokes = (int)(amount * ((strokesPerUnit * 1.0d) / (scrollRate * 1.0d))) * scrollRate; int strokes = (int) (amount * ((strokesPerUnit * 1.0d) / (scrollRate * 1.0d))) * scrollRate;
byte[] body = ByteUtil.fromHexString(String.format("%02x%0" + (2 * length) + "x", length, strokes)); byte[] body = ByteUtil.fromHexString(String.format("%02x%0" + (2 * length) + "x", length, strokes));
@ -159,7 +159,7 @@ public class MedtronicUtil extends RileyLinkUtil {
public static byte[] createCommandBody(byte[] input) { public static byte[] createCommandBody(byte[] input) {
return ByteUtil.concat((byte)input.length, input); return ByteUtil.concat((byte) input.length, input);
} }
@ -187,7 +187,7 @@ public class MedtronicUtil extends RileyLinkUtil {
scrollRate = 2; scrollRate = 2;
} }
int strokes = (int)(amount * (strokesPerUnit / (scrollRate * 1.0d))); int strokes = (int) (amount * (strokesPerUnit / (scrollRate * 1.0d)));
strokes *= scrollRate; strokes *= scrollRate;
@ -198,18 +198,18 @@ public class MedtronicUtil extends RileyLinkUtil {
public static void sendNotification(MedtronicNotificationType notificationType) { public static void sendNotification(MedtronicNotificationType notificationType) {
Notification notification = new Notification( // Notification notification = new Notification( //
notificationType.getNotificationType(), // notificationType.getNotificationType(), //
MainApp.gs(notificationType.getResourceId()), // MainApp.gs(notificationType.getResourceId()), //
notificationType.getNotificationUrgency()); notificationType.getNotificationUrgency());
MainApp.bus().post(new EventNewNotification(notification)); MainApp.bus().post(new EventNewNotification(notification));
} }
public static void sendNotification(MedtronicNotificationType notificationType, Object... parameters) { public static void sendNotification(MedtronicNotificationType notificationType, Object... parameters) {
Notification notification = new Notification( // Notification notification = new Notification( //
notificationType.getNotificationType(), // notificationType.getNotificationType(), //
MainApp.gs(notificationType.getResourceId(), parameters), // MainApp.gs(notificationType.getResourceId(), parameters), //
notificationType.getNotificationUrgency()); notificationType.getNotificationUrgency());
MainApp.bus().post(new EventNewNotification(notification)); MainApp.bus().post(new EventNewNotification(notification));
} }
@ -225,21 +225,21 @@ public class MedtronicUtil extends RileyLinkUtil {
public static byte[] buildCommandPayload(MedtronicCommandType commandType, byte[] parameters) { public static byte[] buildCommandPayload(MedtronicCommandType commandType, byte[] parameters) {
return buildCommandPayload((byte)commandType.commandCode, parameters); return buildCommandPayload((byte) commandType.commandCode, parameters);
} }
public static byte[] buildCommandPayload(byte commandType, byte[] parameters) { public static byte[] buildCommandPayload(byte commandType, byte[] parameters) {
// A7 31 65 51 C0 00 52 // A7 31 65 51 C0 00 52
byte commandLength = (byte)(parameters == null ? 2 : 2 + parameters.length); byte commandLength = (byte) (parameters == null ? 2 : 2 + parameters.length);
ByteBuffer sendPayloadBuffer = ByteBuffer.allocate(ENVELOPE_SIZE + commandLength); // + CRC_SIZE ByteBuffer sendPayloadBuffer = ByteBuffer.allocate(ENVELOPE_SIZE + commandLength); // + CRC_SIZE
sendPayloadBuffer.order(ByteOrder.BIG_ENDIAN); sendPayloadBuffer.order(ByteOrder.BIG_ENDIAN);
byte[] serialNumberBCD = RileyLinkUtil.getRileyLinkServiceData().pumpIDBytes; byte[] serialNumberBCD = RileyLinkUtil.getRileyLinkServiceData().pumpIDBytes;
sendPayloadBuffer.put((byte)0xA7); sendPayloadBuffer.put((byte) 0xA7);
sendPayloadBuffer.put(serialNumberBCD[0]); sendPayloadBuffer.put(serialNumberBCD[0]);
sendPayloadBuffer.put(serialNumberBCD[1]); sendPayloadBuffer.put(serialNumberBCD[1]);
sendPayloadBuffer.put(serialNumberBCD[2]); sendPayloadBuffer.put(serialNumberBCD[2]);
@ -247,9 +247,9 @@ public class MedtronicUtil extends RileyLinkUtil {
sendPayloadBuffer.put(commandType); sendPayloadBuffer.put(commandType);
if (parameters == null) { if (parameters == null) {
sendPayloadBuffer.put((byte)0x00); sendPayloadBuffer.put((byte) 0x00);
} else { } else {
sendPayloadBuffer.put((byte)parameters.length); // size sendPayloadBuffer.put((byte) parameters.length); // size
for (byte val : parameters) { for (byte val : parameters) {
sendPayloadBuffer.put(val); sendPayloadBuffer.put(val);
@ -298,7 +298,7 @@ public class MedtronicUtil extends RileyLinkUtil {
List<Byte> frameData = ByteUtil.getListFromByteArray(substring); List<Byte> frameData = ByteUtil.getListFromByteArray(substring);
if (isEmptyFrame(frameData)) { if (isEmptyFrame(frameData)) {
byte b = (byte)frame; byte b = (byte) frame;
// b |= 0x80; // b |= 0x80;
b |= 0b1000_0000; b |= 0b1000_0000;
// b |= doneBit; // b |= doneBit;
@ -311,7 +311,7 @@ public class MedtronicUtil extends RileyLinkUtil {
done = true; done = true;
} else { } else {
frameData.add(0, (byte)frame); frameData.add(0, (byte) frame);
} }
// System.out.println("Subarray: " + ByteUtil.getCompactString(substring)); // System.out.println("Subarray: " + ByteUtil.getCompactString(substring));
@ -330,7 +330,7 @@ public class MedtronicUtil extends RileyLinkUtil {
if (!lastFrame) { if (!lastFrame) {
List<Byte> frameData = new ArrayList<>(); List<Byte> frameData = new ArrayList<>();
byte b = (byte)frame; byte b = (byte) frame;
b |= 0b1000_0000; b |= 0b1000_0000;
// b |= doneBit; // b |= doneBit;
@ -352,7 +352,7 @@ public class MedtronicUtil extends RileyLinkUtil {
int missing = BIG_FRAME_LENGTH - frameData.size(); int missing = BIG_FRAME_LENGTH - frameData.size();
for (int i = 0; i < missing; i++) { for (int i = 0; i < missing; i++) {
frameData.add((byte)0x00); frameData.add((byte) 0x00);
} }
} }
@ -411,7 +411,7 @@ public class MedtronicUtil extends RileyLinkUtil {
public static MedtronicCommunicationManager getMedtronicCommunicationManager() { public static MedtronicCommunicationManager getMedtronicCommunicationManager() {
return (MedtronicCommunicationManager)RileyLinkUtil.rileyLinkCommunicationManager; return (MedtronicCommunicationManager) RileyLinkUtil.rileyLinkCommunicationManager;
} }
@ -448,6 +448,20 @@ public class MedtronicUtil extends RileyLinkUtil {
} }
public static int pageNumber;
public static int frameNumber;
public static void setCurrentCommand(MedtronicCommandType currentCommand, int pageNumber_, int frameNumber_) {
pageNumber = pageNumber_;
frameNumber = frameNumber_;
if (MedtronicUtil.currentCommand != currentCommand) {
setCurrentCommand(currentCommand);
}
MainApp.bus().post(new EventMedtronicDeviceStatusChange(pumpDeviceState));
}
public static boolean isSame(Double d1, Double d2) { public static boolean isSame(Double d1, Double d2) {
double diff = d1 - d2; double diff = d1 - d2;

View file

@ -158,7 +158,7 @@
</string-array> </string-array>
<string-array name="medtronicPumpFreqArray"> <string-array name="medtronicPumpFreqArray">
<item>@string/medtronic_pump_frequency_us</item> <item>@string/medtronic_pump_frequency_us_ca</item>
<item>@string/medtronic_pump_frequency_worldwide</item> <item>@string/medtronic_pump_frequency_worldwide</item>
</string-array> </string-array>

View file

@ -1231,7 +1231,7 @@
<string name="medtronic_pump_frequency">Pump Frequency</string> <string name="medtronic_pump_frequency">Pump Frequency</string>
<string name="medtronic_pump_max_bolus">Max Bolus on Pump</string> <string name="medtronic_pump_max_bolus">Max Bolus on Pump</string>
<string name="medtronic_pump_max_basal">Max Basal on Pump</string> <string name="medtronic_pump_max_basal">Max Basal on Pump</string>
<string name="medtronic_pump_frequency_us">US (916 MHz)</string> <string name="medtronic_pump_frequency_us_ca">US &amp; Canada (916 MHz)</string>
<string name="medtronic_pump_frequency_worldwide">Worldwide (868 Mhz)</string> <string name="medtronic_pump_frequency_worldwide">Worldwide (868 Mhz)</string>
<string name="rileylink_mac_address">RileyLink MAC Address</string> <string name="rileylink_mac_address">RileyLink MAC Address</string>
<string name="rileylink_scanner_selected_device">Selected</string> <string name="rileylink_scanner_selected_device">Selected</string>
@ -1317,8 +1317,12 @@
<!-- <string name="medtronic_cmd_profile_not_set">Remote Basal profile setting is not supported. Please modify Basal profile on your pump manually.</string> --> <!-- <string name="medtronic_cmd_profile_not_set">Remote Basal profile setting is not supported. Please modify Basal profile on your pump manually.</string> -->
<string name="medtronic_cmd_cancel_bolus_not_supported">Remote cancel of Bolus is not supported. If you wish to cancel bolus, go to pump put it in suspend and then resume. This will cancel the bolus.</string> <string name="medtronic_cmd_cancel_bolus_not_supported">Remote cancel of Bolus is not supported. If you wish to cancel bolus, go to pump put it in suspend and then resume. This will cancel the bolus.</string>
<string name="medtronic_cmd_cant_read_tbr">Could not read current TBR.</string> <string name="medtronic_cmd_cant_read_tbr">Could not read current TBR.</string>
<string name="medtronic_cmd_cant_cancel_tbr">Could not cancel current TBR. Stopping operation.</string> <string name="medtronic_cmd_cant_cancel_tbr_stop_op">Could not cancel current TBR. Stopping operation.</string>
<string name="medtronic_cmd_set_profile_pattern_overflow">Profile set failed, because following patterns, have too big basal rate: %1$s</string> <string name="medtronic_cmd_set_profile_pattern_overflow">Profile set failed, because following patterns, have too big basal rate: %1$s</string>
<string name="medtronic_cmd_bolus_could_not_be_delivered">Bolus could not be delivered.</string>
<string name="medtronic_cmd_tbr_could_not_be_delivered">TBR could not be set.</string>
<string name="medtronic_cmd_cant_cancel_tbr">Could not cancel current TBR.</string>
<string name="medtronic_cmd_basal_profile_could_not_be_set">Basal profile could not be set.</string>
<string name="pump_no_connection_h">No connection for %1$d hour(s) %2$d min</string> <string name="pump_no_connection_h">No connection for %1$d hour(s) %2$d min</string>

View file

@ -0,0 +1,345 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import android.util.Log;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
/**
* Created by andy on 11/21/18.
*/
@RunWith(Parameterized.class)
public class RFToolsParametrizedUTest {
private static final String TAG = "RFToolsUTest";
@Parameterized.Parameters
public static Collection<Object[]> data() {
return Arrays
.asList(new Object[][] { //
{ ByteUtil.createByteArrayFromCompactString("00"), ByteUtil.createByteArrayFromCompactString("5555") },
//
{
ByteUtil.createByteArrayFromCompactString("0000"),
ByteUtil.createByteArrayFromCompactString("555555") }, //
{
ByteUtil.createByteArrayFromCompactString("A71289865D00BE"),
ByteUtil.createByteArrayFromCompactString("A96C726996A694D5552CE5") }, //
{
ByteUtil.createByteArrayFromCompactString("A7128986060015"),
ByteUtil.createByteArrayFromCompactString("A96C726996A6566555C655") }, //
{
ByteUtil.createByteArrayFromCompactString("A7128986150956"),
ByteUtil.createByteArrayFromCompactString("A96C726996A6C655599665") }, //
{
ByteUtil.createByteArrayFromCompactString("A71289868D00B0"),
ByteUtil.createByteArrayFromCompactString("A96C726996A668D5552D55") }, //
{
ByteUtil
.createByteArrayFromCompactString("A71289868D090337323200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000039"),
ByteUtil
.createByteArrayFromCompactString("A96C726996A668D5595638D68F28F25555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555558D95")
//
}, //
});
}
@Parameterized.Parameter
// first data value (0) is default
public/* NOT private */byte[] decoded;
@Parameterized.Parameter(1)
public/* NOT private */byte[] encoded;
// @Test
public void testEncodeGeoff() {
/*
* {0xa7} -> {0xa9, 0x60}
* {0xa7, 0x12} -> {0xa9, 0x6c, 0x72}
* {0xa7, 0x12, 0xa7} -> {0xa9, 0x6c, 0x72, 0xa9, 0x60}
*/
/* test compare */
// byte[] s1 = { 0, 1, 2 };
// byte[] s2 = { 2, 1, 0, 3 };
// byte[] s3 = { 0, 1, 2, 3 };
// if (ByteUtil.compare(s1, s1) != 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s2) >= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s2, s1) <= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s3) >= 0) {
// LOG.error("test: compare failed.");
// }
// testCompose(new byte[] {(byte)0xa7, (byte)0xa7});
byte[] bs = RFTools.encode4b6b(new byte[] { (byte)0xa7 });
byte[] out = new byte[] { (byte)(0xa9), 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12, (byte)0xa7 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72, (byte)0xa9, 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
}
// @Test
public void testEncodeGo() {
/*
* {0xa7} -> {0xa9, 0x60}
* {0xa7, 0x12} -> {0xa9, 0x6c, 0x72}
* {0xa7, 0x12, 0xa7} -> {0xa9, 0x6c, 0x72, 0xa9, 0x60}
*/
/* test compare */
// byte[] s1 = { 0, 1, 2 };
// byte[] s2 = { 2, 1, 0, 3 };
// byte[] s3 = { 0, 1, 2, 3 };
// if (ByteUtil.compare(s1, s1) != 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s2) >= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s2, s1) <= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s3) >= 0) {
// LOG.error("test: compare failed.");
// }
// testCompose(new byte[] {(byte)0xa7, (byte)0xa7});
byte[] bs = RFTools.encode4b6b_go(new byte[] { (byte)0xa7 });
byte[] out = new byte[] { (byte)(0xa9), 0x65 };
System.out.println("EncodeGo: " + ByteUtil.getHex(bs));
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b_go(new byte[] { (byte)0xa7, 0x12 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b_go(new byte[] { (byte)0xa7, 0x12, (byte)0xa7 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72, (byte)0xa9, 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
}
// @Test
public void testDecodeGo() {
// testCompose(new byte[] {(byte)0xa7, (byte)0xa7});
byte[] bs = RFTools.encode4b6b(new byte[] { (byte)0xa7 });
byte[] out = new byte[] { (byte)(0xa9), 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
}
byte[] back = RFTools.decode4b6b(out);
if (ByteUtil.compare(back, bs) != 0) {
Log.e(
TAG,
"decode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
}
back = RFTools.decode4b6b(out);
if (ByteUtil.compare(back, bs) != 0) {
Log.e(
TAG,
"decode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12, (byte)0xa7 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72, (byte)0xa9, 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
}
back = RFTools.decode4b6b(out);
if (ByteUtil.compare(back, bs) != 0) {
Log.e(
TAG,
"decode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
return;
}
// @Test
// public void ttt_decodeGo() {
//
// RFTools.DecodeResponseDto decodeResponseDto = RFTools.decode6b4b_go(new byte[] {
// (byte)0xF9, (byte)0xE9, 0x63, (byte)0x9E, 0x7F, (byte)0xE6, 0x79, 0x5F, -1, (byte)0xCF, (byte)0xF0 });
//
// if (decodeResponseDto.errorData != null) {
// Log.e(TAG, decodeResponseDto.errorData);
// Assert.assertTrue(false);
// } else {
// Assert.assertTrue(true);
// System.out.println("Response: " + ByteUtil.getHex(decodeResponseDto.data));
// }
//
// }
// @Test
public void testParametrizedGeoffEncode() {
byte[] encodedX = RFTools.encode4b6b(this.decoded);
// if (ByteUtil.compare(encodedX, this.encoded) != 0) {
// Assert.assertEquals(encodedX, encoded);
// }
Assert.assertArrayEquals(encodedX, encoded);
}
@Test
public void geoffDecode() {
byte[] decodedX = RFTools.decode4b6b(this.encoded);
Assert.assertArrayEquals(decoded, decodedX);
}
@Test
public void goDecode() {
RFTools.DecodeResponseDto decodeResponseDto = RFTools.decode4b6b_go(this.encoded);
Assert.assertNull(decodeResponseDto.errorData);
System.out.println("Result: " + ByteUtil.getHex(decodeResponseDto.data));
System.out.println("Expected: " + ByteUtil.getHex(decoded));
Assert.assertArrayEquals(decoded, decodeResponseDto.data);
}
// @Test
public void loopDecode() {
byte[] data = RFTools.decode4b6b_loop(this.encoded);
// RFTools.DecodeResponseDto decodeResponseDto
// Assert.assertNull(decodeResponseDto.errorData);
System.out.println("Result: " + ByteUtil.getHex(data));
System.out.println("Expected: " + ByteUtil.getHex(decoded));
Assert.assertArrayEquals(decoded, data);
}
@Test
public void geoffEncode() {
byte[] encodedX = RFTools.encode4b6b(this.decoded);
Assert.assertArrayEquals(encoded, encodedX);
}
@Test
public void goEncode() {
byte[] encodedX = RFTools.encode4b6b_go(this.decoded);
System.out.println("Result: " + ByteUtil.getHex(encodedX));
System.out.println("Expected: " + ByteUtil.getHex(encoded));
Assert.assertArrayEquals(encoded, encodedX);
}
@Test
public void loopEncode() {
byte[] encodedX = RFTools.encode4b6b_loop(this.decoded);
System.out.println("Result: " + ByteUtil.getHex(encodedX));
System.out.println("Expected: " + ByteUtil.getHex(encoded));
Assert.assertArrayEquals(encoded, encodedX);
}
private short[] createShortArray(byte[] data) {
short[] outData = new short[data.length];
for (int i = 0; i < data.length; i++) {
short d = data[i];
if (d < 0) {
d += 256;
}
outData[i] = d;
}
return outData;
}
}

View file

@ -0,0 +1,224 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble;
import junit.framework.Assert;
import org.junit.Test;
import android.util.Log;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
/**
* Created by andy on 11/21/18.
*/
public class RFToolsUTest {
private static final String TAG = "RFToolsUTest";
@Test
public void testEncodeGeoff() {
/*
* {0xa7} -> {0xa9, 0x60}
* {0xa7, 0x12} -> {0xa9, 0x6c, 0x72}
* {0xa7, 0x12, 0xa7} -> {0xa9, 0x6c, 0x72, 0xa9, 0x60}
*/
/* test compare */
// byte[] s1 = { 0, 1, 2 };
// byte[] s2 = { 2, 1, 0, 3 };
// byte[] s3 = { 0, 1, 2, 3 };
// if (ByteUtil.compare(s1, s1) != 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s2) >= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s2, s1) <= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s3) >= 0) {
// LOG.error("test: compare failed.");
// }
// testCompose(new byte[] {(byte)0xa7, (byte)0xa7});
byte[] bs = RFTools.encode4b6b(new byte[] { (byte)0xa7 });
byte[] out = new byte[] { (byte)(0xa9), 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12, (byte)0xa7 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72, (byte)0xa9, 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
}
@Test
public void testEncodeGo() {
/*
* {0xa7} -> {0xa9, 0x60}
* {0xa7, 0x12} -> {0xa9, 0x6c, 0x72}
* {0xa7, 0x12, 0xa7} -> {0xa9, 0x6c, 0x72, 0xa9, 0x60}
*/
/* test compare */
// byte[] s1 = { 0, 1, 2 };
// byte[] s2 = { 2, 1, 0, 3 };
// byte[] s3 = { 0, 1, 2, 3 };
// if (ByteUtil.compare(s1, s1) != 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s2) >= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s2, s1) <= 0) {
// LOG.error("test: compare failed.");
// }
// if (ByteUtil.compare(s1, s3) >= 0) {
// LOG.error("test: compare failed.");
// }
// testCompose(new byte[] {(byte)0xa7, (byte)0xa7});
byte[] bs = RFTools.encode4b6b_go(new byte[] { (byte)0xa7 });
byte[] out = new byte[] { (byte)(0xa9), 0x65 };
System.out.println("EncodeGo: " + ByteUtil.getHex(bs));
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b_go(new byte[] { (byte)0xa7, 0x12 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b_go(new byte[] { (byte)0xa7, 0x12, (byte)0xa7 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72, (byte)0xa9, 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
}
@Test
public void testDecodeGo() {
// testCompose(new byte[] {(byte)0xa7, (byte)0xa7});
byte[] bs = RFTools.encode4b6b(new byte[] { (byte)0xa7 });
byte[] out = new byte[] { (byte)(0xa9), 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
}
byte[] back = RFTools.decode4b6b(out);
if (ByteUtil.compare(back, bs) != 0) {
Log.e(
TAG,
"decode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
}
back = RFTools.decode4b6b(out);
if (ByteUtil.compare(back, bs) != 0) {
Log.e(
TAG,
"decode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
bs = RFTools.encode4b6b(new byte[] { (byte)0xa7, 0x12, (byte)0xa7 });
out = new byte[] { (byte)(0xa9), 0x6c, 0x72, (byte)0xa9, 0x65 };
if (ByteUtil.compare(bs, out) != 0) {
Log.e(
TAG,
"encode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
}
back = RFTools.decode4b6b(out);
if (ByteUtil.compare(back, bs) != 0) {
Log.e(
TAG,
"decode Data failed: expected " + ByteUtil.shortHexString(out) + " but got "
+ ByteUtil.shortHexString(bs));
Assert.fail();
}
return;
}
@Test
public void ttt_decodeGo() {
RFTools.DecodeResponseDto decodeResponseDto = RFTools
.decode4b6b_go(new byte[] {
(byte)0xF9, (byte)0xE9, 0x63, (byte)0x9E, 0x7F, (byte)0xE6, 0x79, 0x5F, (byte)0xFF, (byte)0xCF,
(byte)0xF0 });
if (decodeResponseDto.errorData != null) {
Log.e(TAG, decodeResponseDto.errorData);
Assert.assertTrue(false);
} else {
Assert.assertTrue(true);
System.out.println("Response: " + ByteUtil.getHex(decodeResponseDto.data));
}
}
@Test
public void goTest() {
System.out.println(RFTools.hi(4, (short)0xa7));
}
}