- some changes from RileyLinkAAPS project:

- refactored RfSpy and underlaying classes so that we can read Version (which is not encoded and has no CRC)
   - added functionality to be able to recover RL if BT is disabled and re-enabled
   - some minor refactorings here and there
- TBR enabled
- Bolus delivery
- Medtronic Pump Plugin is working (able to deliver TBRs and Bolus), there are still a lot of things to work on but we have base implementation here...
This commit is contained in:
Andy Rozman 2018-07-26 16:31:23 +01:00 committed by Andy Rozman
parent 0b180d3d65
commit 318436f417
40 changed files with 682 additions and 526 deletions

View file

@ -1,11 +1,16 @@
package info.nightscout.androidaps;
import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.crashlytics.android.Crashlytics;
import com.crashlytics.android.answers.Answers;
@ -47,13 +52,13 @@ import info.nightscout.androidaps.plugins.OpenAPSAMA.OpenAPSAMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSMA.OpenAPSMAPlugin;
import info.nightscout.androidaps.plugins.OpenAPSSMB.OpenAPSSMBPlugin;
import info.nightscout.androidaps.plugins.Overview.OverviewPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.Persistentnotification.PersistentNotificationPlugin;
import info.nightscout.androidaps.plugins.ProfileLocal.LocalProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileNS.NSProfilePlugin;
import info.nightscout.androidaps.plugins.ProfileSimple.SimpleProfilePlugin;
import info.nightscout.androidaps.plugins.PumpCombo.ComboPlugin;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpDanaR.DanaRPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRKorean.DanaRKoreanPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
@ -100,6 +105,7 @@ public class MainApp extends Application {
private static NSAlarmReceiver alarmReciever = new NSAlarmReceiver();
private static AckAlarmReceiver ackAlarmReciever = new AckAlarmReceiver();
private LocalBroadcastManager lbm;
private BroadcastReceiver btReceiver; // used for RileyLink (Medtronic and Omnipod)
public static boolean devBranch;
public static boolean engineeringMode;
@ -137,6 +143,8 @@ public class MainApp extends Application {
registerLocalBroadcastReceiver();
setBTReceiver();
if (pluginsList == null) {
pluginsList = new ArrayList<>();
// Register all tabs in app here
@ -240,6 +248,37 @@ public class MainApp extends Application {
lbm.registerReceiver(ackAlarmReciever, new IntentFilter(Intents.ACTION_ACK_ALARM));
}
private void setBTReceiver() {
// RileyLink framework needs to know, when BT was reconnected, so that we can reconnect to RL device
btReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
switch (state) {
case BluetoothAdapter.STATE_OFF:
case BluetoothAdapter.STATE_TURNING_OFF:
case BluetoothAdapter.STATE_TURNING_ON:
break;
case BluetoothAdapter.STATE_ON:
Log.v("MainApp", "Bluetooth on");
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.BluetoothReconnected);
break;
}
}
}
};
// Register for broadcasts on BluetoothAdapter state change
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
registerReceiver(btReceiver, filter);
}
private void startKeepAliveService() {
if (keepAliveReceiver == null) {
keepAliveReceiver = new KeepAliveReceiver();
@ -404,5 +443,10 @@ public class MainApp extends Application {
sDatabaseHelper.close();
sDatabaseHelper = null;
}
if (btReceiver != null) {
unregisterReceiver(btReceiver);
}
}
}

View file

@ -466,6 +466,8 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
bolusingEvent.percent = 100;
MainApp.bus().post(bolusingEvent);
LOG.debug("deliverTreatment: Carb only treatment.");
return new PumpEnactResult().success(true).enacted(true)
.bolusDelivered(0d).carbsDelivered(detailedBolusInfo.carbs)
.comment(MainApp.gs(R.string.virtualpump_resultok));
@ -483,6 +485,12 @@ public abstract class PumpPluginAbstract extends PluginBase implements PumpInter
protected abstract void triggerUIChange();
public PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) {
return new PumpEnactResult()
.success(false).enacted(false).comment(MainApp.gs(resourceId));
}
// Profile interface
// @Nullable

View file

@ -84,25 +84,24 @@ public enum PumpType {
0.05f, 0.05f, null, PumpCapability.VirtualPump),
// Medtronic
Minimed_512_712("Medtronic 512/712", 0.05f, null, //
Medtronic_512_712("Medtronic 512/712", 0.05f, null, //
new DoseSettings(0.05f, 30, 8 * 60, 0.05f), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05f, 30, 24 * 60, 0f, 35f), //
0.05f, 0.05f, null, PumpCapability.VirtualPump), // TODO
Minimed_515_715("Medtronic 515/715", Minimed_512_712),
Minimed_522_722("Medtronic 522/722", Minimed_512_712),
Minimed_523_723("Medtronic 523/723", Minimed_512_712),
Medtronic_515_715("Medtronic 515/715", Medtronic_512_712),
Medtronic_522_722("Medtronic 522/722", Medtronic_512_712),
Minimed_553_753_Revel("Medtronic 553/753 (Revel)", 0.05f, null, //
Medtronic_523_723_Revel("Medtronic 553/753 (Revel)", 0.05f, null, //
new DoseSettings(0.05f, 30, 8 * 60, 0.05f), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05f, 30, 24 * 60, 0f, 35f), //
0.025f, 0.025f, DoseStepSize.MedtronicVeoBasal, PumpCapability.VirtualPump), //
Minimed_554_754_Veo("Medtronic 554/754 (Veo)", Minimed_553_753_Revel), // TODO
Medtronic_554_754_Veo("Medtronic 554/754 (Veo)", Medtronic_523_723_Revel), // TODO
Minimed_640G("Medtronic 640G", 0.025f, null, //
Medtronic_640G("Medtronic 640G", 0.025f, null, //
new DoseSettings(0.05f, 30, 8 * 60, 0.05f), //
PumpTempBasalType.Absolute, //
new DoseSettings(0.05f, 30, 24 * 60, 0f, 35f), //

View file

@ -9,9 +9,10 @@ import android.widget.TextView;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkServiceData;
import info.nightscout.androidaps.plugins.PumpMedtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
/**
* Created by andy on 5/19/18.
@ -92,7 +93,7 @@ public class RileyLinkSettingsTab1 extends Fragment implements RefreshableInterf
this.connectionError.setText(rileyLinkServiceData.errorCode == null ? "-" : rileyLinkServiceData.errorCode.name());
this.medtronicPumpStatus = RileyLinkUtil.getPumpStatus();
this.medtronicPumpStatus = MedtronicUtil.getPumpStatus();
if (medtronicPumpStatus != null) {
this.deviceType.setText(RileyLinkTargetDevice.MedtronicPump.name());

View file

@ -10,18 +10,16 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
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.RFSpyResponse;
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.RadioResponse;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RLMessage;
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.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkServiceData;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.message.PumpMessage;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpDeviceState;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.utils.SP;
@ -66,26 +64,29 @@ public abstract class RileyLinkCommunicationManager {
protected abstract void configurePumpSpecificSettings();
protected PumpMessage sendAndListen(RLMessage msg) {
return sendAndListen(msg, 4000); // 2000
}
// protected PumpMessage sendAndListen(RLMessage msg) {
// return sendAndListen(msg, 4000); // 2000
// }
private int timeoutCount = 0;
// All pump communications go through this function.
protected PumpMessage sendAndListen(RLMessage msg, int timeout_ms) {
protected <E extends RLMessage> E sendAndListen(RLMessage msg, int timeout_ms, Class<E> clazz) {
if (showPumpMessages) {
LOG.info("Sent:" + ByteUtil.shortHexString(msg.getTxData()));
}
RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(msg.getTxData()), timeout_ms);
PumpMessage rval = new PumpMessage(rfSpyResponse.getRadioResponse().getPayload());
if (rval.isValid()) {
E response = createResponseMessage(rfSpyResponse.getRadioResponse().getPayload(), clazz);
//PumpMessage rval = new PumpMessage(resp.getRadioResponse().getPayload());
if (response.isValid()) {
// Mark this as the last time we heard from the pump.
rememberLastGoodPumpCommunicationTime();
rememberLastGoodDeviceCommunicationTime();
} else {
LOG.warn("Response is invalid. !!! - ", rfSpyResponse.wasInterrupted(), rfSpyResponse.wasTimeout());
@ -95,7 +96,7 @@ public abstract class RileyLinkCommunicationManager {
if (timeoutCount >= 5) {
RileyLinkUtil.setServiceState(RileyLinkServiceState.PumpConnectorError, RileyLinkError.NoContactWithDevice);
timeoutCount = 0;
tuneForPump();
tuneForDevice();
//RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_quickTune);
}
}
@ -105,48 +106,19 @@ public abstract class RileyLinkCommunicationManager {
if (showPumpMessages) {
LOG.info("Received:" + ByteUtil.shortHexString(rfSpyResponse.getRadioResponse().getPayload()));
}
return rval;
return response;
}
// /**
// * For set commands we use this method (it just sends data and returns ACK or NAK)
// *
// * @param msg
// * @param timeoutMs
// * @return
// */
// protected PumpMessage send(RLMessage msg, int timeoutMs) {
//
// // FIXME untested
// if (showPumpMessages) {
// LOG.info("Sent:" + ByteUtil.shortHexString(msg.getTxData()));
// }
//
// RFSpyResponse resp = rfspy.transmit(new RadioPacket(msg.getTxData()));
// PumpMessage rval = new PumpMessage(resp.getRadioResponse().getPayload());
// if (rval.isValid()) {
// // Mark this as the last time we heard from the pump.
// rememberLastGoodPumpCommunicationTime();
// } else {
// LOG.warn("Response is invalid. !!!");
// }
//
// if (showPumpMessages) {
// LOG.info("Received:" + ByteUtil.shortHexString(resp.getRadioResponse().getPayload()));
// }
// return rval;
// }
public abstract <E extends RLMessage> E createResponseMessage(byte[] payload, Class<E> clazz);
public void wakeUp(boolean force) {
wakeUp(receiverDeviceAwakeForMinutes, force);
}
long nextWakeUpRequired = 0L;
private long nextWakeUpRequired = 0L;
public int getNotConnectedCount() {
@ -200,20 +172,24 @@ public abstract class RileyLinkCommunicationManager {
}
public double tuneForPump() {
return scanForPump(scanFrequencies);
public double tuneForDevice() {
return scanForDevice(scanFrequencies);
}
/**
* If user changes pump and one pump is running in US freq, and other in WW, then previously set frequency would be invalid,
* so we would need to retune. This checks that saved frequency is corrent range.
* so we would need to retune. This checks that saved frequency is correct range.
*
* @param frequency
* @return
*/
public boolean isValidFrequency(double frequency) {
return (this.scanFrequencies[0] <= frequency && this.scanFrequencies[scanFrequencies.length - 1] >= frequency);
if (scanFrequencies.length == 1) {
return RileyLinkUtil.isSame(scanFrequencies[0], frequency);
} else {
return (this.scanFrequencies[0] <= frequency && this.scanFrequencies[scanFrequencies.length - 1] >= frequency);
}
}
@ -226,7 +202,7 @@ public abstract class RileyLinkCommunicationManager {
// FIXME sorting, and time display
public double scanForPump(double[] frequencies) {
public double scanForDevice(double[] frequencies) {
LOG.info("Scanning for receiver ({})", receiverDeviceID);
wakeUp(receiverDeviceAwakeForMinutes, false);
FrequencyScanResults results = new FrequencyScanResults();
@ -241,7 +217,7 @@ public abstract class RileyLinkCommunicationManager {
for (int j = 0; j < tries; j++) {
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
RFSpyResponse resp = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte) 0, (byte) 0, (byte) 0, (byte) 0, 1500, (byte) 0);
RFSpyResponse resp = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte) 0, (byte) 0, (byte) 0, (byte) 0, rfspy.EXPECTED_MAX_BLUETOOTH_LATENCY_MS, (byte) 0);
if (resp.wasTimeout()) {
LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]);
} else if (resp.looksLikeRadioPacket()) {
@ -370,18 +346,18 @@ public abstract class RileyLinkCommunicationManager {
}
private void rememberLastGoodPumpCommunicationTime() {
protected void rememberLastGoodDeviceCommunicationTime() {
lastGoodReceiverCommunicationTime = System.currentTimeMillis();
SP.putLong(MedtronicConst.Statistics.LastGoodPumpCommunicationTime, lastGoodReceiverCommunicationTime);
MedtronicUtil.getPumpStatus().setLastCommunicationToNow();
SP.putLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, lastGoodReceiverCommunicationTime);
pumpStatus.setLastCommunicationToNow();
}
private long getLastGoodReceiverCommunicationTime() {
// If we have a value of zero, we need to load from prefs.
if (lastGoodReceiverCommunicationTime == 0L) {
lastGoodReceiverCommunicationTime = SP.getLong(MedtronicConst.Statistics.LastGoodPumpCommunicationTime, 0L);
lastGoodReceiverCommunicationTime = SP.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L);
// Might still be zero, but that's fine.
}
double minutesAgo = (System.currentTimeMillis() - lastGoodReceiverCommunicationTime) / (1000.0 * 60.0);

View file

@ -12,9 +12,10 @@ public class RileyLinkConst {
public static final String RileyLinkReady = Prefix + "RileyLink_Ready";
public static final String RileyLinkGattFailed = Prefix + "RileyLink_Gatt_Failed";
public static final String RileyLinkError = Prefix + "RileyLink_Ready";
//public static final String RileyLinkError = Prefix + "RileyLink_Ready";
public static final String BluetoothConnected = Prefix + "Bluetooth_Connected";
public static final String BluetoothReconnected = Prefix + "Bluetooth_Reconnected";
public static final String BluetoothDisconnected = Prefix + "Bluetooth_Disconnected";
public static final String RileyLinkDisconnected = Prefix + "RileyLink_Disconnected";
@ -24,6 +25,15 @@ public class RileyLinkConst {
public static final String INTENT_NEW_pumpIDKey = Prefix + "INTENT_NEW_pumpIDKey";
}
public class Prefs {
public static final String PrefPrefix = "pref_rileylink_";
public static final String RileyLinkAddress = PrefPrefix + "mac_address";
public static final String LastGoodDeviceCommunicationTime = Prefix + "lastGoodDeviceCommunicationTime";
public static final String LastGoodDeviceFrequency = Prefix + "LastGoodDeviceFrequency";
}
public class IPC {
// needs to br renamed (and maybe removed)
public static final String MSG_PUMP_quickTune = Prefix + "MSG_PUMP_quickTune";
@ -34,9 +44,4 @@ public class RileyLinkConst {
public static final String MSG_ServiceCommand = Prefix + "MSG_ServiceCommand";
}
public class Prefs {
public static final String PrefPrefix = "pref_rileylink_";
public static final String RileyLinkAddress = PrefPrefix + "mac_address";
}
}

View file

@ -23,7 +23,6 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.S
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceTransport;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTask;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicDeviceType;
import info.nightscout.androidaps.plugins.PumpMedtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.PumpMedtronic.events.EventMedtronicDeviceStatusChange;
@ -46,7 +45,7 @@ public class RileyLinkUtil {
//private static RileyLinkIPCConnection rileyLinkIPCConnection;
private static MedtronicDeviceType medtronicPumpModel;
private static RileyLinkTargetFrequency rileyLinkTargetFrequency;
private static MedtronicPumpStatus pumpStatus;
//private static MedtronicPumpStatus pumpStatus;
// BAD dependencies in Classes: RileyLinkService
// Broadcasts: RileyLinkBLE, RileyLinkService,
@ -109,32 +108,11 @@ public class RileyLinkUtil {
}
// public static void setMedtronicPumpStatus(MedtronicPumpStatus medtronicPumpStatus) {
//
// RileyLinkUtil.medtronicPumpStatus = medtronicPumpStatus;
// }
// public static void addHistoryEntry(RLHistoryItem rlHistoryItem) {
// historyRileyLink.add(rlHistoryItem);
// }
// public static MedtronicPumpStatus getMedtronicPumpStatus() {
//
// return RileyLinkUtil.medtronicPumpStatus;
// }
public static boolean hasPumpBeenTunned() {
return RileyLinkUtil.rileyLinkServiceData.tuneUpDone;
}
public static void tuneUpPump() {
RileyLinkUtil.rileyLinkService.doTunePump(); // FIXME thread
}
public static void setRileyLinkService(RileyLinkService rileyLinkService) {
RileyLinkUtil.rileyLinkService = rileyLinkService;
}
@ -156,7 +134,7 @@ public class RileyLinkUtil {
public static boolean sendNotification(ServiceNotification notification, Integer clientHashcode) {
return rileyLinkService.sendNotification(notification, clientHashcode);
return RileyLinkUtil.rileyLinkService.sendNotification(notification, clientHashcode);
}
@ -211,7 +189,11 @@ public class RileyLinkUtil {
return RileyLinkUtil.rileyLinkTargetFrequency;
}
public static MedtronicPumpStatus getPumpStatus() {
return RileyLinkUtil.pumpStatus;
public static boolean isSame(Double d1, Double d2) {
double diff = d1 - d2;
return (Math.abs(diff) <= 0.000001);
}
}

View file

@ -36,7 +36,6 @@ public class RFSpy {
private RileyLinkBLE rileyLinkBle;
private RFSpyReader reader;
//private int previousRegion = 0;
private RileyLinkTargetFrequency selectedTargetFrequency;
private UUID radioServiceUUID = UUID.fromString(GattAttributes.SERVICE_RADIO);
@ -47,7 +46,6 @@ public class RFSpy {
public RFSpy(RileyLinkBLE rileyLinkBle) {
this.rileyLinkBle = rileyLinkBle;
//this.rileyLinkBle.setRFSpy(this);
reader = new RFSpyReader(rileyLinkBle);
}
@ -74,9 +72,34 @@ public class RFSpy {
public int notConnectedCount = 0;
// This gets the version from the BLE113, not from the CC1110.
// I.e., this gets the version from the BLE interface, not from the radio.
public String getVersion() {
BLECommOperationResult result = rileyLinkBle.readCharacteristic_blocking(radioServiceUUID, radioVersionUUID);
if (result.resultCode == BLECommOperationResult.RESULT_SUCCESS) {
return StringUtil.fromBytes(result.value);
} else {
LOG.error("getVersion failed with code: " + result.resultCode);
return "(null)";
}
}
public String getRadioVersion() {
RFSpyResponse resp = writeToData(RFSpyCommand.GetVersion, null, EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
if (resp == null) {
LOG.error("getRadioVersion returned null");
return "(null)";
} else {
return StringUtil.fromBytes(resp.getRadioResponse().decodedPayload);
}
}
// The caller has to know how long the RFSpy will be busy with what was sent to it.
private RFSpyResponse writeToData(byte[] bytes, int responseTimeout_ms) {
private RFSpyResponse writeToData(RFSpyCommand command, byte[] body, int responseTimeout_ms) {
byte[] bytes = getCommandArray(command, body);
SystemClock.sleep(100);
// FIXME drain read queue?
byte[] junkInBuffer = reader.poll(0);
@ -96,7 +119,7 @@ public class RFSpy {
SystemClock.sleep(100);
//Log.i(TAG,ThreadUtil.sig()+String.format(" writeToData:(timeout %d) %s",(responseTimeout_ms),ByteUtil.shortHexString(prepended)));
byte[] rawResponse = reader.poll(responseTimeout_ms);
RFSpyResponse resp = new RFSpyResponse(rawResponse);
RFSpyResponse resp = new RFSpyResponse(command, rawResponse);
if (rawResponse == null) {
LOG.error("writeToData: No response from RileyLink");
notConnectedCount++;
@ -108,11 +131,13 @@ public class RFSpy {
notConnectedCount++;
} else if (resp.isOK()) {
LOG.warn("writeToData: RileyLink reports OK");
resetNotConnectedCount();
} else {
if (resp.looksLikeRadioPacket()) {
RadioResponse radioResp = resp.getRadioResponse();
byte[] responsePayload = radioResp.getPayload();
LOG.info("writeToData: decoded radio response is " + ByteUtil.shortHexString(responsePayload));
resetNotConnectedCount();
}
//Log.i(TAG, "writeToData: raw response is " + ByteUtil.shortHexString(rawResponse));
}
@ -120,10 +145,15 @@ public class RFSpy {
return resp;
}
private void resetNotConnectedCount() {
this.notConnectedCount = 0;
}
private byte[] getByteArray(byte... input) {
return input;
}
private byte[] getCommandArray(RFSpyCommand command, byte[] body) {
int bodyLength = body == null ? 0 : body.length;
@ -141,36 +171,6 @@ public class RFSpy {
}
// This gets the version from the BLE113, not from the CC1110.
// I.e., this gets the version from the BLE interface, not from the radio.
public String getVersion() {
BLECommOperationResult result = rileyLinkBle.readCharacteristic_blocking(radioServiceUUID, radioVersionUUID);
if (result.resultCode == BLECommOperationResult.RESULT_SUCCESS) {
return StringUtil.fromBytes(result.value);
} else {
LOG.error("getVersion failed with code: " + result.resultCode);
return "(null)";
}
}
public RFSpyResponse getRadioVersion() {
RFSpyResponse resp = writeToData(getCommandArray(RFSpyCommand.GetVersion, null), EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
if (resp == null) {
LOG.error("getRadioVersion returned null");
}
/*
Log.d(TAG,"checking response count");
BLECommOperationResult checkRC = rileyLinkBle.readCharacteristic_blocking(radioServiceUUID,responseCountUUID);
if (checkRC.resultCode == BLECommOperationResult.RESULT_SUCCESS) {
Log.d(TAG,"Response count is: " + ByteUtil.shortHexString(checkRC.value));
} else {
LOG.error("Error getting response count, code is " + checkRC.resultCode);
}
*/
return resp;
}
public RFSpyResponse transmit(RadioPacket radioPacket) {
return transmit(radioPacket, (byte) 0, (byte) 0, (byte) 0xFF);
@ -179,16 +179,16 @@ public class RFSpy {
public RFSpyResponse transmit(RadioPacket radioPacket, byte sendChannel, byte repeatCount, byte delay_ms) {
// append checksum, encode data, send it.
byte[] fullPacket = ByteUtil.concat(getCommandArray(RFSpyCommand.Send, getByteArray(sendChannel, repeatCount, delay_ms)), radioPacket.getEncoded());
RFSpyResponse response = writeToData(fullPacket, delay_ms + EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
byte[] fullPacket = ByteUtil.concat(getByteArray(sendChannel, repeatCount, delay_ms), radioPacket.getEncoded());
RFSpyResponse response = writeToData(RFSpyCommand.Send, fullPacket, delay_ms + EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
return response;
}
public RFSpyResponse receive(byte listenChannel, int timeout_ms, byte retryCount) {
int receiveDelay = timeout_ms * (retryCount + 1);
byte[] listen = getCommandArray(RFSpyCommand.GetPacket, getByteArray(listenChannel, (byte) ((timeout_ms >> 24) & 0x0FF), (byte) ((timeout_ms >> 16) & 0x0FF), (byte) ((timeout_ms >> 8) & 0x0FF), (byte) (timeout_ms & 0x0FF), retryCount));
return writeToData(listen, receiveDelay);
byte[] listen = getByteArray(listenChannel, (byte) ((timeout_ms >> 24) & 0x0FF), (byte) ((timeout_ms >> 16) & 0x0FF), (byte) ((timeout_ms >> 8) & 0x0FF), (byte) (timeout_ms & 0x0FF), retryCount);
return writeToData(RFSpyCommand.GetPacket, listen, receiveDelay);
}
@ -201,15 +201,15 @@ public class RFSpy {
int sendDelay = repeatCount * delay_ms;
int receiveDelay = timeout_ms * (retryCount + 1);
byte[] sendAndListen = getCommandArray(RFSpyCommand.SendAndListen, getByteArray(sendChannel, repeatCount, delay_ms, listenChannel, (byte) ((timeout_ms >> 24) & 0x0FF), (byte) ((timeout_ms >> 16) & 0x0FF), (byte) ((timeout_ms >> 8) & 0x0FF), (byte) (timeout_ms & 0x0FF), (byte) retryCount));
byte[] sendAndListen = getByteArray(sendChannel, repeatCount, delay_ms, listenChannel, (byte) ((timeout_ms >> 24) & 0x0FF), (byte) ((timeout_ms >> 16) & 0x0FF), (byte) ((timeout_ms >> 8) & 0x0FF), (byte) (timeout_ms & 0x0FF), (byte) retryCount);
byte[] fullPacket = ByteUtil.concat(sendAndListen, pkt.getEncoded());
return writeToData(fullPacket, sendDelay + receiveDelay + EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
return writeToData(RFSpyCommand.SendAndListen, fullPacket, sendDelay + receiveDelay + EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
}
public RFSpyResponse updateRegister(CC111XRegister reg, int val) {
byte[] updateRegisterPkt = getCommandArray(RFSpyCommand.UpdateRegister, getByteArray(reg.value, (byte) val));
RFSpyResponse resp = writeToData(updateRegisterPkt, EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
byte[] updateRegisterPkt = getByteArray(reg.value, (byte) val);
RFSpyResponse resp = writeToData(RFSpyCommand.UpdateRegister, updateRegisterPkt, EXPECTED_MAX_BLUETOOTH_LATENCY_MS);
return resp;
}
@ -233,7 +233,6 @@ public class RFSpy {
switch (frequency) {
case Medtronic_WorldWide: {
//updateRegister(CC111X_MDMCFG4, (byte) 0x59);
setRXFilterMode(RXFilterMode.Wide);
//updateRegister(CC111X_MDMCFG3, (byte) 0x66);
//updateRegister(CC111X_MDMCFG2, (byte) 0x33);
@ -244,7 +243,6 @@ public class RFSpy {
break;
case Medtronic_US: {
//updateRegister(CC111X_MDMCFG4, (byte) 0x99);
setRXFilterMode(RXFilterMode.Narrow);
//updateRegister(CC111X_MDMCFG3, (byte) 0x66);
//updateRegister(CC111X_MDMCFG2, (byte) 0x33);

View file

@ -23,24 +23,8 @@ public class RFTools {
to communicate with a Medtronic pump.
*/
public static byte[] CodeSymbols = {
0x15,
0x31,
0x32,
0x23,
0x34,
0x25,
0x26,
0x16,
0x1a,
0x19,
0x2a,
0x0b,
0x2c,
0x0d,
0x0e,
0x1c
};
public static byte[] CodeSymbols = {0x15, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x16, 0x1a, 0x19, 0x2a, 0x0b, 0x2c, 0x0d, 0x0e, 0x1c};
public static byte[] appendChecksum(final byte[] input) {
if (input == null) {
@ -285,15 +269,15 @@ public class RFTools {
return toHexString(array, 0, array.length);
}
private final static char[] HEX_DIGITS = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};
private final static char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
public static String toHexString(byte[] array, int offset, int length) {
char[] buf = new char[length * 2];
int bufIndex = 0;
for (int i = offset; i < offset + length; i++) {
for(int i = offset; i < offset + length; i++) {
byte b = array[i];
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];

View file

@ -35,7 +35,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.utils.ThreadUtil;
/**
* Created by geoff on 5/26/16.
* Added: State handling, configuration of RF for different configuration ranges, connection handling - Andy
* Added: State handling, configuration of RF for different configuration ranges, connection handling
*/
public class RileyLinkBLE {
@ -134,8 +134,13 @@ public class RileyLinkBLE {
LOG.warn("onConnectionStateChange " + getGattStatusMessage(status) + " " + stateMessage);
}
if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.BluetoothConnected);
if (newState == BluetoothProfile.STATE_CONNECTED) {
if (status == BluetoothGatt.GATT_SUCCESS) {
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.BluetoothConnected);
} else {
LOG.debug("BT State connected, GATT status {} ({})", status, getGattStatusMessage(status));
}
} else if ((newState == BluetoothProfile.STATE_CONNECTING) || //
(newState == BluetoothProfile.STATE_DISCONNECTING)) {
//LOG.debug("We are in {} state.", status == BluetoothProfile.STATE_CONNECTING ? "Connecting" : "Disconnecting");
@ -227,7 +232,7 @@ public class RileyLinkBLE {
if (rileyLinkFound) {
mIsConnected = true;
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.Intents.RileyLinkReady);
//RileyLinkUtil.sendNotification(new ServiceNotification(RT2Const.IPC.MSG_BLE_RileyLinkReady), null);
//RileyLinkUtil.sendNotification(new ServiceNotification(RileyLinkConst.Intents.RileyLinkReady), null);
} else {
mIsConnected = false;
RileyLinkUtil.setServiceState(RileyLinkServiceState.RileyLinkError, RileyLinkError.DeviceIsNotRileyLink);

View file

@ -10,7 +10,7 @@ import java.util.UUID;
public class GattAttributes {
// NOTE: these uuid strings must be lower case!
private static Map<String, String> attributes;
public static String PREFIX = "0000";
public static String SUFFIX = "-0000-1000-8000-00805f9b34fb";
public static String SERVICE_GAP = PREFIX + "1800" + SUFFIX;
@ -30,6 +30,8 @@ public class GattAttributes {
public static String CHARA_RADIO_VERSION = "30d99dc9-7c91-4295-a051-0a104d238cf2";
public static String CHARA_RADIO_LED_MODE = "c6d84241-f1a7-4f9c-a25f-fce16732f14e";
private static Map<String, String> attributes;
private static Map<String, String> attributesRileyLinkSpecific;
// table of names for uuids
static {
@ -49,6 +51,16 @@ public class GattAttributes {
attributes.put(CHARA_RADIO_TIMER_TICK, "Timer Tick");
attributes.put(CHARA_RADIO_VERSION, "Version"); // firmwareVersion
attributes.put(CHARA_RADIO_LED_MODE, "Led Mode");
attributesRileyLinkSpecific = new HashMap<>();
attributesRileyLinkSpecific.put(SERVICE_RADIO, "Radio Interface"); // a
attributesRileyLinkSpecific.put(CHARA_RADIO_CUSTOM_NAME, "Custom Name");
attributesRileyLinkSpecific.put(CHARA_RADIO_DATA, "Data");
attributesRileyLinkSpecific.put(CHARA_RADIO_RESPONSE_COUNT, "Response Count");
attributesRileyLinkSpecific.put(CHARA_RADIO_TIMER_TICK, "Timer Tick");
attributesRileyLinkSpecific.put(CHARA_RADIO_VERSION, "Version"); // firmwareVersion
attributesRileyLinkSpecific.put(CHARA_RADIO_LED_MODE, "Led Mode");
}
@ -68,10 +80,9 @@ public class GattAttributes {
}
// TODO check if service is rileylink
// we check for specific UUID (Radio ones, because thoose seem to be unique
public static boolean isRileyLink(UUID uuid) {
return attributes.containsKey(uuid.toString());
//return true;
return attributesRileyLinkSpecific.containsKey(uuid.toString());
}

View file

@ -1,5 +1,7 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RFSpyCommand;
/**
* Created by geoff on 5/26/16.
*/
@ -9,33 +11,46 @@ public class RFSpyResponse {
// 0xcc == zero-data
protected byte[] raw;
protected RadioResponse radioResponse;
private RFSpyCommand command;
public RFSpyResponse() {
init(new byte[0]);
}
public RFSpyResponse(byte[] bytes) {
init(bytes);
}
public RFSpyResponse(RFSpyCommand command, byte[] rawResponse) {
this.command = command;
init(rawResponse);
}
public void init(byte[] bytes) {
if (bytes == null) {
raw = new byte[0];
} else {
raw = bytes;
}
if (looksLikeRadioPacket()) {
radioResponse = new RadioResponse(raw);
radioResponse = new RadioResponse(command, raw);
} else {
radioResponse = new RadioResponse();
}
}
public RadioResponse getRadioResponse() {
return radioResponse;
}
public boolean wasTimeout() {
if ((raw.length == 1) || (raw.length == 2)) {
if (raw[0] == (byte) 0xaa) {
@ -45,6 +60,7 @@ public class RFSpyResponse {
return false;
}
public boolean wasInterrupted() {
if ((raw.length == 1) || (raw.length == 2)) {
if (raw[0] == (byte) 0xbb) {
@ -54,6 +70,7 @@ public class RFSpyResponse {
return false;
}
public boolean isOK() {
if ((raw.length == 1) || (raw.length == 2)) {
if (raw[0] == (byte) 0x01) {
@ -63,6 +80,7 @@ public class RFSpyResponse {
return false;
}
public boolean looksLikeRadioPacket() {
if (raw.length > 2) {
return true;
@ -70,6 +88,7 @@ public class RFSpyResponse {
return false;
}
public byte[] getRaw() {
return raw;
}

View file

@ -7,4 +7,6 @@ public interface RLMessage {
byte[] getTxData();
boolean isValid();
}

View file

@ -4,6 +4,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFTools;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RFSpyCommand;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC;
@ -19,6 +20,7 @@ public class RadioResponse {
public int responseNumber;
public byte[] decodedPayload = new byte[0];
public byte receivedCRC;
private RFSpyCommand command;
public RadioResponse() {
@ -29,8 +31,21 @@ public class RadioResponse {
init(rxData);
}
public RadioResponse(RFSpyCommand command, byte[] raw) {
this.command = command;
init(raw);
}
public boolean isValid() {
if (command!=null && !command.isEncoded())
{
return true;
}
if (!decodedOK) {
return false;
}
@ -55,14 +70,25 @@ public class RadioResponse {
responseNumber = rxData[1];
byte[] encodedPayload = ByteUtil.substring(rxData, 2, rxData.length - 2);
try {
byte[] decodeThis = RFTools.decode4b6b(encodedPayload);
decodedOK = true;
decodedPayload = ByteUtil.substring(decodeThis, 0, decodeThis.length - 1);
byte calculatedCRC = CRC.crc8(decodedPayload);
receivedCRC = decodeThis[decodeThis.length - 1];
if (receivedCRC != calculatedCRC) {
LOG.error("RadioResponse: CRC mismatch, calculated 0x%02x, received 0x%02x", calculatedCRC, receivedCRC);
boolean isEncoded = command==null || command.isEncoded();
if (isEncoded) {
byte[] decodeThis = RFTools.decode4b6b(encodedPayload);
decodedOK = true;
decodedPayload = ByteUtil.substring(decodeThis, 0, decodeThis.length - 1);
byte calculatedCRC = CRC.crc8(decodedPayload);
receivedCRC = decodeThis[decodeThis.length - 1];
if (receivedCRC != calculatedCRC) {
LOG.error(String.format("RadioResponse: CRC mismatch, calculated 0x%02x, received 0x%02x", calculatedCRC, receivedCRC));
}
}
else {
decodedOK = true;
decodedPayload = encodedPayload;
}
//byte[] decodeThis = RFTools.decode4b6b(encodedPayload);
} catch (NumberFormatException e) {
decodedOK = false;
LOG.error("Failed to decode radio data: " + ByteUtil.shortHexString(encodedPayload));

View file

@ -7,7 +7,7 @@ package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs;
public enum RFSpyCommand {
GetState(1), //
GetVersion(2), //
GetVersion(2, false), //
GetPacket(3), // aka Listen, receive
Send(4), //
SendAndListen(5), //
@ -17,10 +17,26 @@ public enum RFSpyCommand {
;
public byte code;
private boolean encoded = true;
RFSpyCommand(int code) {
this.code = (byte) code;
}
RFSpyCommand(int code, boolean encoded) {
this.code = (byte) code;
this.encoded = encoded;
}
public boolean isEncoded() {
return encoded;
}
public void setEncoded(boolean encoded) {
this.encoded = encoded;
}
}

View file

@ -1,10 +0,0 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs;
/**
* Created by andy on 5/6/18.
*/
public interface RLMessage {
byte[] getTxData();
}

View file

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

View file

@ -8,7 +8,7 @@ public enum RileyLinkTargetFrequency {
Medtronic_WorldWide(868.25, 868.65, 0.05), //
Medtronic_US(916.45, 916.80, 0.05), //
Omnipod(416.00, 417.00, 0.05), //
Omnipod(433.91, 433.91, 0.00), //
;
double minFrequency;
@ -24,7 +24,17 @@ public enum RileyLinkTargetFrequency {
public double[] getScanFrequencies() {
if (maxFrequency == minFrequency)
{
double freq[] = new double[1];
freq[0] = minFrequency;
return freq;
}
double diff = maxFrequency - minFrequency;
int count = (int) (diff / step);
double freq[] = new double[count];

View file

@ -20,7 +20,7 @@ public enum RileyLinkError {
DeviceIsNotRileyLink(R.string.rileylink_error_not_rl), //
// Device
TuneUpOfPumpFailed(R.string.rileylink_error_tuneup_failed), //
TuneUpOfDeviceFailed(R.string.rileylink_error_tuneup_failed), //
NoContactWithDevice(R.string.rileylink_error_pump_unreachable, R.string.rileylink_error_pod_unreachable), //
;

View file

@ -22,7 +22,7 @@ public enum RileyLinkServiceState {
RileyLinkReady(R.string.rileylink_state_connected), // (OK) if tunning was already done we go to PumpConnectorReady
// Tunning
TuneUpPump(R.string.rileylink_state_pc_tune_up), // (S)
TuneUpDevice(R.string.rileylink_state_pc_tune_up), // (S)
PumpConnectorError(R.string.rileylink_state_pc_error), // either TuneUp Error or pump couldn't not be contacted error
PumpConnectorReady(R.string.rileylink_state_connected), // (OK) RileyLink Ready for Pump Communication

View file

@ -5,7 +5,18 @@ package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs;
*/
public enum RileyLinkTargetDevice {
MedtronicPump, //
Omnipod, //
MedtronicPump(true), //
Omnipod(false), //
;
private boolean tuneUpEnabled;
RileyLinkTargetDevice(boolean tuneUpEnabled) {
this.tuneUpEnabled = tuneUpEnabled;
}
public boolean isTuneUpEnabled() {
return tuneUpEnabled;
}
}

View file

@ -17,10 +17,10 @@ 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.ble.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RileyLinkBLE;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RFSpyResponse;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkTargetFrequency;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceNotification;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceResult;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceTransport;
@ -28,14 +28,12 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.InitializePumpManagerTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpCommon.utils.StringUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.utils.SP;
import static info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil.getRileyLinkCommunicationManager;
//import static info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.;
/**
* Created by andy on 5/6/18.
@ -54,7 +52,7 @@ public abstract class RileyLinkService extends Service {
//protected boolean needBluetoothPermission = true;
//protected RileyLinkIPCConnection rileyLinkIPCConnection;
protected Context context;
public RileyLinkCommunicationManager pumpCommunicationManager;
//public RileyLinkCommunicationManager pumpCommunicationManager;
protected BroadcastReceiver mBroadcastReceiver;
protected RileyLinkServiceData rileyLinkServiceData;
@ -121,16 +119,6 @@ public abstract class RileyLinkService extends Service {
//rileyLinkIPCConnection = new RileyLinkIPCConnection(context); // TODO We might be able to remove this -- Andy
//RileyLinkUtil.setRileyLinkIPCConnection(rileyLinkIPCConnection);
// // get most recently used RileyLink address
// rileyLinkServiceData.rileylinkAddress = SP.getString(MedtronicConst.Prefs.RileyLinkAddress, "");
//
// rileyLinkBLE = new RileyLinkBLE(this);
// rfspy = new RFSpy(context, rileyLinkBLE);
// rfspy.startReader();
//
// RileyLinkUtil.setRileyLinkBLE(rileyLinkBLE);
loadPumpCommunicationManager();
mBroadcastReceiver = new BroadcastReceiver() {
@Override
@ -145,44 +133,16 @@ public abstract class RileyLinkService extends Service {
if (action == null) {
LOG.error("onReceive: null action");
} else {
if (action.equals(RileyLinkConst.Intents.BluetoothConnected)) {
LOG.warn("serviceLocal.bluetooth_connected");
//rileyLinkIPCConnection.sendNotification(new ServiceNotification(RT2Const.IPC.MSG_note_FindingRileyLink), null);
ServiceTaskExecutor.startTask(new DiscoverGattServicesTask());
// If this is successful,
// We will get a broadcast of RT2Const.serviceLocal.BLE_services_discovered
} else if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) {
if (bluetoothAdapter.isEnabled()) {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothReady, RileyLinkError.RileyLinkUnreachable);
} else {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled);
}
} else if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
// FIXME remove
final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
LOG.debug("Bluetooth Action State Changed: " + state);
switch (state) {
case BluetoothAdapter.STATE_OFF: {
LOG.debug("Bluetooth OFF");
//RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled);
}
break;
case BluetoothAdapter.STATE_ON: {
LOG.debug("Bluetooth ON");
//setButtonText("Bluetooth on");
}
break;
case BluetoothAdapter.STATE_TURNING_OFF:
case BluetoothAdapter.STATE_TURNING_ON:
break;
}
} else if (action.equals(RileyLinkConst.Intents.RileyLinkReady)) {
LOG.warn("MedtronicConst.Intents.RileyLinkReady");
// FIXME
@ -190,43 +150,50 @@ public abstract class RileyLinkService extends Service {
rileyLinkBLE.enableNotifications();
rfspy.startReader(); // call startReader from outside?
LOG.debug("RfSpy version (BLE113): " + rfspy.getVersion());
String data = rfspy.getVersion();
LOG.debug("RfSpy version (BLE113): " + data);
rileyLinkServiceData.versionBLE113 = data;
RFSpyResponse radioVersion = rfspy.getRadioVersion();
byte[] response = radioVersion.getRadioResponse().decodedPayload;
LOG.debug("Response: " + HexDump.toHexStringDisplayable(response));
LOG.debug("RfSpy Radio version (CC110): " + StringUtil.fromBytes(radioVersion.getRadioResponse().decodedPayload));
data = rfspy.getRadioVersion();
LOG.debug("RfSpy Radio version (CC110): " + data);
rileyLinkServiceData.versionCC110 = data;
ServiceTask task = new InitializePumpManagerTask();
ServiceTaskExecutor.startTask(task);
LOG.info("Announcing RileyLink open For business");
} /*else if (action.equals(RT2Const.serviceLocal.ipcBound)) {
// If we still need permission for bluetooth, ask now.
// FIXME removed Andy - doesn't do anything
// if (needBluetoothPermission) {
// sendBLERequestForAccess();
// }
}*/ /*else if (RT2Const.IPC.MSG_BLE_accessGranted.equals(action)) {
//initializeLeAdapter();
//bluetoothInit();
} else if (RT2Const.IPC.MSG_BLE_accessDenied.equals(action)) {
LOG.error("BLE_Access_Denied recived. Stoping the service.");
stopSelf(); // This will stop the service.
} */ else if (action.equals(RileyLinkConst.IPC.MSG_PUMP_tunePump)) {
doTunePump();
} else if (action.equals(RileyLinkConst.Intents.BluetoothReconnected)) {
LOG.debug("Reconnecting Bluetooth");
//rileyLinkIPCConnection.sendNotification(new ServiceNotification(RT2Const.IPC.MSG_note_FindingRileyLink), null);
bluetoothInit();
ServiceTaskExecutor.startTask(new DiscoverGattServicesTask(true));
} else if (action.equals(RileyLinkConst.IPC.MSG_PUMP_tunePump)) {
if (getRileyLinkTargetDevice().isTuneUpEnabled()) {
doTuneUpDevice();
}
} else if (action.equals(RileyLinkConst.IPC.MSG_PUMP_quickTune)) {
doTunePump();
} else if (RileyLinkConst.Intents.RileyLinkNewAddressSet.equals(action)) {
reconfigureRileyLink(MedtronicUtil.getPumpStatus().rileyLinkAddress);
if (getRileyLinkTargetDevice().isTuneUpEnabled()) {
doTuneUpDevice();
}
} else if (action.startsWith("MSG_PUMP_")) {
handlePumpSpecificIntents(intent);
} else if (RileyLinkConst.IPC.MSG_ServiceCommand.equals(action)) {
handleIncomingServiceTransport(intent);
} /*else if (RT2Const.serviceLocal.INTENT_sessionCompleted.equals(action)) {
} else if (action.equals(RileyLinkConst.Intents.RileyLinkNewAddressSet)) {
String RileylinkBLEAddress = SP.getString(RileyLinkConst.Prefs.RileyLinkAddress, "");
if (RileylinkBLEAddress.equals("")) {
LOG.error("No Rileylink BLE Address saved in app");
} else {
//showBusy("Configuring Service", 50);
//rileyLinkBLE.findRileyLink(RileylinkBLEAddress);
reconfigureRileyLink(RileylinkBLEAddress);
//MainApp.getServiceClientConnection().setThisRileylink(RileylinkBLEAddress);
}
}
/*else if (RT2Const.serviceLocal.INTENT_sessionCompleted.equals(action)) {
Bundle bundle = intent.getBundleExtra(RT2Const.IPC.bundleKey);
if (bundle != null) {
ServiceTransport transport = new ServiceTransport(bundle);
@ -280,20 +247,16 @@ public abstract class RileyLinkService extends Service {
intentFilter.addAction(RileyLinkConst.Intents.BluetoothDisconnected);
intentFilter.addAction(RileyLinkConst.Intents.RileyLinkReady);
intentFilter.addAction(RileyLinkConst.Intents.RileyLinkDisconnected);
intentFilter.addAction(RileyLinkConst.Intents.BluetoothReconnected);
intentFilter.addAction(RileyLinkConst.Intents.RileyLinkNewAddressSet);
intentFilter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
intentFilter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
//intentFilter.addAction(RT2Const.serviceLocal.ipcBound);
//intentFilter.addAction(RT2Const.IPC.MSG_BLE_accessGranted);
//intentFilter.addAction(RT2Const.IPC.MSG_BLE_accessDenied);
//intentFilter.addAction(RT2Const.IPC.MSG_BLE_useThisDevice);
intentFilter.addAction(RileyLinkConst.IPC.MSG_PUMP_tunePump);
intentFilter.addAction(RileyLinkConst.IPC.MSG_PUMP_quickTune);
//intentFilter.addAction(RT2Const.IPC.MSG_PUMP_useThisAddress);
intentFilter.addAction(RileyLinkConst.IPC.MSG_ServiceCommand);
//intentFilter.addAction(RT2Const.serviceLocal.INTENT_sessionCompleted);
//intentFilter.addAction(RileyLinkConst.serviceLocal.INTENT_sessionCompleted);
addPumpSpecificIntents(intentFilter);
@ -303,12 +266,12 @@ public abstract class RileyLinkService extends Service {
}
public abstract RileyLinkCommunicationManager getDeviceCommunicationManager();
public abstract void addPumpSpecificIntents(IntentFilter intentFilter);
public abstract void handlePumpSpecificIntents(Intent intent);
public abstract void loadPumpCommunicationManager();
public abstract void handleIncomingServiceTransport(Intent intent);
@ -444,14 +407,14 @@ public abstract class RileyLinkService extends Service {
// FIXME: This needs to be run in a session so that is interruptable, has a separate thread, etc.
public void doTunePump() {
public void doTuneUpDevice() {
RileyLinkUtil.setServiceState(RileyLinkServiceState.TuneUpPump);
RileyLinkUtil.setServiceState(RileyLinkServiceState.TuneUpDevice);
double lastGoodFrequency = 0.0d;
if (rileyLinkServiceData.lastGoodFrequency == null) {
lastGoodFrequency = SP.getDouble(MedtronicConst.Statistics.LastGoodPumpFrequency, 0.0d);
lastGoodFrequency = SP.getDouble(RileyLinkConst.Prefs.LastGoodDeviceFrequency, 0.0d);
} else {
lastGoodFrequency = rileyLinkServiceData.lastGoodFrequency;
}
@ -460,21 +423,21 @@ public abstract class RileyLinkService extends Service {
if ((lastGoodFrequency > 0.0d) && getRileyLinkCommunicationManager().isValidFrequency(lastGoodFrequency)) {
LOG.info("Checking for pump near last saved frequency of {}MHz", lastGoodFrequency);
// we have an old frequency, so let's start there.
newFrequency = pumpCommunicationManager.quickTuneForPump(lastGoodFrequency);
newFrequency = getDeviceCommunicationManager().quickTuneForPump(lastGoodFrequency);
if (newFrequency == 0.0) {
// quick scan failed to find pump. Try full scan
LOG.warn("Failed to find pump near last saved frequency, doing full scan");
newFrequency = pumpCommunicationManager.tuneForPump();
newFrequency = getDeviceCommunicationManager().tuneForDevice();
}
} else {
LOG.warn("No saved frequency for pump, doing full scan.");
// we don't have a saved frequency, so do the full scan.
newFrequency = pumpCommunicationManager.tuneForPump();
newFrequency = getDeviceCommunicationManager().tuneForDevice();
}
if ((newFrequency != 0.0) && (newFrequency != lastGoodFrequency)) {
LOG.info("Saving new pump frequency of {}MHz", newFrequency);
SP.putDouble(MedtronicConst.Statistics.LastGoodPumpFrequency, newFrequency);
SP.putDouble(RileyLinkConst.Prefs.LastGoodDeviceFrequency, newFrequency);
rileyLinkServiceData.lastGoodFrequency = newFrequency;
rileyLinkServiceData.tuneUpDone = true;
rileyLinkServiceData.lastTuneUpTime = System.currentTimeMillis();
@ -484,7 +447,7 @@ public abstract class RileyLinkService extends Service {
if (newFrequency == 0.0d) {
// error tuning pump, pump not present ??
RileyLinkUtil.setServiceState(RileyLinkServiceState.PumpConnectorError, RileyLinkError.TuneUpOfPumpFailed);
RileyLinkUtil.setServiceState(RileyLinkServiceState.PumpConnectorError, RileyLinkError.TuneUpOfDeviceFailed);
}
}
@ -492,4 +455,9 @@ public abstract class RileyLinkService extends Service {
public void disconnectRileyLink() {
this.rileyLinkBLE.disconnect();
}
public RileyLinkTargetDevice getRileyLinkTargetDevice() {
return this.rileyLinkServiceData.targetDevice;
}
}

View file

@ -4,6 +4,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLink
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
/**
* Created by andy on 16/05/2018.
*/
@ -17,6 +18,11 @@ public class RileyLinkServiceData {
public long lastTuneUpTime = 0L;
public Double lastGoodFrequency;
// bt version
public String versionBLE113;
// radio version
public String versionCC110;
public RileyLinkTargetDevice targetDevice;
// Medtronic Pump

View file

@ -7,12 +7,24 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
*/
public class DiscoverGattServicesTask extends ServiceTask {
public boolean needToConnect = false;
public DiscoverGattServicesTask() {
}
public DiscoverGattServicesTask(boolean needToConnect) {
this.needToConnect = needToConnect;
}
@Override
public void run() {
if (needToConnect)
RileyLinkUtil.getRileyLinkBLE().connectGatt();
RileyLinkUtil.getRileyLinkBLE().discoverServices();
}
}

View file

@ -7,7 +7,6 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceTransport;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
import info.nightscout.utils.SP;
/**
@ -34,7 +33,7 @@ public class InitializePumpManagerTask extends ServiceTask {
public void run() {
// FIXME
double lastGoodFrequency = SP.getDouble(MedtronicConst.Statistics.LastGoodPumpFrequency, 0.0);
double lastGoodFrequency = SP.getDouble(RileyLinkConst.Prefs.LastGoodDeviceFrequency, 0.0d);
if ((lastGoodFrequency > 0.0d) && RileyLinkUtil.getRileyLinkCommunicationManager().isValidFrequency(lastGoodFrequency)) {
@ -55,7 +54,6 @@ public class InitializePumpManagerTask extends ServiceTask {
//RileyLinkUtil.sendNotification(new ServiceNotification(RT2Const.IPC.MSG_note_Idle), null);
} else {
RileyLinkUtil.sendBroadcastMessage(RileyLinkConst.IPC.MSG_PUMP_tunePump);
}
}
}

View file

@ -20,6 +20,10 @@ public class ServiceTaskExecutor extends ThreadPoolExecutor {
instance = new ServiceTaskExecutor();
}
public static ServiceTaskExecutor getInstance() {
return instance;
}
private ServiceTaskExecutor() {
super(1, 1, 10000, TimeUnit.MILLISECONDS, taskQueue);
}

View file

@ -7,7 +7,6 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.service.RileyLinkMedtron
* Created by geoff on 7/16/16.
*/
public class WakeAndTuneTask extends PumpTask {
private static final String TAG = "WakeAndTuneTask";
public WakeAndTuneTask() {
@ -21,8 +20,7 @@ public class WakeAndTuneTask extends PumpTask {
@Override
public void run() {
//RileyLinkMedtronicService.getInstance().pumpCommunicationManager.wakeup(6);
RileyLinkMedtronicService.getInstance().pumpCommunicationManager.tuneForPump();
RileyLinkMedtronicService.getInstance().doTuneUpDevice();
}
}

View file

@ -7,11 +7,11 @@ import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.FragmentManager;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -39,8 +39,6 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkError;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkServiceState;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpDanaR.Dialogs.ProfileViewDialog;
import info.nightscout.androidaps.plugins.PumpDanaR.activities.DanaRHistoryActivity;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpDeviceState;
import info.nightscout.androidaps.plugins.PumpMedtronic.driver.MedtronicPumpStatus;
@ -48,6 +46,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.events.EventMedtronicDev
import info.nightscout.androidaps.plugins.PumpMedtronic.events.EventMedtronicPumpValuesChanged;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.events.EventQueueChanged;
import info.nightscout.utils.DateUtil;
import info.nightscout.utils.DecimalFormatter;
@ -105,6 +104,9 @@ public class MedtronicFragment extends SubscriberFragment {
@BindView(R.id.medtronic_pump_status)
IconTextView pumpStatusIconView;
@BindView(R.id.medtronic_refresh)
Button refreshButton;
public MedtronicFragment() {
}
@ -148,14 +150,20 @@ public class MedtronicFragment extends SubscriberFragment {
@OnClick(R.id.medtronic_history)
void onHistoryClick() {
startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
//startActivity(new Intent(getContext(), DanaRHistoryActivity.class));
}
@OnClick(R.id.medtronic_viewprofile)
void onViewProfileClick() {
FragmentManager manager = getFragmentManager();
ProfileViewDialog profileViewDialog = new ProfileViewDialog();
profileViewDialog.show(manager, "ProfileViewDialog");
@OnClick(R.id.medtronic_refresh)
void onRefreshClick() {
refreshButton.setEnabled(false);
MedtronicPumpPlugin.getPlugin().resetStatusState();
ConfigBuilderPlugin.getCommandQueue().readStatus("Clicked refresh", new Callback() {
@Override
public void run() {
refreshButton.setEnabled(true);
}
});
}
@OnClick(R.id.medtronic_stats)
@ -163,12 +171,6 @@ public class MedtronicFragment extends SubscriberFragment {
startActivity(new Intent(getContext(), RileylinkSettingsActivity.class));
}
/*@OnClick(R.id.medtronic_btconnection)
void onBtConnectionClick() {
log.debug("Clicked connect to pump");
DanaRPump.getInstance().lastConnection = 0;
ConfigBuilderPlugin.getCommandQueue().readStatus("Clicked connect to pump", null);
}*/
@Subscribe
public void onStatusEvent(final EventPumpStatusChanged c) {
@ -188,20 +190,7 @@ public class MedtronicFragment extends SubscriberFragment {
public void run() {
MedtronicPumpStatus pumpStatus = MedtronicUtil.getPumpStatus();
// if (eventStatusChange.rileyLinkServiceState != null)
// pumpStatus.rileyLinkServiceState = eventStatusChange.rileyLinkServiceState;
//
// if (eventStatusChange.rileyLinkError != null)
// pumpStatus.rileyLinkError = eventStatusChange.rileyLinkError;
//
// if (eventStatusChange.pumpDeviceState != null)
// pumpStatus.pumpDeviceState = eventStatusChange.pumpDeviceState;
setDeviceStatus(pumpStatus);
//pumpStatusIconView.setTextColor(Color.WHITE);
//pumpStatusIconView.setTextSize(20);
//pumpStatusIconView.setText("{fa-bed}");
}
}
);

View file

@ -18,14 +18,20 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TemporaryBasal;
import info.nightscout.androidaps.events.EventRefreshOverview;
import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.interfaces.PumpDescription;
import info.nightscout.androidaps.interfaces.PumpInterface;
import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.plugins.PumpCommon.PumpPluginAbstract;
import info.nightscout.androidaps.plugins.PumpCommon.defs.PumpType;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui.MedtronicUIComm;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui.MedtronicUITask;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
@ -37,6 +43,7 @@ import info.nightscout.androidaps.plugins.PumpMedtronic.events.EventMedtronicPum
import info.nightscout.androidaps.plugins.PumpMedtronic.service.RileyLinkMedtronicService;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicUtil;
import info.nightscout.androidaps.plugins.Treatments.TreatmentsPlugin;
import info.nightscout.utils.SP;
/**
@ -52,7 +59,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
protected static MedtronicPumpPlugin plugin = null;
private MedtronicPumpStatus pumpStatusLocal = null;
private MedtronicUIComm medtronicUIComm = new MedtronicUIComm();
boolean firstRun = true;
// variables for handling statuses and history
private boolean firstRun = true;
private boolean relevantConfigurationChangeFound = false;
private boolean hasBasalProfileChanged = false;
private boolean isBasalProfileInvalid = false;
private Map<MedtronicStatusRefreshType, Long> statusRefreshMap = new HashMap<>();
public static MedtronicPumpPlugin getPlugin() {
if (plugin == null)
@ -79,11 +93,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
.pluginName(R.string.medtronic_name) //
.shortName(R.string.medtronic_name_short) //
.preferencesId(R.xml.pref_medtronic), //
PumpType.Minimed_512_712 // we default to most basic model, correct model from config is loaded later
PumpType.Medtronic_512_712 // we default to most basic model, correct model from config is loaded later
);
LOG.error("After supper called.");
serviceConnection = new ServiceConnection() {
public void onServiceDisconnected(ComponentName name) {
@ -96,47 +108,34 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
RileyLinkMedtronicService.LocalBinder mLocalBinder = (RileyLinkMedtronicService.LocalBinder) service;
medtronicService = mLocalBinder.getServiceInstance();
//pumpStatusLocal.setNotInPreInit();
new Thread(() -> {
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
SystemClock.sleep(5000);
for (int i = 0; i < 20; i++) {
SystemClock.sleep(5000);
LOG.debug("Trying to start service L1.");
if (MedtronicUtil.getPumpStatus() != null) {
LOG.debug("Trying to starting service L2");
if (MedtronicUtil.getPumpStatus().setNotInPreInit()) {
break;
}
if (MedtronicUtil.getPumpStatus() != null) {
LOG.debug("Starting Medtronic-RileyLink service");
if (MedtronicUtil.getPumpStatus().setNotInPreInit()) {
break;
}
}
}
}).start();
}
};
}
@Override
public void initPumpStatusData() {
LOG.error("Init Pump Status Data");
this.pumpStatusLocal = new MedtronicPumpStatus(pumpDescription);
MedtronicUtil.setPumpStatus(pumpStatusLocal);
pumpStatusLocal.refreshConfiguration();
//MedtronicUtil.setPumpStatus(pumpStatusLocal);
LOG.debug("initPumpStatusData: {}", this.pumpStatusLocal);
this.pumpStatus = pumpStatusLocal;
if (pumpStatusLocal.maxBasal != null)
@ -148,7 +147,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
pumpDescription.isExtendedBolusCapable = false;
pumpDescription.isSetBasalProfileCapable = false;
// unchangable
pumpDescription.tempBasalStyle = PumpDescription.PERCENT;
pumpDescription.tempDurationStep15mAllowed = false;
@ -159,9 +157,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
pumpDescription.supportsTDDs = true;
pumpDescription.needsManualTDDLoad = false;
//pumpStatusLocal.setNotInPreInit();
// set first Medtronic Pump Start
if (!SP.contains(MedtronicConst.Statistics.FirstPumpStart)) {
SP.putLong(MedtronicConst.Statistics.FirstPumpStart, System.currentTimeMillis());
@ -185,7 +180,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}).start();
//pumpStatusLocal.setNotInPreInit();
}
@ -210,12 +204,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
return false;
}
// we don't loadTDD
@Override
public PumpEnactResult loadTDDs() {
return OPERATION_NOT_SUPPORTED;
}
// Pump Plugin
@ -223,18 +211,22 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
return medtronicService != null;
}
public boolean isInitialized() {
return isServiceSet() && medtronicService.isInitialized();
}
// FIXME
public boolean isSuspended() {
return isServiceSet() && medtronicService.isSuspended();
}
public boolean isBusy() {
return isServiceSet() && medtronicService.isBusy();
}
public boolean isConnected() {
return isServiceSet() && medtronicService.isInitialized();
}
@ -249,31 +241,11 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
public void connect(String reason) {
// we don't use this.
// we connect to RileyLink on startup and keep connection opened, then connection to pump
// is established when needed.
}
public void disconnect(String reason) {
// see comment in connect
}
public void stopConnecting() {
// see comment in connect
}
// FIXME
@Override
public void getPumpStatus() {
if (this.pumpStatusLocal == null) {
// FIXME I don't know why this happens
LOG.debug("getPumpStatus: reset pumpStatusLocal ");
this.pumpStatusLocal = MedtronicUtil.getPumpStatus();
}
getMDTPumpStatus();
if (firstRun) {
initializePump(true);
@ -281,24 +253,20 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
refreshAnyStatusThatNeedsToBeRefreshed();
}
//LOG.debug("getPumpStatus: {}", this.pumpStatusLocal);
//LOG.debug("getPumpStatus: {}", MedtronicUtil.getPumpStatus());
//getMDTPumpStatus().setLastCommunicationToNow();
MainApp.bus().post(new EventMedtronicPumpValuesChanged());
}
public void resetStatusState() {
firstRun = true;
}
private void refreshAnyStatusThatNeedsToBeRefreshed() {
if (!doWeHaveAnyStatusNeededRefereshing()) {
return;
}
// TODO
boolean resetTime = false;
for (Map.Entry<MedtronicStatusRefreshType, Long> refreshType : statusRefreshMap.entrySet()) {
@ -321,21 +289,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
break;
}
}
}
if (resetTime)
pumpStatusLocal.setLastCommunicationToNow();
//LOG.error("MedtronicPumpPlugin::refreshAnyStatusThatNeedsToBeRefreshed NOT IMPLEMENTED.");
}
Map<MedtronicStatusRefreshType, Long> statusRefreshMap = new HashMap<>();
private boolean doWeHaveAnyStatusNeededRefereshing() {
@ -351,7 +312,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private void initializePump(boolean realInit) {
LOG.error("MedtronicPumpPlugin::initializePump NOT fully IMPLEMENTED.");
LOG.error("initializePump - start");
getMDTPumpStatus();
@ -360,13 +321,15 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
medtronicUIComm.executeCommand(MedtronicCommandType.PumpModel);
} else {
if (pumpStatusLocal.medtronicDeviceType != MedtronicUtil.getMedtronicPumpModel()) {
// TODO error
LOG.warn("Configured pump is not the same as one detected.");
Notification notification = new Notification(Notification.MEDTRONIC_PUMP_ALARM, MainApp.gs(R.string.medtronic_error_pump_type_set_differs_from_detected), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
}
}
// TODO this call might need to do deeper call (several pages)
// pump history handling - special, updates every 5 minutes ???
readPumpHistory();
//scheduleNextRefresh(MedtronicStatusRefreshType.PumpHistory);
// TODO rewrite reading of data to be done in background or different thread perhaps ??
@ -375,14 +338,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
medtronicUIComm.executeCommand(MedtronicCommandType.GetRemainingInsulin);
scheduleNextRefresh(MedtronicStatusRefreshType.RemainingInsulin, 10);
// TODO remaining power (1h)
// remaining power (1h)
medtronicUIComm.executeCommand(MedtronicCommandType.GetBatteryStatus);
scheduleNextRefresh(MedtronicStatusRefreshType.BatteryStatus, 20);
// configuration (once and then if history shows config changes)
medtronicUIComm.executeCommand(MedtronicCommandType.getSettings(MedtronicUtil.getMedtronicPumpModel()));
// TODO time (1h)
// time (1h)
medtronicUIComm.executeCommand(MedtronicCommandType.RealTimeClock);
scheduleNextRefresh(MedtronicStatusRefreshType.PumpTime, 30);
@ -390,18 +353,15 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD);
//if ()
// TODO handle if tunning was needed (more than 5 timeouts)
int errorCount = medtronicUIComm.getInvalidResponsesCount();
if (errorCount >= 5) {
LOG.error("Number of error counts was 5 or more. Starting tunning.");
medtronicUIComm.startTunning();
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
return;
}
pumpStatusLocal.setLastCommunicationToNow();
this.firstRun = false;
@ -411,13 +371,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public boolean isThisProfileSet(Profile profile) {
// FIXME refactor this, reread profile only if history says that profile has changed... This will
// delay change of profile.
if (!isConnected()) {
return true;
}
if (!hasBasalProfileChanged && getMDTPumpStatus().basalsByHour != null) {
return (!isBasalProfileInvalid);
}
MedtronicUITask responseTask = medtronicUIComm.executeCommand(MedtronicCommandType.GetBasalProfileSTD);
boolean invalid = false;
@ -457,6 +418,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
LOG.debug("Basal profile NO DATA");
}
isBasalProfileInvalid = invalid;
return (!invalid);
}
@ -478,7 +441,8 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
private MedtronicPumpStatus getMDTPumpStatus() {
if (pumpStatusLocal == null) {
LOG.warn("Reset Pump Status Local");
// FIXME I don't know why this happens
LOG.warn("!!!! Reset Pump Status Local");
pumpStatusLocal = MedtronicUtil.getPumpStatus();
}
@ -497,15 +461,25 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
LOG.error("MedtronicPumpPlugin::deliverBolus Not fully implemented - Just base command.");
// TODO should wait and display bolus delivery
MedtronicUITask responseTask = medtronicUIComm.executeCommand(MedtronicCommandType.SetBolus, detailedBolusInfo.insulin);
Boolean response = (Boolean) responseTask.returnData;
// TODO display bolus
// TODO change remaining insulin
if (response) {
// FIXME this needs to be fixed to read info from history
boolean treatmentCreated = TreatmentsPlugin.getPlugin().addToHistoryTreatment(detailedBolusInfo);
getMDTPumpStatus().reservoirRemainingUnits -= detailedBolusInfo.insulin; // we subtract insulin, exact amount will be visible with next remainingInsulin update.
incrementStatistics(detailedBolusInfo.isSMB ? MedtronicConst.Statistics.SMBBoluses : MedtronicConst.Statistics.StandardBoluses);
}
readPumpHistory();
return new PumpEnactResult().success(response).enacted(response);
@ -624,10 +598,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
}
@Override
public void stopBolusDelivering() {
private void incrementStatistics(String statsKey) {
long currentCount = SP.getLong(statsKey, 0L);
currentCount++;
SP.putLong(statsKey, currentCount);
}
// if enforceNew===true current temp basal is canceled and new TBR set (duration is prolonged),
// if false and the same rate is requested enacted=false and success=true is returned and TBR is not changed
@Override
@ -647,15 +625,24 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// TODO translate
return new PumpEnactResult().success(false).enacted(false).comment("Couldn't read current TBR.");
} else {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute: Current Basal: " + tbrCurrent.getDurationMinutes() + tbrCurrent.getInsulinRate());
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute: Current Basal: duration: {} min, rate={}", tbrCurrent.getDurationMinutes(), tbrCurrent.getInsulinRate());
}
// FIXME doesn't work correctly. Read current TBR first
if (!enforceNew) {
if (MedtronicUtil.isSame(tbrCurrent.getInsulinRate(), absoluteRate)) {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - No enforceNew and same rate. Exiting.");
return new PumpEnactResult().success(true).enacted(false);
boolean sameRate = true;
if (MedtronicUtil.isSame(0.0d, absoluteRate) && durationInMinutes > 0) {
// if rate is 0.0 and duration>0 then the rate is not the same
sameRate = false;
}
if (sameRate) {
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - No enforceNew and same rate. Exiting.");
return new PumpEnactResult().success(true).enacted(false);
}
}
// if not the same rate, we cancel and start new
}
@ -685,24 +672,42 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
Boolean response = (Boolean) responseTask.returnData;
LOG.info("MedtronicPumpPlugin::setTempBasalAbsolute - setTBR. Response: " + response);
if (response) {
// FIXME put this into UIPostProcessor
pumpStatusLocal.tempBasalStart = new Date();
pumpStatusLocal.tempBasalAmount = absoluteRate;
pumpStatusLocal.tempBasalLength = durationInMinutes;
// FIXME should be read from history
TemporaryBasal tempStart = new TemporaryBasal()
.date(System.currentTimeMillis())
.duration(durationInMinutes)
.absolute(absoluteRate)
.source(Source.USER);
TreatmentsPlugin.getPlugin().addToHistoryTempBasal(tempStart);
incrementStatistics(MedtronicConst.Statistics.TBRsSet);
}
readPumpHistory();
readPumpHistory(); // TODO maybe this is not needed here
MainApp.bus().post(new EventRefreshOverview("TBR"));
triggerUIChange();
return new PumpEnactResult().success(response).enacted(response);
}
private void readPumpHistory() {
LOG.error("MedtronicPumpPlugin::readPumpHistory NOT IMPLEMENTED.");
// TODO implement logic here
boolean relevantConfigurationChangeFound = false;
// TODO implement logic here fror config changes
relevantConfigurationChangeFound = false;
// TODO implement logic to see if Basalrates changed from last time
hasBasalProfileChanged = true;
// TODO reset next refresh date, also set refreshdate if configuration changed
scheduleNextRefresh(MedtronicStatusRefreshType.PumpHistory);
@ -719,6 +724,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
scheduleNextRefresh(refreshType, 0);
}
private void scheduleNextRefresh(MedtronicStatusRefreshType refreshType, int additionalTimeInMinutes) {
switch (refreshType) {
@ -749,6 +755,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
return System.currentTimeMillis() + getTimeInMs(minutes);
}
private long getTimeInMs(int minutes) {
return minutes * 60 * 1000L;
}
@ -757,10 +764,9 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
// TODO
@Override
public PumpEnactResult setExtendedBolus(Double insulin, Integer durationInMinutes) {
LOG.error("MedtronicPumpPlugin::setExtendedBolus NOT IMPLEMENTED.");
LOG.error("MedtronicPumpPlugin::setExtendedBolus NOT IMPLEMENTED YET.");
return null;
//return OPERATION_NOT_YET_SUPPORTED;
return OPERATION_NOT_YET_SUPPORTED;
}
@ -769,6 +775,12 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
if (responseTask.hasData()) {
TempBasalPair tbr = (TempBasalPair) responseTask.returnData;
// we sometimes get rate returned even if TBR is no longer running
if (tbr.getDurationMinutes() == 0) {
tbr.setInsulinRate(0.0d);
}
return tbr;
} else {
return null;
@ -779,8 +791,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public PumpEnactResult cancelTempBasal(boolean enforceNew) {
LOG.error("MedtronicPumpPlugin::cancelTempBasal Not fully implemented - Just base command.");
LOG.info("cancelTempBasal - started");
TempBasalPair tbrCurrent = readTBR();
@ -803,7 +814,6 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
} else {
LOG.info("MedtronicPumpPlugin::cancelTempBasal - Cancel TBR failed.");
}
readPumpHistory();
@ -812,30 +822,59 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
// TODO not supported but we will display message to user that he/she should do it on the pump
@Override
public PumpEnactResult cancelExtendedBolus() {
LOG.error("MedtronicPumpPlugin::cancelExtendedBolus NOT IMPLEMENTED.");
return null;
}
// OPERATIONS not supported by Pump
@Override
public PumpEnactResult setTempBasalPercent(Integer percent, Integer durationInMinutes, Profile profile, boolean enforceNew) {
LOG.error("MedtronicPumpPlugin::setTempBasalPercent NOT IMPLEMENTED.");
return null;
}
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
LOG.warn("MedtronicPumpPlugin::setNewBasalProfile NOT IMPLEMENTED.");
LOG.warn("MedtronicPumpPlugin::setNewBasalProfile NOT IMPLEMENTED YET.");
return new PumpEnactResult().success(false).enacted(false).comment(MainApp.gs(R.string.medtronic_cmd_profile_not_set));
}
// OPERATIONS not supported by Pump or Plugin
@Override
public PumpEnactResult cancelExtendedBolus() {
LOG.warn("cancelExtendedBolus - operation 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;
}
// we don't loadTDD
@Override
public PumpEnactResult loadTDDs() {
return OPERATION_NOT_SUPPORTED;
}
public void connect(String reason) {
// we don't use this.
// we connect to RileyLink on startup and keep connection opened, then connection to pump
// is established when needed.
}
public void disconnect(String reason) {
// see comment in connect
}
public void stopConnecting() {
// see comment in connect
}
@Override
public void stopBolusDelivering() {
// Medtronic doesn't have Bolus cancel, so we fake it.
}
}

View file

@ -13,6 +13,7 @@ import java.util.Map;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkCommunicationManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RLMessage;
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.utils.ByteUtil;
@ -70,6 +71,13 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
@Override
public <E extends RLMessage> E createResponseMessage(byte[] payload, Class<E> clazz) {
PumpMessage pumpMessage = new PumpMessage(payload);
return (E) pumpMessage;
}
// FIXME must not call getPumpModel !!!!!!!!!!!!!
@Override
public boolean tryToConnectToDevice() {
@ -455,6 +463,17 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
// }
protected PumpMessage sendAndListen(RLMessage msg) {
return sendAndListen(msg, 4000); // 2000
}
// All pump communications go through this function.
protected PumpMessage sendAndListen(RLMessage msg, int timeout_ms) {
return sendAndListen(msg, timeout_ms, PumpMessage.class);
}
private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType) {
return sendAndGetResponseWithCheck(commandType, null);
@ -703,6 +722,43 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
// TODO generateRawData (check if it works correctly) and test
public Boolean setBasalProfile(BasalProfile basalProfile) {
// [RileyLinkDevice] ======================== Save Basal Profile ===========================
// [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 1 bytes), 0, 0.180000, 3)
// [PeripheralManager+RileyLink] RL Send: 19050000000000000000b4030000a9659a6b19b199c555b2c000
// [PeripheralManager+RileyLink] RL Recv(single): bb
// [PeripheralManager+RileyLink] RileyLink response: PacketResponse(code: RileyLinkBLEKit.ResponseCode.commandInterrupted, packet: nil)
// [PeripheralManager+RileyLink] RL Recv(single): dd0dbca9659a6b19b156655534d500
// [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 65 bytes), 0, 0.180000, 3)
// [PeripheralManager+RileyLink] RL Send: 79050000000000000000b4030000a9659a6b19b199c571c9a555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556000
// 2018-06-30 15:03:13.333962-0500 Loop[24609:13622692] [PeripheralManager+RileyLink] RL Recv(single): dd10bda9659a6b19b156655534d500
// 2018-06-30 15:03:13.334927-0500 Loop[24609:13622484] [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 65 bytes), 0, 0.180000, 3)
// 2018-06-30 15:03:13.337923-0500 Loop[24609:13622484] [PeripheralManager+RileyLink] RL Send: 79050000000000000000b4030000a9659a6b19b199c5725555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555ac000
// 2018-06-30 15:03:14.114024-0500 Loop[24609:13622486] [PeripheralManager+RileyLink] RL Recv(single): dd0ebea9659a6b19b156655534d500
// 2018-06-30 15:03:14.115017-0500 Loop[24609:13622484] [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 65 bytes), 0, 0.180000, 3)
// 2018-06-30 15:03:14.117600-0500 Loop[24609:13622484] [PeripheralManager+RileyLink] RL Send: 79050000000000000000b4030000a9659a6b19b199c6a355555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555570e000
// 2018-06-30 15:03:15.644502-0500 Loop[24609:13622692] [PeripheralManager+RileyLink] RL Recv(single): dd0ebfa9659a6b19b156655534d500
// 2018-06-30 15:03:15.645388-0500 Loop[24609:13622484] [RileyLinkDevice] ------------------------ Save Basal Profile ---------------------------
// 2018-06-30 15:03:12.167767-0500 Loop[24609:13622484] [RileyLinkDevice] ======================== Save Basal Profile ===========================
// 2018-06-30 15:03:12.168652-0500 Loop[24609:13622484] [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 1 bytes), 0, 0.180000, 3)
// 2018-06-30 15:03:12.169518-0500 Loop[24609:13622484] [PeripheralManager+RileyLink] RL Send: 19050000000000000000b4030000a9659a6b19b199c555b2c000
// 2018-06-30 15:03:12.463546-0500 Loop[24609:13622486] [PeripheralManager+RileyLink] RL Recv(single): bb
// 2018-06-30 15:03:12.463954-0500 Loop[24609:13622486] [PeripheralManager+RileyLink] RileyLink response: PacketResponse(code: RileyLinkBLEKit.ResponseCode.commandInterrupted, packet: nil)
// 2018-06-30 15:03:12.554051-0500 Loop[24609:13622486] [PeripheralManager+RileyLink] RL Recv(single): dd0dbca9659a6b19b156655534d500
// 2018-06-30 15:03:12.555175-0500 Loop[24609:13622484] [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 65 bytes), 0, 0.180000, 3)
// 2018-06-30 15:03:12.557953-0500 Loop[24609:13622484] [PeripheralManager+RileyLink] RL Send: 79050000000000000000b4030000a9659a6b19b199c571c9a555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555556000
// 2018-06-30 15:03:13.333962-0500 Loop[24609:13622692] [PeripheralManager+RileyLink] RL Recv(single): dd10bda9659a6b19b156655534d500
// 2018-06-30 15:03:13.334927-0500 Loop[24609:13622484] [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 65 bytes), 0, 0.180000, 3)
// 2018-06-30 15:03:13.337923-0500 Loop[24609:13622484] [PeripheralManager+RileyLink] RL Send: 79050000000000000000b4030000a9659a6b19b199c5725555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555ac000
// 2018-06-30 15:03:14.114024-0500 Loop[24609:13622486] [PeripheralManager+RileyLink] RL Recv(single): dd0ebea9659a6b19b156655534d500
// 2018-06-30 15:03:14.115017-0500 Loop[24609:13622484] [PumpMessageSender] getResponse(PumpMessage(carelink, setBasalProfileStandard, 3 bytes, 65 bytes), 0, 0.180000, 3)
// 2018-06-30 15:03:14.117600-0500 Loop[24609:13622484] [PeripheralManager+RileyLink] RL Send: 79050000000000000000b4030000a9659a6b19b199c6a355555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555570e000
// 2018-06-30 15:03:15.644502-0500 Loop[24609:13622692] [PeripheralManager+RileyLink] RL Recv(single): dd0ebfa9659a6b19b156655534d500
// 2018-06-30 15:03:15.645388-0500 Loop[24609:13622484] [RileyLinkDevice] ------------------------ Save Basal Profile ---------------------------
//byte[] body = basalProfile.generateRawData();
byte[] body = new byte[]{32, 0, 0, 38, 0, 13, 44, 0, 19, 38, 0, 28};

View file

@ -171,11 +171,17 @@ public class MedtronicConverter {
protected Float decodeRemainingInsulin(byte[] rawData) {
//float value = MedtronicUtil.makeUnsignedShort(rawData[0], rawData[1]) / 10.0f;
int startIdx = 0;
float value = ByteUtil.toInt(rawData[0], rawData[1]) / 10.0f;
int strokes = pumpModel.getBolusStrokes();
System.out.println("Remaining insulin: " + value);
if (strokes == 40) {
startIdx = 2;
}
float value = ByteUtil.toInt(rawData[startIdx], rawData[startIdx + 1]) / (1.0f * strokes);
LOG.debug("Remaining insulin: " + value);
return value;
}

View file

@ -2,7 +2,7 @@ package info.nightscout.androidaps.plugins.PumpMedtronic.comm.message;
import android.util.Log;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RLMessage;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.data.RLMessage;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpCommon.utils.HexDump;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
@ -111,7 +111,7 @@ public class PumpMessage implements RLMessage {
// check Old Way
boolean oldWay = false;
for(int i = (length + 1); i < data.length; i++) {
for (int i = (length + 1); i < data.length; i++) {
if (data[i] != 0x00) {
oldWay = true;
}

View file

@ -65,8 +65,6 @@ public class MedtronicUIPostprocessor {
case RealTimeClock: {
processTime(uiTask);
}
break;
@ -83,8 +81,8 @@ public class MedtronicUIPostprocessor {
case PumpModel: {
if (pumpStatus.medtronicDeviceType != MedtronicUtil.getMedtronicPumpModel()) {
// TODO error
LOG.error("Configured pump is different then pump detected !!");
LOG.warn("Configured pump is different then pump detected !");
sendNotification(R.string.medtronic_error_pump_type_set_differs_from_detected, Notification.NORMAL);
}
}
break;
@ -122,16 +120,21 @@ public class MedtronicUIPostprocessor {
if (diff >= 10 * 60 * 1000) {
LOG.debug("Pump clock needs update, pump time: " + ldt + " (" + ldt + ")");
Notification notification = new Notification(Notification.MEDTRONIC_PUMP_ALARM, MainApp.gs(R.string.combo_notification_check_time_date), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
sendNotification(R.string.combo_notification_check_time_date, Notification.URGENT);
} else if (diff >= 4 * 60 * 1000) {
LOG.debug("Pump clock needs update, pump time: " + ldt + " (" + ldt + ")");
Notification notification = new Notification(Notification.MEDTRONIC_PUMP_ALARM, MainApp.gs(R.string.combo_notification_check_time_date), Notification.NORMAL);
MainApp.bus().post(new EventNewNotification(notification));
sendNotification(R.string.combo_notification_check_time_date, Notification.NORMAL);
}
}
private void sendNotification(int resourceId, int notificationUrgencyType) {
Notification notification = new Notification(Notification.MEDTRONIC_PUMP_ALARM, MainApp.gs(resourceId), notificationUrgencyType);
MainApp.bus().post(new EventNewNotification(notification));
}
private void postProcessSettings(MedtronicUITask uiTask) {
Map<String, PumpSettingDTO> settings = (Map<String, PumpSettingDTO>) uiTask.returnData;
@ -141,18 +144,15 @@ public class MedtronicUIPostprocessor {
// check profile
if (!"Yes".equals(settings.get("PCFG_BASAL_PROFILES_ENABLED").value)) {
//Notification notification = new Notification(Notification.PROFILE_NOT_SET_NOT_INITIALIZED, MainApp.gs(R.string.pumpNotInitializedProfileNotSet), Notification.URGENT);
//MainApp.bus().post(new EventNewNotification(notification));
// TODO profile not enabled
LOG.error("Basal profiles are not enabled on pump.");
sendNotification(R.string.medtronic_error_pump_basal_profiles_not_enabled, Notification.URGENT);
} else {
checkValue = settings.get("PCFG_ACTIVE_BASAL_PROFILE");
if (!"STD".equals(checkValue.value)) {
// TODO wrong profile
LOG.error("Basal profile set on pump is incorrect (must be STD).");
sendNotification(R.string.medtronic_error_pump_incorrect_basal_profile_selected, Notification.URGENT);
}
}
@ -161,8 +161,8 @@ public class MedtronicUIPostprocessor {
checkValue = settings.get("PCFG_TEMP_BASAL_TYPE");
if (!"Units".equals(checkValue.value)) {
// TODO wrong TBR type
LOG.error("Wrong TBR type set on pump (must be Absolute).");
sendNotification(R.string.medtronic_error_pump_wrong_tbr_type_set, Notification.URGENT);
}
// MAXes
@ -170,26 +170,17 @@ public class MedtronicUIPostprocessor {
checkValue = settings.get("PCFG_MAX_BOLUS");
if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), pumpStatus.maxBolus)) {
// TODO wrong max Bolus type
LOG.error("Wrong Max Bolus set on Pump (must be {}).", pumpStatus.maxBolus);
sendNotification(R.string.medtronic_error_pump_wrong_max_bolus_set, Notification.NORMAL);
}
checkValue = settings.get("PCFG_MAX_BASAL");
double maxSet = Double.parseDouble(checkValue.value);
if (!MedtronicUtil.isSame(Double.parseDouble(checkValue.value), pumpStatus.maxBasal)) {
// TODO wrong max Bolus type
LOG.error("Wrong Max Basal set on Pump (must be {}).", pumpStatus.maxBasal);
sendNotification(R.string.medtronic_error_pump_wrong_max_basal_set, Notification.NORMAL);
}
//addSettingToMap("PCFG_MAX_BOLUS", "" + decodeMaxBolus(rd), PumpConfigurationGroup.Bolus, map);
//addSettingToMap("PCFG_MAX_BASAL", "" + decodeBasalInsulin(ByteUtil.makeUnsignedShort(rd[getSettingIndexMaxBasal()], rd[getSettingIndexMaxBasal() + 1])), PumpConfigurationGroup.Basal, map);
//addSettingToMap("PCFG_BASAL_PROFILES_ENABLED", parseResultEnable(rd[10]), PumpConfigurationGroup.Basal, map);
//addSettingToMap("PCFG_ACTIVE_BASAL_PROFILE", patt, PumpConfigurationGroup.Basal, map);
//addSettingToMap("PCFG_TEMP_BASAL_TYPE", rd[14] != 0 ? "Percent" : "Units", PumpConfigurationGroup.Basal, map);
}

View file

@ -27,10 +27,9 @@ public class MedtronicUITask {
boolean invalid = false;
public MedtronicUITask(MedtronicCommandType commandType) {
this(commandType, null);
this.commandType = commandType;
}
public MedtronicUITask(MedtronicCommandType commandType, Object... parameters) {
this.commandType = commandType;
this.parameters = parameters;

View file

@ -61,6 +61,7 @@ public enum MedtronicCommandType implements Serializable //, MinimedCommandTypeI
RealTimeClock(112, "Real Time Clock", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, 7), // 0x70
GetBatteryStatus(0x72, "Get Battery Status", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters), //
// GetBattery((byte) 0x72), //
GetRemainingInsulin(0x73, "Read Remaining Insulin", MinimedTargetType.PumpConfiguration, MedtronicDeviceType.All, MinimedCommandParameterType.NoParameters, 2), // 115

View file

@ -120,17 +120,17 @@ public class MedtronicPumpStatus extends PumpStatus {
private void createMedtronicPumpMap() {
medtronicPumpMap = new HashMap<>();
medtronicPumpMap.put("512", PumpType.Minimed_512_712);
medtronicPumpMap.put("712", PumpType.Minimed_512_712);
medtronicPumpMap.put("515", PumpType.Minimed_515_715);
medtronicPumpMap.put("715", PumpType.Minimed_515_715);
medtronicPumpMap.put("512", PumpType.Medtronic_512_712);
medtronicPumpMap.put("712", PumpType.Medtronic_512_712);
medtronicPumpMap.put("515", PumpType.Medtronic_515_715);
medtronicPumpMap.put("715", PumpType.Medtronic_515_715);
medtronicPumpMap.put("522", PumpType.Minimed_522_722);
medtronicPumpMap.put("722", PumpType.Minimed_522_722);
medtronicPumpMap.put("523", PumpType.Minimed_523_723);
medtronicPumpMap.put("723", PumpType.Minimed_523_723);
medtronicPumpMap.put("554", PumpType.Minimed_554_754_Veo);
medtronicPumpMap.put("754", PumpType.Minimed_554_754_Veo);
medtronicPumpMap.put("522", PumpType.Medtronic_522_722);
medtronicPumpMap.put("722", PumpType.Medtronic_522_722);
medtronicPumpMap.put("523", PumpType.Medtronic_523_723_Revel);
medtronicPumpMap.put("723", PumpType.Medtronic_523_723_Revel);
medtronicPumpMap.put("554", PumpType.Medtronic_554_754_Veo);
medtronicPumpMap.put("754", PumpType.Medtronic_554_754_Veo);
frequencies = new String[2];
frequencies[0] = MainApp.gs(R.string.medtronic_pump_frequency_us);

View file

@ -19,6 +19,7 @@ import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.DetailedBolusInfo;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult;
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.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.RFSpy;
@ -196,11 +197,6 @@ public class RileyLinkMedtronicService extends RileyLinkService {
}
}
@Override
public void loadPumpCommunicationManager() {
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
@ -246,22 +242,20 @@ public class RileyLinkMedtronicService extends RileyLinkService {
RileyLinkUtil.setRileyLinkBLE(rileyLinkBLE);
// init rileyLinkCommunicationManager
pumpCommunicationManager = new MedtronicCommunicationManager(context, rfspy, rileyLinkTargetFrequency);
medtronicCommunicationManager = (MedtronicCommunicationManager) pumpCommunicationManager;
// init rileyLinkCommunicationManager
medtronicCommunicationManager = new MedtronicCommunicationManager(context, rfspy, rileyLinkTargetFrequency);
// FIXME remove
//pumpHistoryManager = new PumpHistoryManager(getApplicationContext());
}
public MedtronicCommunicationManager getMedtronicCommunicationManager() {
@Override
public RileyLinkCommunicationManager getDeviceCommunicationManager() {
return this.medtronicCommunicationManager;
}
public void setPumpIDString(String pumpID) {
if (pumpID.length() != 6) {
LOG.error("setPumpIDString: invalid pump id string: " + pumpID);

View file

@ -20,11 +20,11 @@ public class MedtronicConst {
public class Statistics {
public static final String StatsPrefix = "medtronic_";
static final String StatsPrefix = "medtronic_";
static final String TBRsSet = StatsPrefix + "tbrs_set";
static final String StandardBoluses = StatsPrefix + "std_boluses_delivered";
static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered";
public static final String TBRsSet = StatsPrefix + "tbrs_set";
public static final String StandardBoluses = StatsPrefix + "std_boluses_delivered";
public static final String SMBBoluses = StatsPrefix + "smb_boluses_delivered";
public static final String FirstPumpStart = Prefix + "first_pump_use";
public static final String LastGoodPumpCommunicationTime = Prefix + "lastGoodPumpCommunicationTime";

View file

@ -489,16 +489,17 @@
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/medtronic_viewprofile"
android:id="@+id/medtronic_refresh"
style="@style/ButtonSmallFontStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawableTop="@drawable/icon_danarprofile"
android:drawableTop="@drawable/icon_actions_refill"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:text="@string/danar_viewprofile" />
android:text="@string/combo_refresh" />
<Button

View file

@ -1060,52 +1060,45 @@
<string name="location_yes">Enable</string>
<string name="location_no">No</string>
<!-- Medtronic -->
<!-- Medtronic (MDT) - Base -->
<string name="medtronic_name" translatable="false">Medtronic</string>
<string name="medtronic_name_short" translatable="false">MDT</string>
<!-- MDT Configuration -->
<string name="medtronic_serial_number">Pump Serial Number</string>
<string name="medtronic_pump_type">Pump Type</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_basal">Max Basal on Pump</string>
<string name="medtronic_errors">Errors</string>
<string name="medtronic_error_serial_not_set">Serial # not set.</string>
<string name="medtronic_error_serial_invalid">Serial # invalid.</string>
<string name="medtronic_error_pump_type_not_set">Pump Type not set.</string>
<string name="medtronic_error_pump_type_invalid">Pump Type unsupported.</string>
<string name="medtronic_error_pump_frequency_not_set">Pump Frequency not set.</string>
<string name="medtronic_error_pump_frequency_invalid">Pump Frequency unsupported.</string>
<string name="medtronic_error_rileylink_address_invalid">RileyLink Address invalid.</string>
<string name="medtronic_pump_frequency_us">US (916 MHz)</string>
<string name="medtronic_pump_frequency_worldwide">Worldwide (868 Mhz)</string>
<string name="rileylink_mac_address">RileyLink MAC Address</string>
<string name="rileylink_scanner_selected_device">Selected</string>
<string name="rileylink_scanner_scan">Scan</string>
<string name="rileylink_scanner_title">RileyLink BLE Scan</string>
<string name="rileylink_scanner_scan_menu">Scan for RileyLink</string>
<!-- RL Status Page -->
<string name="rileylink_settings_tab1">Settings</string>
<string name="rileylink_settings_tab2">History</string>
<string name="rileylink_settings_tab3">Device</string>
<string name="rileylink_status">RileyLink Status</string>
<string name="medtronic_pump_status">Pump Status</string>
<string name="rileylink_settings_title">RileyLink Settings</string>
<string name="title_activity_rileylink_settings">RileyLink Settings</string>
<string name="rileylink_title">Riley Link</string>
<string name="rileylink_configured_address">Configured Address</string>
<string name="rileylink_connected_device">Connected Device</string>
<string name="rileylink_connection_status">Connection Status</string>
<string name="rileylink_connection_error">Connection Error</string>
<string name="rileylink_device">Device</string>
<string name="rileylink_device_type">Device Type</string>
<string name="rileylink_device_model">Device Model</string>
<string name="rileylink_last_used_frequency">Last used frequency</string>
<string name="rileylink_last_device_contact">Last device contact</string>
<string name="rileylink_settings_tab1">Settings</string>
<string name="rileylink_settings_tab2">History</string>
<string name="rileylink_status">RileyLink Status</string>
<string name="medtronic_pump_status">Pump Status</string>
<!-- RL State -->
<string name="rileylink_state_bt_init">Bluetooth Initializing…</string>
<string name="rileylink_state_bt_error">Bluetooth Error</string>
<string name="rileylink_state_bt_ready">Bluetooth Ready</string>
@ -1115,6 +1108,8 @@
<string name="rileylink_state_pc_tune_up">Tunning up RileyLink and Pump</string>
<string name="rileylink_state_pc_error">Problem connecting to Pump</string>
<string name="rileylink_state_connected">Connected</string>
<!-- RL Errors -->
<string name="rileylink_error_not_rl">Device is not RileyLink</string>
<string name="rileylink_error_unreachable">RileyLink unreachable</string>
<string name="rileylink_error_bt_disabled">Bluetooth disabled</string>
@ -1123,7 +1118,26 @@
<string name="rileylink_error_pump_unreachable">Pump unreachable</string>
<string name="rileylink_error_pod_unreachable">Pod unreachable</string>
<string name="medtronic_cmd_profile_not_set">Remote Basal profile setting is not supported. Please modify Basal profile on your pump manually.</string>
<!-- MDT Errors -->
<string name="medtronic_errors">Errors</string>
<string name="medtronic_error_serial_not_set">Serial # not set.</string>
<string name="medtronic_error_serial_invalid">Serial # invalid.</string>
<string name="medtronic_error_pump_type_not_set">Pump Type not set.</string>
<string name="medtronic_error_pump_type_invalid">Pump Type unsupported.</string>
<string name="medtronic_error_pump_frequency_not_set">Pump Frequency not set.</string>
<string name="medtronic_error_pump_frequency_invalid">Pump Frequency unsupported.</string>
<string name="medtronic_error_rileylink_address_invalid">RileyLink Address invalid.</string>
<string name="medtronic_error_pump_type_set_differs_from_detected">Pump type detected is not the same as configured type.</string>
<string name="medtronic_error_pump_basal_profiles_not_enabled">Basal profiles are not enabled on pump.</string>
<string name="medtronic_error_pump_incorrect_basal_profile_selected">Basal profile set on pump is incorrect (must be STD).</string>
<string name="medtronic_error_pump_wrong_tbr_type_set">Wrong TBR type set on pump (must be Absolute).</string>
<string name="medtronic_error_pump_wrong_max_bolus_set" formatted="false">Wrong Max Bolus set on Pump (must be %.2f).</string>
<string name="medtronic_error_pump_wrong_max_basal_set" formatted="false">Wrong Max Basal set on Pump (must be %.2f).</string>
<string name="xxx">xxx</string>
<!-- MDT Pump Status -->
<string name="medtronic_pump_status_never_contacted">Never contacted</string>
<string name="medtronic_pump_status_waking_up">Waking up</string>
<string name="medtronic_pump_status_error_comm">Error with communication</string>
@ -1131,4 +1145,8 @@
<string name="medtronic_pump_status_problem_contacting">Problem contacting Pump</string>
<string name="medtronic_pump_status_invalid_config">Invalid configuration</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>
</resources>