- refactored Broadcast receiving
- implementation of SetProfile finished
- added additional null checking in RadioResponse class
This commit is contained in:
Andy Rozman 2018-10-25 16:22:31 +01:00
parent 43f2f69133
commit 03e38158f4
21 changed files with 949 additions and 610 deletions

View file

@ -68,6 +68,7 @@ import info.nightscout.androidaps.plugins.PumpDanaRS.DanaRSPlugin;
import info.nightscout.androidaps.plugins.PumpDanaRv2.DanaRv2Plugin;
import info.nightscout.androidaps.plugins.PumpInsight.InsightPlugin;
import info.nightscout.androidaps.plugins.PumpMDI.MDIPlugin;
import info.nightscout.androidaps.plugins.PumpMedtronic.MedtronicPumpPlugin;
import info.nightscout.androidaps.plugins.PumpVirtual.VirtualPumpPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityAAPSPlugin;
import info.nightscout.androidaps.plugins.Sensitivity.SensitivityOref0Plugin;
@ -174,8 +175,10 @@ public class MainApp extends Application {
if (Config.PUMPDRIVERS)
pluginsList.add(DanaRSPlugin.getPlugin());
pluginsList.add(CareportalPlugin.getPlugin());
if (Config.PUMPDRIVERS && engineeringMode)
if (Config.PUMPDRIVERS && engineeringMode) {
pluginsList.add(InsightPlugin.getPlugin()); // <-- Enable Insight plugin here
pluginsList.add(MedtronicPumpPlugin.getPlugin());
}
if (Config.PUMPDRIVERS)
pluginsList.add(ComboPlugin.getPlugin());
if (Config.MDI)

View file

@ -211,7 +211,7 @@ public abstract class RileyLinkCommunicationManager {
byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData);
RFSpyResponse resp = rfspy.transmitThenReceive(new RadioPacket(pumpMsgContent), (byte)0, (byte)0,
(byte)0, (byte)0, 500, (byte)0);
(byte)0, (byte)0, 1000, (byte)0);
if (resp.wasTimeout()) {
LOG.error("scanForPump: Failed to find pump at frequency {}", frequencies[i]);
} else if (resp.looksLikeRadioPacket()) {

View file

@ -157,7 +157,8 @@ public class RileyLinkUtil {
public static boolean sendNotification(ServiceNotification notification, Integer clientHashcode) {
return RileyLinkUtil.rileyLinkService.sendNotification(notification, clientHashcode);
// return RileyLinkUtil.rileyLinkIPCConnection.sendNotification(notification, clientHashcode);
return false;
}
@ -200,6 +201,10 @@ public class RileyLinkUtil {
// RileyLinkUtil.rileyLinkIPCConnection = rileyLinkIPCConnection;
// }
// public static RileyLinkIPCConnection getRileyLinkIPCConnection() {
// return RileyLinkUtil.rileyLinkIPCConnection;
// }
public static RileyLinkTargetFrequency getRileyLinkTargetFrequency() {
return RileyLinkUtil.rileyLinkTargetFrequency;
}
@ -217,6 +222,7 @@ public class RileyLinkUtil {
}
@Deprecated
public static BleAdvertisedData parseAdertisedData(byte[] advertisedData) {
List<UUID> uuids = new ArrayList<UUID>();
String name = null;

View file

@ -11,6 +11,7 @@ import info.nightscout.androidaps.plugins.PumpCommon.utils.CRC;
/**
* Created by geoff on 7/31/15.
*/
// TODO refactor this DRY
public class RFTools {
public static final byte[] codes = new byte[] { 21, 49, 50, 35, 52, 37, 38, 22, 26, 25, 42, 11, 44, 13, 14, 28 };

View file

@ -100,8 +100,17 @@ public class RadioResponse {
decodedPayload = encodedPayload;
break;
case FourByteSixByte:
LOG.debug("encodedPayload: {}", ByteUtil.getHex(encodedPayload));
byte[] decodeThis = RFTools.decode4b6b(encodedPayload);
LOG.debug("decodedPayload: {}", ByteUtil.getHex(decodeThis));
decodedOK = true;
if (decodeThis == null || decodeThis.length == 0) {
LOG.error("Decoded payload length is zero.");
decodedOK = false;
return;
}
decodedPayload = ByteUtil.substring(decodeThis, 0, decodeThis.length - 1);
receivedCRC = decodeThis[decodeThis.length - 1];
byte calculatedCRC = CRC.crc8(decodedPayload);

View file

@ -0,0 +1,296 @@
package info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service;
/**
* Created by andy on 10/23/18.
*/
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkConst;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.RileyLinkUtil;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.ble.defs.RileyLinkFirmwareVersion;
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.tasks.DiscoverGattServicesTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.InitializePumpManagerTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTask;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTaskExecutor;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.WakeAndTuneTask;
import info.nightscout.utils.SP;
/**
* I added this class outside of RileyLinkService, because for now it's very important part of RL framework and
* where we get a lot of problems. Especially merging between AAPS and RileyLinkAAPS. I might put it back at
* later time
*/
public class RileyLinkBroadcastReceiver extends BroadcastReceiver {
private static final Logger LOG = LoggerFactory.getLogger(RileyLinkBroadcastReceiver.class);
RileyLinkService serviceInstance;
// protected RileyLinkIPCConnection rileyLinkIPCConnection;
protected Map<String, List<String>> broadcastIdentifiers = null;
String deviceSpecificPrefix;
Context context;
public RileyLinkBroadcastReceiver(RileyLinkService serviceInstance, Context context) {
this.serviceInstance = serviceInstance;
this.context = context;
// TODO remove in AAPS -- Andy
// rileyLinkIPCConnection = new RileyLinkIPCConnection(context);
// RileyLinkUtil.setRileyLinkIPCConnection(rileyLinkIPCConnection);
createBroadcastIdentifiers();
}
private void createBroadcastIdentifiers() {
this.broadcastIdentifiers = new HashMap<>();
// Bluetooth
this.broadcastIdentifiers.put("Bluetooth", Arrays.asList( //
RileyLinkConst.Intents.BluetoothConnected, //
RileyLinkConst.Intents.BluetoothReconnected, //
RileyLinkConst.Intents.BluetoothReconnected));
// TuneUp
this.broadcastIdentifiers.put("TuneUp", Arrays.asList( //
// RT2Const.IPC.MSG_PUMP_tunePump, //
// RT2Const.IPC.MSG_PUMP_quickTune, //
RileyLinkConst.IPC.MSG_PUMP_tunePump, //
RileyLinkConst.IPC.MSG_PUMP_quickTune));
// RileyLink
this.broadcastIdentifiers.put("RileyLink", Arrays.asList( //
RileyLinkConst.Intents.RileyLinkDisconnected, //
RileyLinkConst.Intents.RileyLinkReady, //
RileyLinkConst.Intents.RileyLinkDisconnected, //
RileyLinkConst.Intents.RileyLinkNewAddressSet, //
RileyLinkConst.Intents.RileyLinkDisconnect));
// Device Specific
deviceSpecificPrefix = serviceInstance.getDeviceSpecificBroadcastsIdentifierPrefix();
// Application specific
// this.broadcastIdentifiers.put("AppSpecific", Arrays.asList( //
// RT2Const.serviceLocal.ipcBound, //
// RT2Const.IPC.MSG_ServiceCommand, //
// RT2Const.serviceLocal.INTENT_sessionCompleted));
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
LOG.error("onReceive: received null intent");
} else {
String action = intent.getAction();
if (action == null) {
LOG.error("onReceive: null action");
} else {
LOG.debug("Received Broadcast: " + action);
if (!processBluetoothBroadcasts(action) && //
!processRileyLinkBroadcasts(action) && //
!processTuneUpBroadcasts(action) && //
!processDeviceSpecificBroadcasts(action, intent) && //
!processApplicationSpecificBroadcasts(action, intent) //
) {
LOG.error("Unhandled broadcast: action=" + action);
}
}
}
}
public void registerBroadcasts() {
IntentFilter intentFilter = new IntentFilter();
for (Map.Entry<String, List<String>> stringListEntry : broadcastIdentifiers.entrySet()) {
for (String intentKey : stringListEntry.getValue()) {
System.out.println("Intent: " + intentKey);
intentFilter.addAction(intentKey);
}
}
if (deviceSpecificPrefix != null) {
serviceInstance.registerDeviceSpecificBroadcasts(intentFilter);
}
LocalBroadcastManager.getInstance(context).registerReceiver(this, intentFilter);
}
private boolean processRileyLinkBroadcasts(String action) {
if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) {
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
RileyLinkUtil
.setServiceState(RileyLinkServiceState.BluetoothReady, RileyLinkError.RileyLinkUnreachable);
} else {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled);
}
return true;
} else if (action.equals(RileyLinkConst.Intents.RileyLinkReady)) {
LOG.warn("MedtronicConst.Intents.RileyLinkReady");
// sendIPCNotification(RT2Const.IPC.MSG_note_WakingPump);
this.serviceInstance.rileyLinkBLE.enableNotifications();
this.serviceInstance.rfspy.startReader(); // call startReader from outside?
this.serviceInstance.rfspy.initializeRileyLink();
String bleVersion = this.serviceInstance.rfspy.getBLEVersionCached();
RileyLinkFirmwareVersion rlVersion = this.serviceInstance.rfspy.getRLVersionCached();
LOG.debug("RfSpy version (BLE113): " + bleVersion);
this.serviceInstance.rileyLinkServiceData.versionBLE113 = bleVersion;
LOG.debug("RfSpy Radio version (CC110): " + rlVersion.name());
this.serviceInstance.rileyLinkServiceData.versionCC110 = rlVersion;
ServiceTask task = new InitializePumpManagerTask(RileyLinkUtil.getTargetDevice());
ServiceTaskExecutor.startTask(task);
LOG.info("Announcing RileyLink open For business");
return true;
} else if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) {
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
RileyLinkUtil
.setServiceState(RileyLinkServiceState.BluetoothReady, RileyLinkError.RileyLinkUnreachable);
} else {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError, RileyLinkError.BluetoothDisabled);
}
return true;
} 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);
this.serviceInstance.reconfigureRileyLink(RileylinkBLEAddress);
// MainApp.getServiceClientConnection().setThisRileylink(RileylinkBLEAddress);
}
return true;
} else if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnect)) {
this.serviceInstance.disconnectRileyLink();
return true;
} else {
return false;
}
}
public boolean processBluetoothBroadcasts(String action) {
if (action.equals(RileyLinkConst.Intents.BluetoothConnected)) {
LOG.debug("Bluetooth - Connected");
// sendIPCNotification(RT2Const.IPC.MSG_note_FindingRileyLink);
ServiceTaskExecutor.startTask(new DiscoverGattServicesTask());
return true;
} else if (action.equals(RileyLinkConst.Intents.BluetoothReconnected)) {
LOG.debug("Bluetooth - Reconnecting");
// sendIPCNotification(RT2Const.IPC.MSG_note_FindingRileyLink);
serviceInstance.bluetoothInit();
ServiceTaskExecutor.startTask(new DiscoverGattServicesTask(true));
return true;
} else if (action.equals(RileyLinkConst.Intents.BluetoothReconnected)) {
LOG.debug("Bluetooth - Reconnected");
// sendIPCNotification(RT2Const.IPC.MSG_note_FindingRileyLink);
serviceInstance.bluetoothInit();
ServiceTaskExecutor.startTask(new DiscoverGattServicesTask(true));
return true;
} else {
return false;
}
}
private boolean processTuneUpBroadcasts(String action) {
if (this.broadcastIdentifiers.get("TuneUp").contains(action)) {
if (serviceInstance.getRileyLinkTargetDevice().isTuneUpEnabled()) {
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
}
return true;
} else {
return false;
}
}
public boolean processDeviceSpecificBroadcasts(String action, Intent intent) {
if (this.deviceSpecificPrefix == null) {
return false;
}
if (action.startsWith(this.deviceSpecificPrefix)) {
return this.serviceInstance.handleDeviceSpecificBroadcasts(intent);
} else
return false;
}
public boolean processApplicationSpecificBroadcasts(String action, Intent intent) {
// if (action.equals(RT2Const.serviceLocal.ipcBound)) {
// // If we still need permission for bluetooth, ask now.
// // if (needBluetoothPermission) {
// // sendBLERequestForAccess();
// // }
// return true;
// } else if (RT2Const.IPC.MSG_ServiceCommand.equals(action)) {
// serviceInstance.handleIncomingServiceTransport(intent);
// return true;
// } else if (RT2Const.serviceLocal.INTENT_sessionCompleted.equals(action)) {
// Bundle bundle = intent.getBundleExtra(RT2Const.IPC.bundleKey);
// if (bundle != null) {
// ServiceTransport transport = new ServiceTransport(bundle);
// rileyLinkIPCConnection.sendTransport(transport, transport.getSenderHashcode());
// } else {
// LOG.error("sessionCompleted: no bundle!");
// }
// return true;
// } else {
// return false;
// }
return false;
}
public void sendIPCNotification(String notification) {
// rileyLinkIPCConnection.sendNotification(new ServiceNotification(notification), null);
}
}

View file

@ -48,7 +48,7 @@ public abstract class RileyLinkService extends Service {
protected BluetoothAdapter bluetoothAdapter;
protected RFSpy rfspy; // interface for RL xxx Mhz radio.
protected Context context;
protected BroadcastReceiver mBroadcastReceiver;
protected RileyLinkBroadcastReceiver mBroadcastReceiver;
protected RileyLinkServiceData rileyLinkServiceData;
protected RileyLinkTargetFrequency rileyLinkTargetFrequency;
@ -121,173 +121,32 @@ public abstract class RileyLinkService extends Service {
super.onCreate();
LOG.debug("onCreate");
// rileyLinkIPCConnection = new RileyLinkIPCConnection(context); // TODO We might be able to remove this -- Andy
// RileyLinkUtil.setRileyLinkIPCConnection(rileyLinkIPCConnection);
mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
LOG.error("onReceive: received null intent");
return;
}
String action = intent.getAction();
if (action == null) {
LOG.error("onReceive: null action");
} else {
if (action.equals(RileyLinkConst.Intents.BluetoothConnected)) {
// rileyLinkIPCConnection.sendNotification(new
// ServiceNotification(RT2Const.IPC.MSG_note_FindingRileyLink), null);
ServiceTaskExecutor.startTask(new DiscoverGattServicesTask());
} else if (action.equals(RileyLinkConst.Intents.RileyLinkDisconnected)) {
if (BluetoothAdapter.getDefaultAdapter().isEnabled()) {
RileyLinkUtil.setServiceState(RileyLinkServiceState.RileyLinkError,
RileyLinkError.RileyLinkUnreachable);
} else {
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothError,
RileyLinkError.BluetoothDisabled);
}
} else if (action.equals(RileyLinkConst.Intents.RileyLinkReady)) {
LOG.warn("BroadcastReceive: RileyLink Ready");
rileyLinkBLE.enableNotifications();
rfspy.startReader(); // call startReader from outside?
rfspy.initializeRileyLink();
String bleVersion = rfspy.getBLEVersionCached();
RileyLinkFirmwareVersion rlVersion = rfspy.getRLVersionCached();
LOG.debug("RfSpy version (BLE113): " + bleVersion);
rileyLinkServiceData.versionBLE113 = bleVersion;
LOG.debug("RfSpy Radio version (CC110): " + rlVersion.name());
rileyLinkServiceData.versionCC110 = rlVersion;
ServiceTask task = new InitializePumpManagerTask(getRileyLinkTargetDevice());
ServiceTaskExecutor.startTask(task);
LOG.info("Announcing RileyLink open For business");
} else if (action.equals(RileyLinkConst.Intents.BluetoothReconnected)) {
LOG.debug("BroadcastReceive: 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) || //
action.equals(RileyLinkConst.IPC.MSG_PUMP_quickTune)) {
if (getRileyLinkTargetDevice().isTuneUpEnabled()) {
// doTuneUpDevice();
ServiceTaskExecutor.startTask(new WakeAndTuneTask());
}
} else if (action.startsWith("MSG_PUMP_")) {
handlePumpSpecificIntents(intent);
} else if (RileyLinkConst.IPC.MSG_ServiceCommand.equals(action)) {
handleIncomingServiceTransport(intent);
} 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 (action.equals(RileyLinkConst.Intents.RileyLinkDisconnect)) {
disconnectRileyLink();
}
/*
* else if (RT2Const.serviceLocal.INTENT_sessionCompleted.equals(action)) {
* Bundle bundle = intent.getBundleExtra(RT2Const.IPC.bundleKey);
* if (bundle != null) {
* ServiceTransport transport = new ServiceTransport(bundle);
* //rileyLinkIPCConnection.sendTransport(transport, transport.getSenderHashcode());
* //RileyLinkUtil.send
* } else {
* LOG.error("sessionCompleted: no bundle!");
* }
* }
*/
/*
* else
*
* if (case RT2Const.local.INTENT_serviceConnected:
* case RT2Const.local.INTENT_NEW_rileylinkAddressKey:
* showIdle();
* /**
* Client MUST send a "UseThisRileylink" message because it asserts that
* the user has given explicit permission to use bluetooth.
*
* We can change the format so that it is a simple "bluetooth OK" message,
* rather than an explicit address of a Rileylink, and the Service can
* use the last known good value. But the kick-off of bluetooth ops must
* come from an Activity.
*/
/*
* String RileylinkBLEAddress = SP.getString(MedtronicConst.Prefs.RileyLinkAddress, "");
* if (RileylinkBLEAddress.equals("")) {
* // TODO: 11/07/2016 @TIM UI message for user
* Log.e(TAG, "No Rileylink BLE Address saved in app");
* } else {
* //showBusy("Configuring Service", 50);
* MainApp.getServiceClientConnection().setThisRileylink(RileylinkBLEAddress);
* }
* break;
* case RT2Const.local.INTENT_NEW_pumpIDKey:
* MainApp.getServiceClientConnection().sendPUMP_useThisDevice(SP.getString(MedtronicConst.Prefs.
* PumpSerial, ""));
* break;
*/
else {
LOG.error("Unhandled broadcast: action=" + action);
}
}
}
};
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(RileyLinkConst.Intents.BluetoothConnected);
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(RileyLinkConst.Intents.RileyLinkDisconnect);
// 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(RT2Const.IPC.MSG_PUMP_useThisAddress);
intentFilter.addAction(RileyLinkConst.IPC.MSG_ServiceCommand);
// intentFilter.addAction(RileyLinkConst.serviceLocal.INTENT_sessionCompleted);
addPumpSpecificIntents(intentFilter);
LocalBroadcastManager.getInstance(context).registerReceiver(mBroadcastReceiver, intentFilter);
mBroadcastReceiver = new RileyLinkBroadcastReceiver(this, this.context);
mBroadcastReceiver.registerBroadcasts();
LOG.debug("onCreate(): It's ALIVE!");
}
/**
* Prefix for Device specific broadcast identifier prefix (for example MSG_PUMP_ for pump or
* MSG_POD_ for Omnipod)
*
* @return
*/
public abstract String getDeviceSpecificBroadcastsIdentifierPrefix();
public abstract boolean handleDeviceSpecificBroadcasts(Intent intent);
public abstract void registerDeviceSpecificBroadcasts(IntentFilter intentFilter);
public abstract RileyLinkCommunicationManager getDeviceCommunicationManager();
public abstract void addPumpSpecificIntents(IntentFilter intentFilter);
public abstract void handlePumpSpecificIntents(Intent intent);
public abstract void handleIncomingServiceTransport(Intent intent);
public abstract boolean handleIncomingServiceTransport(Intent intent);
// Here is where the wake-lock begins:
@ -300,7 +159,7 @@ public abstract class RileyLinkService extends Service {
}
private boolean bluetoothInit() {
public boolean bluetoothInit() {
LOG.debug("bluetoothInit: attempting to get an adapter");
RileyLinkUtil.setServiceState(RileyLinkServiceState.BluetoothInitializing);
@ -380,13 +239,6 @@ public abstract class RileyLinkService extends Service {
}
public boolean sendNotification(ServiceNotification notification, Integer clientHashcode) {
// return rileyLinkIPCConnection.sendNotification(notification, clientHashcode);
LOG.error("sendNotification not implemented.");
return false;
}
// FIXME: This needs to be run in a session so that is interruptable, has a separate thread, etc.
public void doTuneUpDevice() {

View file

@ -25,6 +25,7 @@ public class LocationHelper {
*/
public static boolean isLocationEnabled(Context context) {
LocationManager locationManager = (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);
return (locationManager != null && //
(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) || //
locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)));

View file

@ -5,6 +5,8 @@ import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.Hours;
import org.joda.time.LocalDateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -39,9 +41,12 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLink
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.MedtronicCommunicationManager;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.history.pump.PumpHistoryEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui.MedtronicUIComm;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.ui.MedtronicUITask;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.MedtronicHistoryData;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfileEntry;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicNotificationType;
@ -133,6 +138,11 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
private String getLogPrefix() {
return "MedtronicPumpPlugin::";
}
@Override
public void initPumpStatusData() {
@ -141,6 +151,7 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
pumpStatusLocal.lastConnection = SP.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L);
pumpStatusLocal.lastDataTime = new LocalDateTime(pumpStatusLocal.lastConnection);
pumpStatusLocal.previousConnection = pumpStatusLocal.lastConnection;
pumpStatusLocal.refreshConfiguration();
@ -151,10 +162,10 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
pumpDescription.maxTempAbsolute = (pumpStatusLocal.maxBasal != null) ? pumpStatusLocal.maxBasal : 35.0d;
// needs to be changed in configuration, after all functionalities are done
pumpDescription.isBolusCapable = true;
pumpDescription.isBolusCapable = true; // WIP
pumpDescription.isTempBasalCapable = true; // WIP
pumpDescription.isExtendedBolusCapable = false;
pumpDescription.isSetBasalProfileCapable = false;
pumpDescription.isSetBasalProfileCapable = true;
// unchangable
pumpDescription.tempBasalStyle = PumpDescription.PERCENT;
@ -852,11 +863,14 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
return new PumpEnactResult().success(response).enacted(response);
}
// Gson gson = new Gson();
PumpHistoryEntry lastPumpHistoryEntry;
private void readPumpHistory() {
LOG.error("MedtronicPumpPlugin::readPumpHistory NOT IMPLEMENTED.");
// TODO read History
// readPumpHistoryLogic();
scheduleNextRefresh(MedtronicStatusRefreshType.PumpHistory);
@ -868,6 +882,50 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
}
private void readPumpHistoryLogic() {
Long lastPumpHistoryEntryTime = null;
// TODO read History
if (lastPumpHistoryEntry == null) {
lastPumpHistoryEntryTime = SP.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, null);
}
if (firstRun) {
DateTime dt = new DateTime();
dt.minus(Hours.hours(36));
if (lastPumpHistoryEntry == null && lastPumpHistoryEntryTime == null) {
} else {
}
}
// determine if first run, if yes detrmine how much of update do we need
// first run:
// get last hiostory entry, if not there download 1.5 days of data
// - there: check if last entry is older than 1.5 days
// - yes: download 1.5 days
// - no: download with last entry
// - not there: download 1.5 days
//
// upload all new entries to NightScout (TBR, Bolus)
// determine pump status
//
// save last entry
//
// not first run:
// update to last entry
// - save
// - determine pump status
//
}
private void scheduleNextRefresh(MedtronicStatusRefreshType refreshType) {
scheduleNextRefresh(refreshType, 0);
}
@ -931,8 +989,19 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public PumpEnactResult cancelTempBasal(boolean enforceNew) {
LOG.info("cancelTempBasal - started");
LOG.info("MedtronicPumpPlugin::cancelTempBasal - started");
if (isPumpNotReachable()) {
setRefreshButtonEnabled(true);
return new PumpEnactResult() //
.success(false) //
.enacted(false) //
.comment(MainApp.gs(R.string.medtronic_pump_status_pump_unreachable));
}
MedtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable);
setRefreshButtonEnabled(false);
TempBasalPair tbrCurrent = readTBR();
@ -969,12 +1038,89 @@ public class MedtronicPumpPlugin extends PumpPluginAbstract implements PumpInter
@Override
public PumpEnactResult setNewBasalProfile(Profile profile) {
LOG.warn("MedtronicPumpPlugin::setNewBasalProfile NOT IMPLEMENTED YET.");
LOG.error(getLogPrefix() + "setNewBasalProfile - WIP.");
// TODO implement this
setRefreshButtonEnabled(false);
return new PumpEnactResult().success(false).enacted(false)
.comment(MainApp.gs(R.string.medtronic_cmd_profile_not_set));
if (isPumpNotReachable()) {
setRefreshButtonEnabled(true);
return new PumpEnactResult() //
.success(false) //
.enacted(false) //
.comment(MainApp.gs(R.string.medtronic_pump_status_pump_unreachable));
}
MedtronicUtil.dismissNotification(MedtronicNotificationType.PumpUnreachable);
BasalProfile basalProfile = convertProfileToMedtronicProfile(profile);
String profileInvalid = isProfileValid(basalProfile);
if (profileInvalid != null) {
return new PumpEnactResult() //
.success(false) //
.enacted(false) //
.comment(MainApp.gs(R.string.medtronic_cmd_set_profile_pattern_overflow, profileInvalid));
}
MedtronicUITask responseTask = medtronicUIComm.executeCommand(MedtronicCommandType.SetBasalProfileSTD,
basalProfile);
Boolean response = (Boolean)responseTask.returnData;
LOG.info(getLogPrefix() + "Basal Profile was set: " + response);
return new PumpEnactResult().success(response).enacted(response);
}
private String isProfileValid(BasalProfile basalProfile) {
StringBuilder stringBuilder = new StringBuilder();
MedtronicPumpStatus pumpStatus = getMDTPumpStatus();
if (pumpStatusLocal.maxBasal == null)
return null;
for (BasalProfileEntry profileEntry : basalProfile.getEntries()) {
if (profileEntry.rate > pumpStatusLocal.maxBasal) {
stringBuilder.append(profileEntry.startTime.toString("HH:mm") + "=" + profileEntry.rate);
}
}
return stringBuilder.length() == 0 ? null : stringBuilder.toString();
}
@NonNull
private BasalProfile convertProfileToMedtronicProfile(Profile profile) {
MedtronicPumpStatus pumpStatus = getMDTPumpStatus();
PumpType pumpType = pumpStatus.pumpType;
BasalProfile basalProfile = new BasalProfile();
for (int i = 0; i < 24; i++) {
double rate = profile.getBasalTimeFromMidnight(i * 60 * 60);
double v = pumpType.determineCorrectBasalSize(rate);
BasalProfileEntry basalEntry = new BasalProfileEntry(v, i, 0);
basalProfile.addEntry(basalEntry);
}
basalProfile.generateRawDataFromEntries();
return basalProfile;
}

View file

@ -343,15 +343,13 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
LOG.debug("Run command with Frames: Got ACK response for Attention packet");
}
int start = 0;
int frameNr = 1;
int len = 0;
for (List<Byte> frame : frames) {
byte[] frameData = MedtronicUtil.createByteArray(frame);
LOG.debug("Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData));
// LOG.debug("Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData));
PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(frameData));
@ -375,10 +373,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
public PumpHistoryResult getPumpHistory(PumpHistoryEntry lastEntry, LocalDateTime targetDate) {
// int pageNumber = 0;
// TODO multiple history pages
PumpHistoryResult pumpTotalResult = new PumpHistoryResult(lastEntry, targetDate);
if (doWakeUpBeforeCommand)
@ -480,14 +474,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
return pumpTotalResult;
// Page page = new Page();
// // page.parseFrom(rval.getData(),PumpModel.MM522);
// // FIXME
// page.parseFrom(rawHistoryPage.getData(), MedtronicDeviceType.Medtronic_522);
//
// // return page;
//
// return null;
}
@ -774,40 +760,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
// TODO remove not needed - probably
// @Deprecated
// private void executeSetCommand(MedtronicCommandType commandType, byte[] bodyData) {
//
// LOG.debug("Executing Set for {} - 1st call", commandType.name());
//
// // first we send command without paramters and wait for ACK
// PumpMessage pumpMessage = sendAndGetACK(commandType, null, 4000);
//
// // FIXME check if ACK
// LOG.debug("Response 1 - {}", HexDump.toHexStringDisplayable(pumpMessage.getRawContent()));
//
//
// LOG.debug("Executing Set for {} - 2nd call", commandType.name());
// // second we send command with parameters and full package 64 bits with zeroed empty places
//
// byte newBodyData[] = new byte[64];
// for(int i = 0; i < 64; i++) {
// newBodyData[i] = 0x00;
// }
//
// newBodyData[0] = (byte) bodyData.length;
//
// for(int i = 0; i < bodyData.length; i++) {
// newBodyData[i + 1] = bodyData[i];
// }
//
// PumpMessage pumpMessage2 = sendAndGetACK(commandType, newBodyData, 4000);
//
//
// LOG.debug("Response 2 - {}", HexDump.toHexStringDisplayable(pumpMessage.getRawContent()));
//
// }
// PUMP SPECIFIC COMMANDS
public Float getRemainingInsulin() {
@ -830,14 +782,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
public BasalProfile getBasalProfile_Old() {
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBasalProfileSTD);
return responseObject == null ? null : (BasalProfile)responseObject;
}
public BasalProfile getBasalProfile() {
// wakeUp
@ -992,7 +936,6 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
// TODO WIP test
public boolean setTBR(TempBasalPair tbr) {
if (this.doWakeUpBeforeCommand)
@ -1028,6 +971,19 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
}
public Boolean setBasalProfile(BasalProfile basalProfile) {
List<List<Byte>> basalProfileFrames = MedtronicUtil.getBasalProfileFrames(basalProfile.getRawData());
PumpMessage responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, basalProfileFrames);
// LOG.debug("Set Basal Profile: {}", HexDump.toHexStringDisplayable(responseMessage.getRawContent()));
return responseMessage.commandType == MedtronicCommandType.CommandACK;
}
// FIXME --- After this line commands in development --- REMOVE THIS COMMANDS
// TODO test
@ -1061,146 +1017,11 @@ 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 };
byte[] body = ByteUtil
.createByteArray(
"06000052000178050202000304000402000504000602000704000802000904000a02000b04000c02000d02000e02000f040010020011040012020013040014020015040016020017040018020019000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
0);
List<List<Byte>> basalProfileFrames = MedtronicUtil.getBasalProfileFrames(body);
PumpMessage responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileA, basalProfileFrames);
// PumpMessage responseMessage;
//
// if (debugSetCommands)
// LOG.debug("Set Basal Profile: Body [{}] - {}", body.length, HexDump.toHexStringDisplayable(body));
//
// for (List<Byte> basalProfileFrame : basalProfileFrames) {
//
// PumpMessage msg = makePumpMessage(MedtronicCommandType.SetBasalProfileA, //
// new CarelinkLongMessageBody(ByteUtil.concat((byte)body.length, body)));
//
// responseMessage = runCommandWithArgs(msg);
//
// }
// if (body.length <= 64) {
//
// PumpMessage msg = makePumpMessage(MedtronicCommandType.SetBasalProfileA, //
// new CarelinkLongMessageBody(ByteUtil.concat((byte) body.length, body)));
//
// responseMessage = runCommandWithArgs(msg);
// } else
// {
//
// responseMessage = runCommandWithArgsLong(MedtronicCommandType.SetBasalProfileA, body);
// }
// if (debugSetCommands)
// LOG.debug("Set Basal Profile: {}", HexDump.toHexStringDisplayable(responseMessage.getRawContent()));
LOG.debug("Set Basal Profile: {}", HexDump.toHexStringDisplayable(responseMessage.getRawContent()));
return responseMessage.commandType == MedtronicCommandType.CommandACK;
}
// public byte[] getFullMessageBody(byte[] bodyData, int length) {
// byte newBodyData[] = getEmptyMessage(length);
//
// newBodyData[0] = (byte) bodyData.length;
//
// for (int i = 0; i < bodyData.length; i++) {
// newBodyData[i + 1] = bodyData[i];
// }
//
// return newBodyData;
// }
// public byte[] getEmptyMessage(int length) {
// byte newBodyData[] = new byte[length];
// for (int i = 0; i < length; i++) {
// newBodyData[i] = 0x00;
// }
//
// return newBodyData;
// }
public PumpMessage cancelBolus() {
// ? maybe suspend and resume
return null;
}
// Set TBR 100%
// Cancel TBR (set TBR 100%) 100%
// Get Status (40%)
@ -1215,42 +1036,4 @@ public class MedtronicCommunicationManager extends RileyLinkCommunicationManager
// Read History 60%
// Load TDD ?
// FIXME remove - each part needs to be gotten manually
public void updatePumpManagerStatus() {
// Integer resp = getRemainingBattery();
// pumpStatus.batteryRemaining = resp == null ? -1 : resp;
// pumpStatus.remainUnits = getRemainingInsulin();
/* current basal */
// TempBasalPair basalRate = getCurrentBasalRate();
// FIXME
// byte[] basalRateBytes = resp.getContents();
// if (basalRateBytes != null) {
// if (basalRateBytes.length == 2) {
// /**
// * 0x98 0x06
// * 0x98 is "basal rate"
// * 0x06 is what? Not currently running a temp basal, current basal is "standard" at 0
// */
// double basalRate = ByteUtil.asUINT8(basalRateBytes[1]);
// pumpStatus.currentBasal = basalRate;
// }
// }
// get last bolus amount
// get last bolus time
// get tempBasalInProgress
// get tempBasalRatio
// get tempBasalRemainMin
// get tempBasalStart
// get pump time
LocalDateTime clockResult = getPumpTime();
if (clockResult != null) {
// pumpStatus.time = clockResult.toDate();
}
// get last sync time
}
}

View file

@ -119,11 +119,12 @@ public abstract class MedtronicHistoryDecoder {
// public abstract List<? extends MedtronicHistoryEntry> processPageAndCreateRecords(RawHistoryPage page,
// boolean partial) throws Exception;
//
//
// public List<? extends MedtronicHistoryEntry> processPageAndCreateRecords(RawHistoryPage page) throws Exception {
// return processPageAndCreateRecords(page, false);
// }
public <E extends MedtronicHistoryEntry> List<E> processPageAndCreateRecords(RawHistoryPage rawHistoryPage,
Class<E> clazz) throws Exception {
return processPageAndCreateRecords(rawHistoryPage, false, clazz);
}
protected void prepareStatistics() {
if (!statisticsEnabled)
@ -212,12 +213,6 @@ public abstract class MedtronicHistoryDecoder {
}
// public <E extends MedtronicHistoryEntry> List<E> processPageAndCreateRecords(RawHistoryPage rawHistoryPage,
// boolean partial) {
// return (processPageAndCreateRecords(
// rawHistoryPage, partial, clazz);
// }
public <E extends MedtronicHistoryEntry> List<E> processPageAndCreateRecords(RawHistoryPage rawHistoryPage,
boolean partial, Class<E> clazz) {
List<Byte> dataClear = checkPage(rawHistoryPage, partial);
@ -234,4 +229,5 @@ public abstract class MedtronicHistoryDecoder {
protected abstract <E extends MedtronicHistoryEntry> List<E> createRecords(List<Byte> dataClear, Class<E> clazz);
}

View file

@ -44,6 +44,17 @@ public class MedtronicUIPostprocessor {
switch (uiTask.commandType) {
case SetBasalProfileSTD: {
Boolean response = (Boolean) uiTask.returnData;
if (response) {
BasalProfile basalProfile = (BasalProfile) uiTask.getParameter(0);
pumpStatus.basalsByHour = basalProfile.getProfilesByHour();
}
}
break;
case GetBasalProfileSTD: {
BasalProfile basalProfile = (BasalProfile)uiTask.returnData;

View file

@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.MedtronicCommunicationManager;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.BasalProfile;
import info.nightscout.androidaps.plugins.PumpMedtronic.data.dto.TempBasalPair;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicCommandType;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.MedtronicUIResponseType;
@ -118,7 +119,9 @@ public class MedtronicUITask {
case SetBasalProfileSTD:
case SetBasalProfileA: {
// returnData = communicationManager.setBasalProfile(profile);
BasalProfile profile = (BasalProfile) parameters[0];
returnData = communicationManager.setBasalProfile(profile);
// Float amount = getAmount();
//
// if (amount != null) {
@ -227,4 +230,8 @@ public class MedtronicUITask {
public boolean hasData() {
return (responseType == MedtronicUIResponseType.Data);
}
public Object getParameter(int index) {
return parameters[index];
}
}

View file

@ -69,7 +69,13 @@ public class BasalProfile {
data = MedtronicUtil.createByteArray(data[0], (byte)0, (byte)0);
}
if (data.length == MAX_RAW_DATA_SIZE) {
mRawData = data;
} else {
int len = Math.min(MAX_RAW_DATA_SIZE, data.length);
mRawData = new byte[MAX_RAW_DATA_SIZE];
System.arraycopy(data, 0, mRawData, 0, len);
}
return true;
}
@ -190,7 +196,7 @@ public class BasalProfile {
}
public byte[] generateRawData() {
public void generateRawDataFromEntries() {
List<Byte> outData = new ArrayList<>();
@ -205,7 +211,7 @@ public class BasalProfile {
this.setRawData(MedtronicUtil.createByteArray(outData));
return this.mRawData;
// return this.mRawData;
}

View file

@ -25,6 +25,24 @@ public class BasalProfileEntry {
}
public BasalProfileEntry(double rate, int hour, int minutes) {
byte[] data = MedtronicUtil.getBasalStrokes(rate, true);
rate_raw = new byte[2];
rate_raw[0] = data[1];
rate_raw[1] = data[0];
int interval = hour * 2;
if (minutes == 30) {
interval++;
}
startTime_raw = (byte)interval;
startTime = new LocalTime(hour, minutes == 30 ? 30 : 0);
}
public BasalProfileEntry(int rateStrokes, int startTimeInterval) {
// rateByte is insulin delivery rate, U/hr, in 0.025 U increments
// startTimeByte is time-of-day, in 30 minute increments

View file

@ -1,13 +1,8 @@
package info.nightscout.androidaps.plugins.PumpMedtronic.service;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
@ -27,12 +22,10 @@ import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLink
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.defs.RileyLinkTargetDevice;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkService;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.RileyLinkServiceData;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.data.ServiceNotification;
import info.nightscout.androidaps.plugins.PumpCommon.hw.rileylink.service.tasks.ServiceTask;
import info.nightscout.androidaps.plugins.PumpCommon.utils.ByteUtil;
import info.nightscout.androidaps.plugins.PumpMedtronic.MedtronicPumpPlugin;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.MedtronicCommunicationManager;
import info.nightscout.androidaps.plugins.PumpMedtronic.comm.data.Page;
import info.nightscout.androidaps.plugins.PumpMedtronic.defs.PumpDeviceState;
import info.nightscout.androidaps.plugins.PumpMedtronic.driver.MedtronicPumpStatus;
import info.nightscout.androidaps.plugins.PumpMedtronic.util.MedtronicConst;
@ -74,119 +67,6 @@ public class RileyLinkMedtronicService extends RileyLinkService {
}
public void addPumpSpecificIntents(IntentFilter intentFilter) {
//intentFilter.addAction(RileyLinkConst.IPC.MSG_PUMP_fetchHistory);
//intentFilter.addAction(RileyLinkConst.IPC.MSG_PUMP_fetchSavedHistory);
}
public void handlePumpSpecificIntents(Intent intent) {
String action = intent.getAction();
if (action.equals(RileyLinkConst.IPC.MSG_PUMP_fetchHistory)) {
// mHistoryPages = medtronicCommunicationManager.getAllHistoryPages();
// final boolean savePages = true;
// if (savePages) {
// for (int i = 0; i < mHistoryPages.size(); i++) {
// String filename = "PumpHistoryPage-" + i;
// LOG.warn("Saving history page to file " + filename);
// FileOutputStream outputStream;
// try {
// outputStream = openFileOutput(filename, 0);
// byte[] rawData = mHistoryPages.get(i).getRawData();
// if (rawData != null) {
// outputStream.write(rawData);
// }
// outputStream.close();
// } catch (FileNotFoundException fnf) {
// fnf.printStackTrace();
// } catch (IOException ioe) {
// ioe.printStackTrace();
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
// }
//
// Message msg = Message.obtain(null, RT2Const.IPC.MSG_IPC, 0, 0);
// // Create a bundle with the data
// Bundle bundle = new Bundle();
// bundle.putString(RT2Const.IPC.messageKey, RT2Const.IPC.MSG_PUMP_history);
// ArrayList<Bundle> packedPages = new ArrayList<>();
// for (Page page : mHistoryPages) {
// packedPages.add(page.pack());
// }
// bundle.putParcelableArrayList(RT2Const.IPC.MSG_PUMP_history_key, packedPages);
//
// // save it to SQL.
// pumpHistoryManager.clearDatabase();
// pumpHistoryManager.initFromPages(bundle);
// // write html page to documents folder
// pumpHistoryManager.writeHtmlPage();
//
// // Set payload
// msg.setData(bundle);
// //rileyLinkIPCConnection.sendMessage(msg, null/*broadcast*/);
// LOG.debug("sendMessage: sent Full history report");
} else if (RileyLinkConst.IPC.MSG_PUMP_fetchSavedHistory.equals(action)) {
LOG.info("Fetching saved history");
// FileInputStream inputStream;
// ArrayList<Page> storedHistoryPages = new ArrayList<>();
// for (int i = 0; i < 16; i++) {
//
// String filename = "PumpHistoryPage-" + i;
// try {
// inputStream = openFileInput(filename);
// byte[] buffer = new byte[1024];
// int numRead = inputStream.read(buffer, 0, 1024);
// if (numRead == 1024) {
// Page p = new Page();
// //p.parseFrom(buffer, PumpModel.MM522);
// // FIXME
// p.parseFrom(buffer, PumpModel.MM522);
// storedHistoryPages.add(p);
// } else {
// LOG.error(filename + " error: short file");
// }
// } catch (FileNotFoundException fnf) {
// LOG.error("Failed to open " + filename + " for reading.");
// } catch (IOException e) {
// LOG.error("Failed to read " + filename);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// mHistoryPages = storedHistoryPages;
// if (storedHistoryPages.isEmpty()) {
// LOG.error("No stored history pages loaded");
// } else {
// Message msg = Message.obtain(null, RT2Const.IPC.MSG_IPC, 0, 0);
// // Create a bundle with the data
// Bundle bundle = new Bundle();
// bundle.putString(RT2Const.IPC.messageKey, RT2Const.IPC.MSG_PUMP_history);
// ArrayList<Bundle> packedPages = new ArrayList<>();
// for (Page page : mHistoryPages) {
// packedPages.add(page.pack());
// }
// bundle.putParcelableArrayList(RT2Const.IPC.MSG_PUMP_history_key, packedPages);
//
// // save it to SQL.
// pumpHistoryManager.clearDatabase();
// pumpHistoryManager.initFromPages(bundle);
// // write html page to documents folder
// pumpHistoryManager.writeHtmlPage();
//
// // Set payload
// msg.setData(bundle);
// //rileyLinkIPCConnection.sendMessage(msg, null/*broadcast*/);
//
// }
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
LOG.warn("onConfigurationChanged");
@ -286,10 +166,166 @@ public class RileyLinkMedtronicService extends RileyLinkService {
// LOG.info("setPumpIDString: saved pumpID " + idString);
}
public class LocalBinder extends Binder {
public RileyLinkMedtronicService getServiceInstance() {
return RileyLinkMedtronicService.this;
}
}
/* private functions */
public void handleIncomingServiceTransport(Intent intent) {
// PumpInterface - REMOVE
public boolean isInitialized() {
return RileyLinkServiceState.isReady(RileyLinkUtil.getRileyLinkServiceData().serviceState);
}
public boolean isSuspended() {
return false;
}
public boolean isBusy() {
return false;
}
public boolean isConnected() {
return RileyLinkServiceState.isReady(RileyLinkUtil.getRileyLinkServiceData().serviceState);
}
public boolean isConnecting() {
return !RileyLinkServiceState.isReady(RileyLinkUtil.getRileyLinkServiceData().serviceState);
}
@Override
public String getDeviceSpecificBroadcastsIdentifierPrefix() {
return null;
}
public boolean handleDeviceSpecificBroadcasts(Intent intent) {
// String action = intent.getAction();
// if (action.equals(RileyLinkConst.IPC.MSG_PUMP_fetchHistory)) {
// mHistoryPages = medtronicCommunicationManager.getAllHistoryPages();
// final boolean savePages = true;
// if (savePages) {
// for (int i = 0; i < mHistoryPages.size(); i++) {
// String filename = "PumpHistoryPage-" + i;
// LOG.warn("Saving history page to file " + filename);
// FileOutputStream outputStream;
// try {
// outputStream = openFileOutput(filename, 0);
// byte[] rawData = mHistoryPages.get(i).getRawData();
// if (rawData != null) {
// outputStream.write(rawData);
// }
// outputStream.close();
// } catch (FileNotFoundException fnf) {
// fnf.printStackTrace();
// } catch (IOException ioe) {
// ioe.printStackTrace();
// } catch (Exception e) {
// e.printStackTrace();
// }
//
// }
// }
//
// Message msg = Message.obtain(null, RT2Const.IPC.MSG_IPC, 0, 0);
// // Create a bundle with the data
// Bundle bundle = new Bundle();
// bundle.putString(RT2Const.IPC.messageKey, RT2Const.IPC.MSG_PUMP_history);
// ArrayList<Bundle> packedPages = new ArrayList<>();
// for (Page page : mHistoryPages) {
// packedPages.add(page.pack());
// }
// bundle.putParcelableArrayList(RT2Const.IPC.MSG_PUMP_history_key, packedPages);
//
// // save it to SQL.
// pumpHistoryManager.clearDatabase();
// pumpHistoryManager.initFromPages(bundle);
// // write html page to documents folder
// pumpHistoryManager.writeHtmlPage();
//
// // Set payload
// msg.setData(bundle);
// //rileyLinkIPCConnection.sendMessage(msg, null/*broadcast*/);
// LOG.debug("sendMessage: sent Full history report");
// } else if (RileyLinkConst.IPC.MSG_PUMP_fetchSavedHistory.equals(action)) {
// LOG.info("Fetching saved history");
// FileInputStream inputStream;
// ArrayList<Page> storedHistoryPages = new ArrayList<>();
// for (int i = 0; i < 16; i++) {
//
// String filename = "PumpHistoryPage-" + i;
// try {
// inputStream = openFileInput(filename);
// byte[] buffer = new byte[1024];
// int numRead = inputStream.read(buffer, 0, 1024);
// if (numRead == 1024) {
// Page p = new Page();
// //p.parseFrom(buffer, PumpModel.MM522);
//
// p.parseFrom(buffer, PumpModel.MM522);
// storedHistoryPages.add(p);
// } else {
// LOG.error(filename + " error: short file");
// }
// } catch (FileNotFoundException fnf) {
// LOG.error("Failed to open " + filename + " for reading.");
// } catch (IOException e) {
// LOG.error("Failed to read " + filename);
// } catch (Exception e) {
// e.printStackTrace();
// }
// }
// mHistoryPages = storedHistoryPages;
// if (storedHistoryPages.isEmpty()) {
// LOG.error("No stored history pages loaded");
// } else {
// Message msg = Message.obtain(null, RT2Const.IPC.MSG_IPC, 0, 0);
// // Create a bundle with the data
// Bundle bundle = new Bundle();
// bundle.putString(RT2Const.IPC.messageKey, RT2Const.IPC.MSG_PUMP_history);
// ArrayList<Bundle> packedPages = new ArrayList<>();
// for (Page page : mHistoryPages) {
// packedPages.add(page.pack());
// }
// bundle.putParcelableArrayList(RT2Const.IPC.MSG_PUMP_history_key, packedPages);
//
// // save it to SQL.
// pumpHistoryManager.clearDatabase();
// pumpHistoryManager.initFromPages(bundle);
// // write html page to documents folder
// pumpHistoryManager.writeHtmlPage();
//
// // Set payload
// msg.setData(bundle);
// //rileyLinkIPCConnection.sendMessage(msg, null/*broadcast*/);
//
// }
// }
return false;
}
@Override
public void registerDeviceSpecificBroadcasts(IntentFilter intentFilter) {
// intentFilter.addAction(RT2Const.IPC.MSG_PUMP_fetchHistory);
// intentFilter.addAction(RT2Const.IPC.MSG_PUMP_fetchSavedHistory);
}
public boolean handleIncomingServiceTransport(Intent intent) {
// Bundle bundle = intent.getBundleExtra(RT2Const.IPC.bundleKey);
//
@ -368,6 +404,7 @@ public class RileyLinkMedtronicService extends RileyLinkService {
// break;
// }
// }
return false;
}
@ -385,62 +422,21 @@ public class RileyLinkMedtronicService extends RileyLinkService {
*/
}
public void saveHistoryPage(int pagenumber, Page page) {
if ((page == null) || (page.getRawData() == null)) {
return;
}
String filename = "history-" + pagenumber;
FileOutputStream os;
try {
os = openFileOutput(filename, Context.MODE_PRIVATE);
os.write(page.getRawData());
os.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
// PumpInterface - REMOVE
public boolean isInitialized() {
return RileyLinkServiceState.isReady(RileyLinkUtil.getRileyLinkServiceData().serviceState);
}
public boolean isSuspended() {
return false;
}
public boolean isBusy() {
return false;
}
public boolean isConnected() {
return RileyLinkServiceState.isReady(RileyLinkUtil.getRileyLinkServiceData().serviceState);
}
public boolean isConnecting() {
return !RileyLinkServiceState.isReady(RileyLinkUtil.getRileyLinkServiceData().serviceState);
}
// FIXME remove
public void sendNotification(ServiceNotification serviceNotification, Object o) {
LOG.warn("Send Notification has no implementation.");
}
public class LocalBinder extends Binder {
public RileyLinkMedtronicService getServiceInstance() {
return RileyLinkMedtronicService.this;
}
}
// public void saveHistoryPage(int pagenumber, Page page) {
// if ((page == null) || (page.getRawData() == null)) {
// return;
// }
// String filename = "history-" + pagenumber;
// FileOutputStream os;
// try {
// os = openFileOutput(filename, Context.MODE_PRIVATE);
// os.write(page.getRawData());
// os.close();
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
}

View file

@ -27,6 +27,7 @@ public class MedtronicConst {
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 LastPumpHistoryEntry = StatsPrefix + "pump_history_entry";
}
}

View file

@ -318,8 +318,8 @@ public class MedtronicUtil extends RileyLinkUtil {
if (isEmptyFrame(frameData)) {
byte b = (byte)frame;
// b |= 0x80;
// b |= 0b1000_0000;
b |= doneBit;
b |= 0b1000_0000;
// b |= doneBit;
frameData.add(0, b);
@ -349,8 +349,8 @@ public class MedtronicUtil extends RileyLinkUtil {
List<Byte> frameData = new ArrayList<>();
byte b = (byte)frame;
// b |= 0b1000_0000;
b |= doneBit;
b |= 0b1000_0000;
// b |= doneBit;
frameData.add(b);

View file

@ -1313,10 +1313,12 @@
<string name="medtronic_pump_status_active">Active</string>
<string name="medtronic_pump_status_sleeping">Sleeping</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_profile_not_set">Remote Basal profile setting is not supported. Please modify Basal profile on your pump manually.</string> -->
<string name="medtronic_cmd_cancel_bolus_not_supported">Remote cancel of Bolus is not supported. If you wish to cancel bolus, go to pump put it in suspend and then resume. This will cancel the bolus.</string>
<string name="medtronic_cmd_cant_read_tbr">Could not read current TBR.</string>
<string name="medtronic_cmd_cant_cancel_tbr">Could not cancel current TBR. Stopping operation.</string>
<string name="medtronic_cmd_set_profile_pattern_overflow">Profile set failed, because following patterns, have too big basal rate: %1$s</string>
<string name="pump_no_connection_h">No connection for %1$d hour(s) %2$d min</string>
<string name="pump_no_connection_d">No connection for %1$d day(s) %2$d hours</string>

76
docs/MedtronicRoadmap.md Normal file
View file

@ -0,0 +1,76 @@
#Medtronic AAPS Roadmap
------------------------
## Phase 1: Create AAPS integration point
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Plugin | 100 |
| Base configuration (no RileyLink Discovery) | 100 |
| Basic pump configuration | 100 |
| Display Fragment | 90 |
| Pump Configuration | 70 |
## Phase 2: Implement commands within Roadtrip2 application
1. Base Bolus/Status commands
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Set Bolus | 0 |
| Cancel Bolus | 0 |
| Get Status | 0 |
2. TBR
| Functionality | Done % |
| --- |:------:|
| Set TBR (Absolute) | 0 |
| Cancel TBR | 0 |
3. Basal Profile
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Get Profile | 0 |
| Set Profile | 0 |
4. History
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Get History | 0 |
| Decde History | 0 |
5. Extended Bolus
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Set Extended Bolus | 0 |
| Cancel Extended Bolus | 0 |
6. Other commands
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Load TDD | 0 |
##Phase 3: Refactor RT2 code to split RileyLink and Medtronic parts
| Functionality | Done % |
| ----------------------------------------- |:------:|
| Refactor: Split RL and Medtronic code | 0 |
| Add RL code to AAPS | 0 |
| Start adding commands to AAPS | 0 |
| CMD: Base Bolus/Status commands | 0 |
| CMD: TBR | 0 |
| CMD: Basal Profile | 0 |
| CMD: History | 0 |
| CMD: Extended Bolus | 0 |

129
docs/MedtronicToDo.txt Normal file
View file

@ -0,0 +1,129 @@
RileyLinkAAPS
=============
Medtronic
- set basal profile (try to get to work - see new Loop code)
- read history
Bugs:
History: - parse pump history
Device search/scan refactor
CGMS [not in plan for now]:
- read history
AAPS-Medtronic
==============
- history: - integrate
- basal change code
- settings change code
- foolproofing: - bolus
- TBR
* connection (!!)
- bolus: - progress
- cancel handling
- What needs to be fixed: + button when clicked Refresh
x basal profile by 1/2 hour (not supported by AAPS)
* disconnect
- MedtronicUIResponseType integration
- add fabric code for following errors
- tuneup not working correctly
- BT Scan:
+ display mac on calling Preference
+ fix location problem
- fix start/stop of scan:
- remove toast button:
- Remove Refresh
- Add Scan Button
- Scan button is Stop button when search is running
- after change old error visible
* Refresh button toggling
Pages (RL Info):
- Base: - display firmware version
- display current data (it doesn't work ATM)
- RL history
- Device page: - Add Commands:
- get model
- tune (with report)
- get time
- get remaining insulin
- Add Statistics:
- Bolus,
- TBR
- Bolus SMB
- Pump Tab: - fix 3 buttons
==========================================================================================================
DONE - AAPS-Medtronic
=====================
+ status time
+ status all scheduling
+ status config
+ status power
+ Statistics in App:
+ Bolus,
+ TBR
+ Bolus SMB
+ status error display: + time
+ basal profile enabled
+ basal profile incorrect
+ tbr type set
+ max bolus
+ max basal
+ wrong pump selected
+ Basal refactoring: - basal is read when history says there was a change
+ merge: bugs (3)
+ Code to determine number of users:
DONE - RileyLinkAAPS
=====================
RileyLink
+ BT Disconnect and reconnect (change in RileyLinkBLE ??)
+ RL version
Medtronic
x extended bolus
Firmware Support:
+ version 2 support: + V1 works
+ V2 works
Bugs:
+ Bolus 554
+ TBR (554) ?
+ Remaining Insulin [554]
+ Get Basal profile returns just part of profile
+ Set TBR problem (after Bolus fixes)