diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java index 94673a29b6..c795ea4050 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/treatments/TreatmentsPlugin.java @@ -1,10 +1,13 @@ package info.nightscout.androidaps.plugins.treatments; import android.content.Context; +import android.os.Bundle; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.google.firebase.analytics.FirebaseAnalytics; + import java.util.List; import java.util.stream.Collectors; @@ -14,9 +17,11 @@ import javax.inject.Singleton; import dagger.android.HasAndroidInjector; import info.nightscout.androidaps.Constants; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.activities.ErrorHelperActivity; import info.nightscout.androidaps.data.DetailedBolusInfo; import info.nightscout.androidaps.data.ProfileIntervals; import info.nightscout.androidaps.database.AppRepository; +import info.nightscout.androidaps.database.embedments.InterfaceIDs; import info.nightscout.androidaps.db.ExtendedBolus; import info.nightscout.androidaps.db.ProfileSwitch; import info.nightscout.androidaps.db.Source; @@ -32,12 +37,16 @@ import info.nightscout.androidaps.interfaces.ProfileFunction; import info.nightscout.androidaps.interfaces.ProfileStore; import info.nightscout.androidaps.interfaces.TreatmentServiceInterface; import info.nightscout.androidaps.interfaces.TreatmentsInterface; +import info.nightscout.androidaps.interfaces.UpdateReturn; import info.nightscout.androidaps.logging.AAPSLogger; import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.bus.RxBusWrapper; import info.nightscout.androidaps.plugins.general.nsclient.NSUpload; import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification; import info.nightscout.androidaps.plugins.general.overview.notifications.Notification; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; +import info.nightscout.androidaps.plugins.pump.medtronic.data.MedtronicHistoryData; import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.FabricPrivacy; import info.nightscout.androidaps.utils.resources.ResourceHelper; @@ -67,6 +76,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface private final ProfileIntervals profiles = new ProfileIntervals<>(); + private final boolean useNewPumpSync = false; + + + @Inject public TreatmentsPlugin( HasAndroidInjector injector, @@ -245,38 +258,48 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface @Deprecated @Override public boolean addToHistoryTempBasal(TemporaryBasal tempBasal) { - throw new IllegalStateException("Migrate to new DB"); -/* + if (useNewPumpSync) { + throw new IllegalStateException("Migrate to new DB"); + } else { + getAapsLogger().error("!!! addToHistoryTempBasal: Need to migrate to new DB"); + } + //log.debug("Adding new TemporaryBasal record" + tempBasal.toString()); boolean newRecordCreated = databaseHelper.createOrUpdate(tempBasal); if (newRecordCreated) { - if (tempBasal.durationInMinutes == 0) - nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId); - else if (tempBasal.isAbsolute) - nsUpload.uploadTempBasalStartAbsolute(tempBasal, null); - else - nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date)); +// if (tempBasal.durationInMinutes == 0) +// nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId); +// else if (tempBasal.isAbsolute) +// nsUpload.uploadTempBasalStartAbsolute(tempBasal, null); +// else +// nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date)); } return newRecordCreated; - */ } @Deprecated public TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) { - throw new IllegalStateException("Migrate to new DB"); -/* + if (useNewPumpSync) { + throw new IllegalStateException("Migrate to new DB"); + } else { + getAapsLogger().error("!!! createOrUpdateMedtronic: Need to migrate to new DB"); + } + UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout); return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord()); - */ } // return true if new record is created @Deprecated @Override public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) { - throw new IllegalStateException("Migrate to new DB"); -/* + if (useNewPumpSync) { + throw new IllegalStateException("Migrate to new DB"); + } else { + getAapsLogger().error("!!! addToHistoryTreatment: Need to migrate to new DB"); + } + boolean medtronicPump = activePlugin.getActivePump() instanceof MedtronicPumpPlugin; getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::isMedtronicPump={} " + medtronicPump); @@ -320,8 +343,8 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface getService().createOrUpdateMedtronic(carbsTreatment, false); //log.debug("Adding new Treatment record" + carbsTreatment); } - if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING) - nsUpload.uploadTreatmentRecord(detailedBolusInfo); +// if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING) +// nsUpload.uploadTreatmentRecord(detailedBolusInfo); if (!allowUpdate && !creatOrUpdateResult.getSuccess()) { getAapsLogger().error("Treatment could not be added to DB", new Exception()); @@ -337,7 +360,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface } return newRecordCreated; - */ + } @Override diff --git a/medtronic/build.gradle b/medtronic/build.gradle index a3cb9f789e..0488efd078 100644 --- a/medtronic/build.gradle +++ b/medtronic/build.gradle @@ -12,6 +12,9 @@ android { versionCode 1 versionName "1.0" } + dataBinding { + enabled = true + } } dependencies { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt index 26660c4936..6b7e738929 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.kt @@ -74,11 +74,11 @@ abstract class PumpPluginAbstract protected constructor( @JvmField protected var pumpState = PumpDriverState.NotInitialized @JvmField protected var displayConnectionMessages = false - var pumpType: PumpType? = null + var pumpType: PumpType = PumpType.GENERIC_AAPS get() = field set(value) { field = value - pumpDescription.setPumpDescription(value!!) + pumpDescription.setPumpDescription(value) } @@ -366,11 +366,11 @@ abstract class PumpPluginAbstract protected constructor( } override fun manufacturer(): ManufacturerType { - return pumpType!!.manufacturer!! + return pumpType.manufacturer!! } override fun model(): PumpType { - return pumpType!! + return pumpType } @@ -395,7 +395,7 @@ abstract class PumpPluginAbstract protected constructor( val temporaryId = generateTempId(detailedBolusInfo.timestamp) val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, temporaryId, detailedBolusInfo.bolusType, - pumpType!!, serialNumber()) + pumpType, serialNumber()) if (response && writeToInternalHistory) { driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo) sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory)) @@ -403,6 +403,7 @@ abstract class PumpPluginAbstract protected constructor( return response } + // TODO protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) { // long temporaryId = generateTempId(temporaryBasal.timestamp); // boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin, diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt index 49b2415264..c9d4009bf7 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicFragment.kt @@ -210,7 +210,6 @@ class MedtronicFragment : DaggerFragment() { } ?: "-" when (medtronicPumpStatus.pumpDeviceState) { - null, PumpDeviceState.Sleeping -> binding.pumpStatusIcon.text = "{fa-bed} " // + pumpStatus.pumpDeviceState.name()); PumpDeviceState.NeverContacted, PumpDeviceState.WakingUp, diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt index 803f281b45..64bb650744 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt @@ -98,7 +98,7 @@ class MedtronicPumpPlugin @Inject constructor( .preferencesId(R.xml.pref_medtronic) .description(R.string.description_pump_medtronic), // PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later - injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers!!, pumpSync!! + injector, resourceHelper, aapsLogger, commandQueue, rxBus, activePlugin, sp, context, fabricPrivacy, dateUtil, aapsSchedulers, pumpSync ), Pump, RileyLinkPumpDevice { private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null @@ -149,7 +149,7 @@ class MedtronicPumpPlugin @Inject constructor( } private val logPrefix: String - private get() = "MedtronicPumpPlugin::" + get() = "MedtronicPumpPlugin::" override fun initPumpStatusData() { medtronicPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L) @@ -225,7 +225,7 @@ class MedtronicPumpPlugin @Inject constructor( // Pump Plugin private val isServiceSet: Boolean - private get() = rileyLinkMedtronicService != null + get() = rileyLinkMedtronicService != null override fun getRileyLinkService(): RileyLinkMedtronicService? { return rileyLinkMedtronicService @@ -313,7 +313,7 @@ class MedtronicPumpPlugin @Inject constructor( }// private val isPumpNotReachable: Boolean - private get() { + get() { val rileyLinkServiceState = rileyLinkServiceData.rileyLinkServiceState if (rileyLinkServiceState == null) { aapsLogger.debug(LTag.PUMP, "RileyLink unreachable. RileyLinkServiceState is null.") @@ -908,7 +908,7 @@ class MedtronicPumpPlugin @Inject constructor( } private val lastPumpEntryTime: Long - private get() { + get() { val lastPumpEntryTime = sp.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L) return try { val localDateTime = DateTimeUtil.toLocalDateTime(lastPumpEntryTime) @@ -1085,7 +1085,7 @@ class MedtronicPumpPlugin @Inject constructor( private fun isProfileValid(basalProfile: BasalProfile): String? { val stringBuilder = StringBuilder() if (medtronicPumpStatus.maxBasal == null) return null - for (profileEntry in basalProfile.entries) { + for (profileEntry in basalProfile.getEntries()) { if (profileEntry.rate > medtronicPumpStatus.maxBasal!!) { stringBuilder.append(profileEntry.startTime!!.toString("HH:mm")) stringBuilder.append("=") @@ -1099,7 +1099,7 @@ class MedtronicPumpPlugin @Inject constructor( val basalProfile = BasalProfile(aapsLogger) for (i in 0..23) { val rate = profile.getBasalTimeFromMidnight(i * 60 * 60) - val v = pumpDescription.pumpType.determineCorrectBasalSize(rate) + val v = pumpType.determineCorrectBasalSize(rate) val basalEntry = BasalProfileEntry(v, i, 0) basalProfile.addEntry(basalEntry) } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java deleted file mode 100644 index 4e855dafa3..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.java +++ /dev/null @@ -1,956 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm; - -import android.os.SystemClock; - -import org.joda.time.LocalDateTime; - -import java.util.Calendar; -import java.util.GregorianCalendar; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkCommunicationManager; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RileyLinkCommunicationException; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RFSpyResponse; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioPacket; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioResponse; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RLMessageType; -import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RawHistoryPage; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.CarelinkLongMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.CarelinkShortMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.GetHistoryPageCarelinkMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.MessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PacketType; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PumpAckMessageBody; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.PumpMessage; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; -import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Original file created by geoff on 5/30/16. - *

- * Split into 2 implementations, so that we can split it by target device. - Andy - * This was mostly rewritten from Original version, and lots of commands and - * functionality added. - */ -@Singleton -public class MedtronicCommunicationManager extends RileyLinkCommunicationManager { - - @Inject MedtronicPumpStatus medtronicPumpStatus; - @Inject MedtronicPumpPlugin medtronicPumpPlugin; - @Inject MedtronicConverter medtronicConverter; - @Inject MedtronicUtil medtronicUtil; - @Inject MedtronicPumpHistoryDecoder medtronicPumpHistoryDecoder; - - private final int MAX_COMMAND_TRIES = 3; - private final int DEFAULT_TIMEOUT = 2000; - private final long RILEYLINK_TIMEOUT = 15 * 60 * 1000; // 15 min - - private String errorMessage; - private final boolean debugSetCommands = false; - - private boolean doWakeUpBeforeCommand = true; - - // This empty constructor must be kept, otherwise dagger injection might break! - @Inject - public MedtronicCommunicationManager() { - } - - @Inject - public void onInit() { - // we can't do this in the constructor, as sp only gets injected after the constructor has returned - medtronicPumpStatus.setPreviousConnection(sp.getLong( - RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)); - } - - @Override - public PumpMessage createResponseMessage(byte[] payload) { - return new PumpMessage(aapsLogger, payload); - } - - @Override - public void setPumpDeviceState(PumpDeviceState pumpDeviceState) { - this.medtronicPumpStatus.setPumpDeviceState(pumpDeviceState); - } - - public void setDoWakeUpBeforeCommand(boolean doWakeUp) { - this.doWakeUpBeforeCommand = doWakeUp; - } - - - @Override - public boolean isDeviceReachable() { - return isDeviceReachable(false); - } - - - /** - * We do actual wakeUp and compare PumpModel with currently selected one. If returned model is - * not Unknown, pump is reachable. - * - * @return - */ - public boolean isDeviceReachable(boolean canPreventTuneUp) { - - PumpDeviceState state = medtronicPumpStatus.getPumpDeviceState(); - - if (state != PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.WakingUp); - - for (int retry = 0; retry < 5; retry++) { - - aapsLogger.debug(LTag.PUMPCOMM, "isDeviceReachable. Waking pump... " + (retry != 0 ? " (retry " + retry + ")" : "")); - - boolean connected = connectToDevice(); - - if (connected) - return true; - - SystemClock.sleep(1000); - - } - - if (state != PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.PumpUnreachable); - - if (!canPreventTuneUp) { - - long diff = System.currentTimeMillis() - medtronicPumpStatus.getLastConnection(); - - if (diff > RILEYLINK_TIMEOUT) { - serviceTaskExecutor.startTask(new WakeAndTuneTask(injector)); - } - } - - return false; - } - - - private boolean connectToDevice() { - - PumpDeviceState state = medtronicPumpStatus.getPumpDeviceState(); - - // check connection - - byte[] pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData); // simple - RFSpyResponse rfSpyResponse = rfspy.transmitThenReceive(new RadioPacket(injector, pumpMsgContent), (byte) 0, (byte) 200, - (byte) 0, (byte) 0, 25000, (byte) 0); - aapsLogger.info(LTag.PUMPCOMM, "wakeup: raw response is " + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - - if (rfSpyResponse.wasTimeout()) { - aapsLogger.error(LTag.PUMPCOMM, "isDeviceReachable. Failed to find pump (timeout)."); - } else if (rfSpyResponse.looksLikeRadioPacket()) { - RadioResponse radioResponse = new RadioResponse(injector); - - try { - - radioResponse.init(rfSpyResponse.getRaw()); - - if (radioResponse.isValid()) { - - PumpMessage pumpResponse = createResponseMessage(radioResponse.getPayload()); - - if (!pumpResponse.isValid()) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Response is invalid ! [interrupted=%b, timeout=%b]", rfSpyResponse.wasInterrupted(), - rfSpyResponse.wasTimeout())); - } else { - - // radioResponse.rssi; - Object dataResponse = medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), MedtronicCommandType.PumpModel, - pumpResponse.getRawContent()); - - MedtronicDeviceType pumpModel = (MedtronicDeviceType) dataResponse; - boolean valid = (pumpModel != MedtronicDeviceType.Unknown_Device); - - if (medtronicUtil.getMedtronicPumpModel() == null && valid) { - medtronicUtil.setMedtronicPumpModel(pumpModel); - } - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "isDeviceReachable. PumpModel is %s - Valid: %b (rssi=%d)", pumpModel.name(), valid, - radioResponse.rssi)); - - if (valid) { - if (state == PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.WakingUp); - else - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - rememberLastGoodDeviceCommunicationTime(); - - return true; - - } else { - if (state != PumpDeviceState.PumpUnreachable) - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.PumpUnreachable); - } - - } - - } else { - aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to parse radio response: " - + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to decode radio response: " - + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - } - - } else { - aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.getRaw())); - } - - return false; - } - - - @Override - public boolean tryToConnectToDevice() { - return isDeviceReachable(true); - } - - - private PumpMessage runCommandWithArgs(PumpMessage msg) throws RileyLinkCommunicationException { - - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: "); - - PumpMessage rval; - PumpMessage shortMessage = makePumpMessage(msg.getCommandType(), new CarelinkShortMessageBody(new byte[]{0})); - // look for ack from short message - PumpMessage shortResponse = sendAndListen(shortMessage); - if (shortResponse.getCommandType() == MedtronicCommandType.CommandACK) { - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: Got ACK response"); - - rval = sendAndListen(msg); - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, "2nd Response: " + rval); - - return rval; - } else { - aapsLogger.error(LTag.PUMPCOMM, "runCommandWithArgs: Pump did not ack Attention packet"); - return new PumpMessage(aapsLogger, "No ACK after Attention packet."); - } - } - - - private PumpMessage runCommandWithFrames(MedtronicCommandType commandType, List> frames) - throws RileyLinkCommunicationException { - - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: " + commandType.name()); - - PumpMessage rval = null; - PumpMessage shortMessage = makePumpMessage(commandType, new CarelinkShortMessageBody(new byte[]{0})); - // look for ack from short message - PumpMessage shortResponse = sendAndListen(shortMessage); - - if (shortResponse.getCommandType() != MedtronicCommandType.CommandACK) { - aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ack Attention packet"); - - return new PumpMessage(aapsLogger, "No ACK after start message."); - } else { - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for Attention packet"); - } - - int frameNr = 1; - - for (List frame : frames) { - - byte[] frameData = medtronicUtil.createByteArray(frame); - - // aapsLogger.debug(LTag.PUMPCOMM,"Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData)); - - PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(frameData)); - - rval = sendAndListen(msg); - - // aapsLogger.debug(LTag.PUMPCOMM,"PumpResponse: " + rval); - - if (rval.getCommandType() != MedtronicCommandType.CommandACK) { - aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ACK frame #" + frameNr); - - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Run command with Frames FAILED (command=%s, response=%s)", commandType.name(), - rval.toString())); - - return new PumpMessage(aapsLogger, "No ACK after frame #" + frameNr); - } else { - aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for frame #" + frameNr); - } - - frameNr++; - } - - return rval; - - } - - - public PumpHistoryResult getPumpHistory(PumpHistoryEntry lastEntry, LocalDateTime targetDate) { - - PumpHistoryResult pumpTotalResult = new PumpHistoryResult(aapsLogger, lastEntry, targetDate == null ? null - : DateTimeUtil.toATechDate(targetDate)); - - if (doWakeUpBeforeCommand) - wakeUp(receiverDeviceAwakeForMinutes, false); - - aapsLogger.debug(LTag.PUMPCOMM, "Current command: " + medtronicUtil.getCurrentCommand()); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Active); - boolean doneWithError = false; - - for (int pageNumber = 0; pageNumber < 5; pageNumber++) { - - RawHistoryPage rawHistoryPage = new RawHistoryPage(aapsLogger); - // wakeUp(receiverDeviceAwakeForMinutes, false); - PumpMessage getHistoryMsg = makePumpMessage(MedtronicCommandType.GetHistoryData, - new GetHistoryPageCarelinkMessageBody(pageNumber)); - - aapsLogger.info(LTag.PUMPCOMM, "getPumpHistory: Page " + pageNumber); - // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData())); - // Ask the pump to transfer history (we get first frame?) - - PumpMessage firstResponse = null; - boolean failed = false; - - medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, null); - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - firstResponse = runCommandWithArgs(getHistoryMsg); - failed = false; - break; - } catch (RileyLinkCommunicationException e) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "First call for PumpHistory failed (retry=%d)", retries)); - failed = true; - } - } - - if (failed) { - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - return pumpTotalResult; - } - - // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); - - PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); - GetHistoryPageCarelinkMessageBody currentResponse = new GetHistoryPageCarelinkMessageBody(firstResponse.getMessageBody().getTxData()); - int expectedFrameNum = 1; - boolean done = false; - // while (expectedFrameNum == currentResponse.getFrameNumber()) { - - int failures = 0; - while (!done) { - // examine current response for problems. - byte[] frameData = currentResponse.getFrameData(); - if ((frameData != null) && (frameData.length > 0) - && currentResponse.getFrameNumber() == expectedFrameNum) { - // success! got a frame. - if (frameData.length != 64) { - aapsLogger.warn(LTag.PUMPCOMM, "Expected frame of length 64, got frame of length " + frameData.length); - // but append it anyway? - } - // handle successful frame data - rawHistoryPage.appendData(currentResponse.getFrameData()); - // RileyLinkMedtronicService.getInstance().announceProgress(((100 / 16) * - // currentResponse.getFrameNumber() + 1)); - medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, - currentResponse.getFrameNumber()); - - aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Got frame %d of Page %d", currentResponse.getFrameNumber(), pageNumber)); - // Do we need to ask for the next frame? - if (expectedFrameNum < 16) { // This number may not be correct for pumps other than 522/722 - expectedFrameNum++; - } else { - done = true; // successful completion - } - } else { - if (frameData == null) { - aapsLogger.error(LTag.PUMPCOMM, "null frame data, retrying"); - } else if (currentResponse.getFrameNumber() != expectedFrameNum) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Expected frame number %d, received %d (retrying)", expectedFrameNum, - currentResponse.getFrameNumber())); - } else if (frameData.length == 0) { - aapsLogger.warn(LTag.PUMPCOMM, "Frame has zero length, retrying"); - } - failures++; - if (failures == 6) { - aapsLogger.error(LTag.PUMPCOMM, - String.format(Locale.ENGLISH, "getPumpHistory: 6 failures in attempting to download frame %d of page %d, giving up.", - expectedFrameNum, pageNumber)); - done = true; // failure completion. - doneWithError = true; - } - } - - if (!done) { - // ask for next frame - PumpMessage nextMsg = null; - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - nextMsg = sendAndListen(ackMsg); - break; - } catch (RileyLinkCommunicationException e) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Problem acknowledging frame response. (retry=%d)", retries)); - } - } - - if (nextMsg != null) - currentResponse = new GetHistoryPageCarelinkMessageBody(nextMsg.getMessageBody().getTxData()); - else { - aapsLogger.error(LTag.PUMPCOMM, "We couldn't acknowledge frame from pump, aborting operation."); - } - } - } - - if (rawHistoryPage.getLength() != 1024) { - aapsLogger.warn(LTag.PUMPCOMM, "getPumpHistory: short page. Expected length of 1024, found length of " - + rawHistoryPage.getLength()); - doneWithError = true; - } - - if (!rawHistoryPage.isChecksumOK()) { - aapsLogger.error(LTag.PUMPCOMM, "getPumpHistory: checksum is wrong"); - doneWithError = true; - } - - if (doneWithError) { - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - return pumpTotalResult; - } - - rawHistoryPage.dumpToDebug(); - - List medtronicHistoryEntries = medtronicPumpHistoryDecoder.processPageAndCreateRecords(rawHistoryPage); - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Found %d history entries.", medtronicHistoryEntries.size())); - - pumpTotalResult.addHistoryEntries(medtronicHistoryEntries, pageNumber); - - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Search status: Search finished: %b", pumpTotalResult.isSearchFinished())); - - if (pumpTotalResult.isSearchFinished()) { - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return pumpTotalResult; - } - } - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return pumpTotalResult; - - } - - - public String getErrorResponse() { - return this.errorMessage; - } - - - @Override - public byte[] createPumpMessageContent(RLMessageType type) { - switch (type) { - case PowerOn: - return medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.RFPowerOn, // - new byte[]{2, 1, (byte) receiverDeviceAwakeForMinutes}); // maybe this is better FIXME - - case ReadSimpleData: - return medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.PumpModel, null); - } - return new byte[0]; - } - - - private PumpMessage makePumpMessage(MedtronicCommandType messageType, byte[] body) { - return makePumpMessage(messageType, body == null ? new CarelinkShortMessageBody() - : new CarelinkShortMessageBody(body)); - } - - - private PumpMessage makePumpMessage(MedtronicCommandType messageType) { - return makePumpMessage(messageType, (byte[]) null); - } - - - private PumpMessage makePumpMessage(MedtronicCommandType messageType, MessageBody messageBody) { - PumpMessage msg = new PumpMessage(aapsLogger); - msg.init(PacketType.Carelink, rileyLinkServiceData.pumpIDBytes, messageType, messageBody); - return msg; - } - - - private PumpMessage sendAndGetResponse(MedtronicCommandType commandType) throws RileyLinkCommunicationException { - - return sendAndGetResponse(commandType, null, DEFAULT_TIMEOUT); - } - - - /** - * Main wrapper method for sending data - (for getting responses) - * - * @param commandType - * @param bodyData - * @param timeoutMs - * @return - */ - private PumpMessage sendAndGetResponse(MedtronicCommandType commandType, byte[] bodyData, int timeoutMs) - throws RileyLinkCommunicationException { - // wakeUp - if (doWakeUpBeforeCommand) - wakeUp(receiverDeviceAwakeForMinutes, false); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Active); - - // create message - PumpMessage msg; - - if (bodyData == null) - msg = makePumpMessage(commandType); - else - msg = makePumpMessage(commandType, bodyData); - - // send and wait for response - PumpMessage response = sendAndListen(msg, timeoutMs); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return response; - } - - - private PumpMessage sendAndListen(PumpMessage msg) throws RileyLinkCommunicationException { - return sendAndListen(msg, 4000); // 2000 - } - - - // All pump communications go through this function. - @Override - protected PumpMessage sendAndListen(PumpMessage msg, int timeout_ms) throws RileyLinkCommunicationException { - return super.sendAndListen(msg, timeout_ms); - } - - - private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType) { - - return sendAndGetResponseWithCheck(commandType, null); - } - - - private Object sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData) { - - aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - - String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength()); - - if (check == null) { - - Object dataResponse = medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, response.getRawContent()); - - if (dataResponse != null) { - this.errorMessage = null; - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), dataResponse)); - - return dataResponse; - } else { - this.errorMessage = "Error decoding response."; - } - } else { - this.errorMessage = check; - // return null; - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - - } - - return null; - } - - - private T sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData, Class clazz) { - - aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); - - for (int retries = 0; retries < MAX_COMMAND_TRIES; retries++) { - - try { - PumpMessage response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - - String check = checkResponseContent(response, commandType.getCommandDescription(), commandType.getExpectedLength()); - - if (check == null) { - - T dataResponse = (T)medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, response.getRawContent()); - - if (dataResponse != null) { - this.errorMessage = null; - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), dataResponse)); - - return dataResponse; - } else { - this.errorMessage = "Error decoding response."; - } - } else { - this.errorMessage = check; - // return null; - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - - } - - return null; - } - - - private String checkResponseContent(PumpMessage response, String method, int expectedLength) { - - if (!response.isValid()) { - String responseData = String.format("%s: Invalid response.", method); - aapsLogger.warn(LTag.PUMPCOMM, responseData); - return responseData; - } - - byte[] contents = response.getRawContent(); - - if (contents != null) { - if (contents.length >= expectedLength) { - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Content: %s", method, ByteUtil.shortHexString(contents))); - return null; - - } else { - String responseData = String.format( - "%s: Cannot return data. Data is too short [expected=%s, received=%s].", method, "" - + expectedLength, "" + contents.length); - - aapsLogger.warn(LTag.PUMPCOMM, responseData); - return responseData; - } - } else { - String responseData = String.format("%s: Cannot return data. Null response.", method); - aapsLogger.warn(LTag.PUMPCOMM, responseData); - return responseData; - } - } - - - // PUMP SPECIFIC COMMANDS - - public Double getRemainingInsulin() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin); - - return responseObject == null ? null : (Double) responseObject; - } - - - public MedtronicDeviceType getPumpModel() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel); - - return responseObject == null ? null : (MedtronicDeviceType) responseObject; - } - - - public BasalProfile getBasalProfile() { - - // wakeUp - if (doWakeUpBeforeCommand) - wakeUp(receiverDeviceAwakeForMinutes, false); - - MedtronicCommandType commandType = MedtronicCommandType.GetBasalProfileSTD; - - aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: " + commandType); - - medtronicUtil.setCurrentCommand(commandType); - - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Active); - - for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) { - - try { - // create message - PumpMessage msg; - - msg = makePumpMessage(commandType); - - // send and wait for response - - PumpMessage response = sendAndListen(msg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - -// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); -// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData())); - - String check = checkResponseContent(response, commandType.getCommandDescription(), 1); - - byte[] data = null; - - if (check == null) { - - data = response.getRawContentOfFrame(); - - PumpMessage ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, new PumpAckMessageBody()); - - while (checkIfWeHaveMoreData(commandType, response, data)) { - - response = sendAndListen(ackMsg, DEFAULT_TIMEOUT + (DEFAULT_TIMEOUT * retries)); - -// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, HexDump.toHexStringDisplayable(response2.getRawContent())); -// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, -// HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData())); - - String check2 = checkResponseContent(response, commandType.getCommandDescription(), 1); - - if (check2 == null) { - - data = ByteUtil.concat(data, response.getRawContentOfFrame()); - - } else { - this.errorMessage = check2; - aapsLogger.error(LTag.PUMPCOMM, "Error with response got GetProfile: " + check2); - } - } - - } else { - errorMessage = check; - } - - BasalProfile basalProfile = (BasalProfile) medtronicConverter.convertResponse(medtronicPumpPlugin.getPumpDescription().getPumpType(), commandType, data); - - if (basalProfile != null) { - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name(), basalProfile)); - - medtronicUtil.setCurrentCommand(null); - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return basalProfile; - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - } - - aapsLogger.warn(LTag.PUMPCOMM, "Error reading profile in max retries."); - medtronicUtil.setCurrentCommand(null); - medtronicPumpStatus.setPumpDeviceState(PumpDeviceState.Sleeping); - - return null; - - } - - - private boolean checkIfWeHaveMoreData(MedtronicCommandType commandType, PumpMessage response, byte[] data) { - - if (commandType == MedtronicCommandType.GetBasalProfileSTD || // - commandType == MedtronicCommandType.GetBasalProfileA || // - commandType == MedtronicCommandType.GetBasalProfileB) { - byte[] responseRaw = response.getRawContentOfFrame(); - - int last = responseRaw.length - 1; - - aapsLogger.debug(LTag.PUMPCOMM, "Length: " + data.length); - - if (data.length >= BasalProfile.MAX_RAW_DATA_SIZE) { - return false; - } - - if (responseRaw.length < 2) { - return false; - } - - return !(responseRaw[last] == 0x00 && responseRaw[last - 1] == 0x00 && responseRaw[last - 2] == 0x00); - } - - return false; - } - - - public ClockDTO getPumpTime() { - - ClockDTO clockDTO = new ClockDTO(); - clockDTO.setLocalDeviceTime(new LocalDateTime()); - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock); - - if (responseObject != null) { - clockDTO.setPumpTime((LocalDateTime) responseObject); - return clockDTO; - } - - return null; - } - - - public TempBasalPair getTemporaryBasal() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.ReadTemporaryBasal); - - return responseObject == null ? null : (TempBasalPair) responseObject; - } - - - public Map getPumpSettings() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.getSettings(medtronicUtil - .getMedtronicPumpModel())); - - return responseObject == null ? null : (Map) responseObject; - } - - - public Boolean setBolus(double units) { - - aapsLogger.info(LTag.PUMPCOMM, "setBolus: " + units); - - return setCommand(MedtronicCommandType.SetBolus, medtronicUtil.getBolusStrokes(units)); - - } - - - public boolean setTBR(TempBasalPair tbr) { - - aapsLogger.info(LTag.PUMPCOMM, "setTBR: " + tbr.getDescription()); - - return setCommand(MedtronicCommandType.SetTemporaryBasal, tbr.getAsRawData()); - } - - - public Boolean setPumpTime() { - - GregorianCalendar gc = new GregorianCalendar(); - gc.add(Calendar.SECOND, 5); - - aapsLogger.info(LTag.PUMPCOMM, "setPumpTime: " + DateTimeUtil.toString(gc)); - - int i = 1; - byte[] data = new byte[8]; - data[0] = 7; - data[i] = (byte) gc.get(Calendar.HOUR_OF_DAY); - data[i + 1] = (byte) gc.get(Calendar.MINUTE); - data[i + 2] = (byte) gc.get(Calendar.SECOND); - - byte[] yearByte = MedtronicUtil.getByteArrayFromUnsignedShort(gc.get(Calendar.YEAR), true); - - data[i + 3] = yearByte[0]; - data[i + 4] = yearByte[1]; - - data[i + 5] = (byte) (gc.get(Calendar.MONTH) + 1); - data[i + 6] = (byte) gc.get(Calendar.DAY_OF_MONTH); - - //aapsLogger.info(LTag.PUMPCOMM,"setPumpTime: Body: " + ByteUtil.getHex(data)); - - return setCommand(MedtronicCommandType.SetRealTimeClock, data); - - } - - - private boolean setCommand(MedtronicCommandType commandType, byte[] body) { - - for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) { - - try { - if (this.doWakeUpBeforeCommand) - wakeUp(false); - - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Body - %s", commandType.getCommandDescription(), - ByteUtil.getHex(body))); - - PumpMessage msg = makePumpMessage(commandType, new CarelinkLongMessageBody(body)); - - PumpMessage pumpMessage = runCommandWithArgs(msg); - - if (debugSetCommands) - aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: %s", commandType.getCommandDescription(), pumpMessage.getResponseContent())); - - if (pumpMessage.getCommandType() == MedtronicCommandType.CommandACK) { - return true; - } else { - aapsLogger.warn(LTag.PUMPCOMM, "We received non-ACK response from pump: " + pumpMessage.getResponseContent()); - } - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - } - - return false; - } - - - public boolean cancelTBR() { - return setTBR(new TempBasalPair(0.0d, false, 0)); - } - - - public BatteryStatusDTO getRemainingBattery() { - - Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus); - - return responseObject == null ? null : (BatteryStatusDTO) responseObject; - } - - - public Boolean setBasalProfile(BasalProfile basalProfile) { - - List> basalProfileFrames = medtronicUtil.getBasalProfileFrames(basalProfile.getRawData()); - - for (int retries = 0; retries <= MAX_COMMAND_TRIES; retries++) { - - PumpMessage responseMessage = null; - try { - responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, - basalProfileFrames); - - if (responseMessage.getCommandType() == MedtronicCommandType.CommandACK) - return true; - - } catch (RileyLinkCommunicationException e) { - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.getMessage(), retries + 1)); - } - - if (responseMessage != null) - aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Set Basal Profile: Invalid response: commandType=%s,rawData=%s", responseMessage.getCommandType(), ByteUtil.shortHexString(responseMessage.getRawContent()))); - else - aapsLogger.warn(LTag.PUMPCOMM, "Set Basal Profile: Null response."); - } - - return false; - - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt new file mode 100644 index 0000000000..e913ff52f7 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/MedtronicCommunicationManager.kt @@ -0,0 +1,664 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm + +import android.os.SystemClock +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDeviceState +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkCommunicationManager +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RileyLinkCommunicationException +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioPacket +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioResponse +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.defs.RLMessageType +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.tasks.WakeAndTuneTask +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.MedtronicPumpPlugin +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RawHistoryPage +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.MedtronicPumpHistoryDecoder +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryResult +import info.nightscout.androidaps.plugins.pump.medtronic.comm.message.* +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BatteryStatusDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.ClockDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.PumpSettingDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicCommandType.Companion.getSettings +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.driver.MedtronicPumpStatus +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil.Companion.createByteArray +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil.Companion.getByteArrayFromUnsignedShort +import org.joda.time.LocalDateTime +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton +import kotlin.jvm.Throws + +/** + * Original file created by geoff on 5/30/16. + * + * + * Split into 2 implementations, so that we can split it by target device. - Andy + * This was mostly rewritten from Original version, and lots of commands and + * functionality added. + */ +@Singleton +class MedtronicCommunicationManager // This empty constructor must be kept, otherwise dagger injection might break! +@Inject constructor() : RileyLinkCommunicationManager() { + + @Inject lateinit var medtronicPumpStatus: MedtronicPumpStatus + @Inject lateinit var medtronicPumpPlugin: MedtronicPumpPlugin + @Inject lateinit var medtronicConverter: MedtronicConverter + @Inject lateinit var medtronicUtil: MedtronicUtil + @Inject lateinit var medtronicPumpHistoryDecoder: MedtronicPumpHistoryDecoder + + private val MAX_COMMAND_TRIES = 3 + private val DEFAULT_TIMEOUT = 2000 + private val RILEYLINK_TIMEOUT: Long = 15 * 60 * 1000 // 15 min + + var errorResponse: String? = null + private set + private val debugSetCommands = false + private var doWakeUpBeforeCommand = true + + @Inject + open fun onInit(): Unit { + // we can't do this in the constructor, as sp only gets injected after the constructor has returned + medtronicPumpStatus.previousConnection = sp.getLong( + RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L) + } + + override fun createResponseMessage(payload: ByteArray): PumpMessage { + return PumpMessage(aapsLogger, payload) + } + + override fun setPumpDeviceState(pumpDeviceState: PumpDeviceState) { + medtronicPumpStatus.pumpDeviceState = pumpDeviceState + } + + fun setDoWakeUpBeforeCommand(doWakeUp: Boolean) { + doWakeUpBeforeCommand = doWakeUp + } + + override fun isDeviceReachable(): Boolean { + return isDeviceReachable(false) + } + + /** + * We do actual wakeUp and compare PumpModel with currently selected one. If returned model is + * not Unknown, pump is reachable. + * + * @return + */ + fun isDeviceReachable(canPreventTuneUp: Boolean): Boolean { + val state = medtronicPumpStatus.pumpDeviceState + if (state !== PumpDeviceState.PumpUnreachable) medtronicPumpStatus.pumpDeviceState = PumpDeviceState.WakingUp + for (retry in 0..4) { + aapsLogger.debug(LTag.PUMPCOMM, "isDeviceReachable. Waking pump... " + if (retry != 0) " (retry $retry)" else "") + val connected = connectToDevice() + if (connected) return true + SystemClock.sleep(1000) + } + if (state !== PumpDeviceState.PumpUnreachable) medtronicPumpStatus.pumpDeviceState = PumpDeviceState.PumpUnreachable + if (!canPreventTuneUp) { + val diff = System.currentTimeMillis() - medtronicPumpStatus.lastConnection + if (diff > RILEYLINK_TIMEOUT) { + serviceTaskExecutor.startTask(WakeAndTuneTask(injector)) + } + } + return false + } + + private fun connectToDevice(): Boolean { + val state = medtronicPumpStatus.pumpDeviceState + + // check connection + val pumpMsgContent = createPumpMessageContent(RLMessageType.ReadSimpleData) // simple + val rfSpyResponse = rfspy.transmitThenReceive(RadioPacket(injector, pumpMsgContent), 0.toByte(), 200.toByte(), + 0.toByte(), 0.toByte(), 25000, 0.toByte()) + aapsLogger.info(LTag.PUMPCOMM, "wakeup: raw response is " + ByteUtil.shortHexString(rfSpyResponse.raw)) + if (rfSpyResponse.wasTimeout()) { + aapsLogger.error(LTag.PUMPCOMM, "isDeviceReachable. Failed to find pump (timeout).") + } else if (rfSpyResponse.looksLikeRadioPacket()) { + val radioResponse = RadioResponse(injector) + try { + radioResponse.init(rfSpyResponse.raw) + if (radioResponse.isValid) { + val pumpResponse = createResponseMessage(radioResponse.payload) + if (!pumpResponse.isValid) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Response is invalid ! [interrupted=%b, timeout=%b]", rfSpyResponse.wasInterrupted(), + rfSpyResponse.wasTimeout())) + } else { + + // radioResponse.rssi; + val dataResponse = medtronicConverter!!.convertResponse(medtronicPumpStatus.pumpType, MedtronicCommandType.PumpModel, + pumpResponse.rawContent) + val pumpModel = dataResponse as MedtronicDeviceType? + val valid = pumpModel !== MedtronicDeviceType.Unknown_Device + if (medtronicUtil.medtronicPumpModel == null && valid) { + medtronicUtil.medtronicPumpModel = pumpModel + } + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "isDeviceReachable. PumpModel is %s - Valid: %b (rssi=%d)", pumpModel!!.name, valid, + radioResponse.rssi)) + if (valid) { + if (state === PumpDeviceState.PumpUnreachable) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.WakingUp + else + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + rememberLastGoodDeviceCommunicationTime() + return true + } else { + if (state !== PumpDeviceState.PumpUnreachable) medtronicPumpStatus.pumpDeviceState = PumpDeviceState.PumpUnreachable + } + } + } else { + aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to parse radio response: " + + ByteUtil.shortHexString(rfSpyResponse.raw)) + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Failed to decode radio response: " + + ByteUtil.shortHexString(rfSpyResponse.raw)) + } + } else { + aapsLogger.warn(LTag.PUMPCOMM, "isDeviceReachable. Unknown response: " + ByteUtil.shortHexString(rfSpyResponse.raw)) + } + return false + } + + override fun tryToConnectToDevice(): Boolean { + return isDeviceReachable(true) + } + + @Throws(RileyLinkCommunicationException::class) + private fun runCommandWithArgs(msg: PumpMessage): PumpMessage { + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: ") + val rval: PumpMessage + val shortMessage = makePumpMessage(msg.commandType, CarelinkShortMessageBody(byteArrayOf(0))) + // look for ack from short message + val shortResponse = sendAndListen(shortMessage) + return if (shortResponse.commandType === MedtronicCommandType.CommandACK) { + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "Run command with Args: Got ACK response") + rval = sendAndListen(msg) + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, "2nd Response: $rval") + rval + } else { + aapsLogger.error(LTag.PUMPCOMM, "runCommandWithArgs: Pump did not ack Attention packet") + PumpMessage(aapsLogger, "No ACK after Attention packet.") + } + } + + @Throws(RileyLinkCommunicationException::class) + private fun runCommandWithFrames(commandType: MedtronicCommandType, frames: List>): PumpMessage? { + aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: " + commandType.name) + var rval: PumpMessage? = null + val shortMessage = makePumpMessage(commandType, CarelinkShortMessageBody(byteArrayOf(0))) + // look for ack from short message + val shortResponse = sendAndListen(shortMessage) + if (shortResponse.commandType !== MedtronicCommandType.CommandACK) { + aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ack Attention packet") + return PumpMessage(aapsLogger, "No ACK after start message.") + } else { + aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for Attention packet") + } + var frameNr = 1 + for (frame in frames) { + val frameData = createByteArray(frame) + + // aapsLogger.debug(LTag.PUMPCOMM,"Frame {} data:\n{}", frameNr, ByteUtil.getCompactString(frameData)); + val msg = makePumpMessage(commandType, CarelinkLongMessageBody(frameData)) + rval = sendAndListen(msg) + + // aapsLogger.debug(LTag.PUMPCOMM,"PumpResponse: " + rval); + if (rval.commandType !== MedtronicCommandType.CommandACK) { + aapsLogger.error(LTag.PUMPCOMM, "runCommandWithFrames: Pump did not ACK frame #$frameNr") + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Run command with Frames FAILED (command=%s, response=%s)", commandType.name, + rval.toString())) + return PumpMessage(aapsLogger, "No ACK after frame #$frameNr") + } else { + aapsLogger.debug(LTag.PUMPCOMM, "Run command with Frames: Got ACK response for frame #$frameNr") + } + frameNr++ + } + return rval + } + + fun getPumpHistory(lastEntry: PumpHistoryEntry?, targetDate: LocalDateTime?): PumpHistoryResult { + val pumpTotalResult = PumpHistoryResult(aapsLogger, lastEntry, if (targetDate == null) null else DateTimeUtil.toATechDate(targetDate)) + if (doWakeUpBeforeCommand) wakeUp(receiverDeviceAwakeForMinutes, false) + aapsLogger.debug(LTag.PUMPCOMM, "Current command: " + medtronicUtil.getCurrentCommand()) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Active + var doneWithError = false + for (pageNumber in 0..4) { + val rawHistoryPage = RawHistoryPage(aapsLogger) + // wakeUp(receiverDeviceAwakeForMinutes, false); + val getHistoryMsg = makePumpMessage(MedtronicCommandType.GetHistoryData, + GetHistoryPageCarelinkMessageBody(pageNumber)) + aapsLogger.info(LTag.PUMPCOMM, "getPumpHistory: Page $pageNumber") + // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): "+ByteUtil.shortHexString(getHistoryMsg.getTxData())); + // Ask the pump to transfer history (we get first frame?) + var firstResponse: PumpMessage? = null + var failed = false + medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, null) + for (retries in 0 until MAX_COMMAND_TRIES) { + try { + firstResponse = runCommandWithArgs(getHistoryMsg) + failed = false + break + } catch (e: RileyLinkCommunicationException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "First call for PumpHistory failed (retry=%d)", retries)) + failed = true + } + } + if (failed) { + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + + // aapsLogger.info(LTag.PUMPCOMM,"getPumpHistoryPage("+pageNumber+"): " + ByteUtil.shortHexString(firstResponse.getContents())); + val ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, PumpAckMessageBody()) + var currentResponse = GetHistoryPageCarelinkMessageBody(firstResponse!!.messageBody!!.txData) + var expectedFrameNum = 1 + var done = false + // while (expectedFrameNum == currentResponse.getFrameNumber()) { + var failures = 0 + while (!done) { + // examine current response for problems. + val frameData = currentResponse.frameData + if (frameData != null && frameData.size > 0 + && currentResponse.frameNumber == expectedFrameNum) { + // success! got a frame. + if (frameData.size != 64) { + aapsLogger.warn(LTag.PUMPCOMM, "Expected frame of length 64, got frame of length " + frameData.size) + // but append it anyway? + } + // handle successful frame data + rawHistoryPage.appendData(currentResponse.frameData) + // RileyLinkMedtronicService.getInstance().announceProgress(((100 / 16) * + // currentResponse.getFrameNumber() + 1)); + medtronicUtil.setCurrentCommand(MedtronicCommandType.GetHistoryData, pageNumber, + currentResponse.frameNumber) + aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Got frame %d of Page %d", currentResponse.frameNumber, pageNumber)) + // Do we need to ask for the next frame? + if (expectedFrameNum < 16) { // This number may not be correct for pumps other than 522/722 + expectedFrameNum++ + } else { + done = true // successful completion + } + } else { + if (frameData == null) { + aapsLogger.error(LTag.PUMPCOMM, "null frame data, retrying") + } else if (currentResponse.frameNumber != expectedFrameNum) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Expected frame number %d, received %d (retrying)", expectedFrameNum, + currentResponse.frameNumber)) + } else if (frameData.size == 0) { + aapsLogger.warn(LTag.PUMPCOMM, "Frame has zero length, retrying") + } + failures++ + if (failures == 6) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: 6 failures in attempting to download frame %d of page %d, giving up.", + expectedFrameNum, pageNumber)) + done = true // failure completion. + doneWithError = true + } + } + if (!done) { + // ask for next frame + var nextMsg: PumpMessage? = null + for (retries in 0 until MAX_COMMAND_TRIES) { + try { + nextMsg = sendAndListen(ackMsg) + break + } catch (e: RileyLinkCommunicationException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Problem acknowledging frame response. (retry=%d)", retries)) + } + } + if (nextMsg != null) currentResponse = GetHistoryPageCarelinkMessageBody(nextMsg.messageBody!!.txData) else { + aapsLogger.error(LTag.PUMPCOMM, "We couldn't acknowledge frame from pump, aborting operation.") + } + } + } + if (rawHistoryPage.length != 1024) { + aapsLogger.warn(LTag.PUMPCOMM, "getPumpHistory: short page. Expected length of 1024, found length of " + + rawHistoryPage.length) + doneWithError = true + } + if (!rawHistoryPage.isChecksumOK) { + aapsLogger.error(LTag.PUMPCOMM, "getPumpHistory: checksum is wrong") + doneWithError = true + } + if (doneWithError) { + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + rawHistoryPage.dumpToDebug() + val medtronicHistoryEntries = medtronicPumpHistoryDecoder.processPageAndCreateRecords(rawHistoryPage) + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Found %d history entries.", medtronicHistoryEntries.size)) + pumpTotalResult.addHistoryEntries(medtronicHistoryEntries, pageNumber) + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getPumpHistory: Search status: Search finished: %b", pumpTotalResult.isSearchFinished)) + if (pumpTotalResult.isSearchFinished) { + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + } + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return pumpTotalResult + } + + override fun createPumpMessageContent(type: RLMessageType): ByteArray { + return when (type) { + RLMessageType.PowerOn -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.RFPowerOn, byteArrayOf(2, 1, receiverDeviceAwakeForMinutes.toByte())) // maybe this is better FIXME + RLMessageType.ReadSimpleData -> medtronicUtil.buildCommandPayload(rileyLinkServiceData, MedtronicCommandType.PumpModel, null) + } + return ByteArray(0) + } + + private fun makePumpMessage(messageType: MedtronicCommandType, body: ByteArray? = null as ByteArray?): PumpMessage { + return makePumpMessage(messageType, body?.let { CarelinkShortMessageBody(it) } + ?: CarelinkShortMessageBody()) + } + + private fun makePumpMessage(messageType: MedtronicCommandType?, messageBody: MessageBody): PumpMessage { + val msg = PumpMessage(aapsLogger) + msg.init(PacketType.Carelink, rileyLinkServiceData.pumpIDBytes, messageType, messageBody) + return msg + } + + /** + * Main wrapper method for sending data - (for getting responses) + * + * @param commandType + * @param bodyData + * @param timeoutMs + * @return + */ + @Throws(RileyLinkCommunicationException::class) + private fun sendAndGetResponse(commandType: MedtronicCommandType, bodyData: ByteArray? = null, timeoutMs: Int = DEFAULT_TIMEOUT): PumpMessage { + // wakeUp + if (doWakeUpBeforeCommand) wakeUp(receiverDeviceAwakeForMinutes, false) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Active + + // create message + val msg: PumpMessage + msg = bodyData?.let { makePumpMessage(commandType, it) } ?: makePumpMessage(commandType) + + // send and wait for response + val response = sendAndListen(msg, timeoutMs) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return response + } + + @Throws(RileyLinkCommunicationException::class) + private fun sendAndListen(msg: PumpMessage): PumpMessage { + return sendAndListen(msg, 4000) // 2000 + } + + // All pump communications go through this function. + @Throws(RileyLinkCommunicationException::class) + protected /*override*/ fun sendAndListen(msg: PumpMessage, timeout_ms: Int): PumpMessage { + return super.sendAndListen(msg, timeout_ms)!! + } + + private fun sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray? = null): Any? { + aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: $commandType") + for (retries in 0 until MAX_COMMAND_TRIES) { + try { + val response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) + val check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength) + if (check == null) { + val dataResponse = medtronicConverter.convertResponse(medtronicPumpStatus.pumpType, commandType, response.rawContent) + if (dataResponse != null) { + errorResponse = null + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, dataResponse)) + return dataResponse + } else { + errorResponse = "Error decoding response." + } + } else { + errorResponse = check + // return null; + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + } + return null + } + + // private fun sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray, clazz: Class): T? { + // aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: $commandType") + // for (retries in 0 until MAX_COMMAND_TRIES) { + // try { + // val response = sendAndGetResponse(commandType, bodyData, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) + // val check = checkResponseContent(response, commandType.commandDescription, commandType.expectedLength) + // if (check == null) { + // val dataResponse = medtronicConverter!!.convertResponse(medtronicPumpPlugin!!.pumpDescription.pumpType, commandType, response.rawContent) as T? + // if (dataResponse != null) { + // errorResponse = null + // aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, dataResponse)) + // return dataResponse + // } else { + // errorResponse = "Error decoding response." + // } + // } else { + // errorResponse = check + // // return null; + // } + // } catch (e: RileyLinkCommunicationException) { + // aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + // } + // } + // return null + // } + + private fun checkResponseContent(response: PumpMessage, method: String, expectedLength: Int): String? { + if (!response.isValid) { + val responseData = String.format("%s: Invalid response.", method) + aapsLogger.warn(LTag.PUMPCOMM, responseData) + return responseData + } + val contents = response.rawContent + return if (contents != null) { + if (contents.size >= expectedLength) { + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Content: %s", method, ByteUtil.shortHexString(contents))) + null + } else { + val responseData = String.format( + "%s: Cannot return data. Data is too short [expected=%s, received=%s].", method, "" + + expectedLength, "" + contents.size) + aapsLogger.warn(LTag.PUMPCOMM, responseData) + responseData + } + } else { + val responseData = String.format("%s: Cannot return data. Null response.", method) + aapsLogger.warn(LTag.PUMPCOMM, responseData) + responseData + } + } + + // PUMP SPECIFIC COMMANDS + fun getRemainingInsulin(): Double? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRemainingInsulin) + return if (responseObject == null) null else responseObject as Double? + } + + fun getPumpModel(): MedtronicDeviceType? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.PumpModel) + return if (responseObject == null) null else responseObject as MedtronicDeviceType? + } + + + + fun getBasalProfile(): BasalProfile? { + + // wakeUp + if (doWakeUpBeforeCommand) wakeUp(receiverDeviceAwakeForMinutes, false) + val commandType = MedtronicCommandType.GetBasalProfileSTD + aapsLogger.debug(LTag.PUMPCOMM, "getDataFromPump: $commandType") + medtronicUtil.setCurrentCommand(commandType) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Active + for (retries in 0..MAX_COMMAND_TRIES) { + try { + // create message + var msg: PumpMessage + msg = makePumpMessage(commandType) + + // send and wait for response + var response = sendAndListen(msg, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) + +// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getRawContent())); +// aapsLogger.debug(LTag.PUMPCOMM,"1st Response: " + HexDump.toHexStringDisplayable(response.getMessageBody().getTxData())); + val check = checkResponseContent(response, commandType.commandDescription, 1) + var data: ByteArray? = null + if (check == null) { + data = response.rawContentOfFrame + val ackMsg = makePumpMessage(MedtronicCommandType.CommandACK, PumpAckMessageBody()) + while (checkIfWeHaveMoreData(commandType, response, data)) { + response = sendAndListen(ackMsg, DEFAULT_TIMEOUT + DEFAULT_TIMEOUT * retries) + +// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, HexDump.toHexStringDisplayable(response2.getRawContent())); +// aapsLogger.debug(LTag.PUMPCOMM,"{} Response: {}", runs, +// HexDump.toHexStringDisplayable(response2.getMessageBody().getTxData())); + val check2 = checkResponseContent(response, commandType.commandDescription, 1) + if (check2 == null) { + data = ByteUtil.concat(data, response.rawContentOfFrame) + } else { + errorResponse = check2 + aapsLogger.error(LTag.PUMPCOMM, "Error with response got GetProfile: $check2") + } + } + } else { + errorResponse = check + } + val basalProfile = medtronicConverter.convertResponse(medtronicPumpPlugin.pumpType, commandType, data) as BasalProfile? + if (basalProfile != null) { + aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Converted response for %s is %s.", commandType.name, basalProfile)) + medtronicUtil.setCurrentCommand(null) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return basalProfile + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.error(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + } + aapsLogger.warn(LTag.PUMPCOMM, "Error reading profile in max retries.") + medtronicUtil.setCurrentCommand(null) + medtronicPumpStatus.pumpDeviceState = PumpDeviceState.Sleeping + return null + } + + private fun checkIfWeHaveMoreData(commandType: MedtronicCommandType, response: PumpMessage, data: ByteArray?): Boolean { + if (commandType === MedtronicCommandType.GetBasalProfileSTD || // + commandType === MedtronicCommandType.GetBasalProfileA || // + commandType === MedtronicCommandType.GetBasalProfileB) { + val responseRaw = response.rawContentOfFrame + val last = responseRaw.size - 1 + aapsLogger.debug(LTag.PUMPCOMM, "Length: " + data!!.size) + if (data.size >= BasalProfile.MAX_RAW_DATA_SIZE) { + return false + } + return if (responseRaw.size < 2) { + false + } else !(responseRaw[last] == 0x00.toByte() && responseRaw[last - 1] == 0x00.toByte() && responseRaw[last - 2] == 0x00.toByte()) + } + return false + } + + fun getPumpTime(): ClockDTO? { + val clockDTO = ClockDTO() + clockDTO.localDeviceTime = LocalDateTime() + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetRealTimeClock) + if (responseObject != null) { + clockDTO.pumpTime = responseObject as LocalDateTime? + return clockDTO + } + return null + } + + fun getTemporaryBasal(): TempBasalPair? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.ReadTemporaryBasal) + return if (responseObject == null) null else responseObject as TempBasalPair? + } + + fun getPumpSettings(): Map? { + val responseObject = sendAndGetResponseWithCheck(getSettings(medtronicUtil.medtronicPumpModel)) + return if (responseObject == null) null else responseObject as Map? + } + + fun setBolus(units: Double): Boolean { + aapsLogger.info(LTag.PUMPCOMM, "setBolus: $units") + return setCommand(MedtronicCommandType.SetBolus, medtronicUtil.getBolusStrokes(units)) + } + + fun setTemporaryBasal(tbr: TempBasalPair): Boolean { + aapsLogger.info(LTag.PUMPCOMM, "setTBR: " + tbr.description) + return setCommand(MedtronicCommandType.SetTemporaryBasal, tbr.asRawData) + } + + fun setPumpTime(): Boolean { + val gc = GregorianCalendar() + gc.add(Calendar.SECOND, 5) + aapsLogger.info(LTag.PUMPCOMM, "setPumpTime: " + DateTimeUtil.toString(gc)) + val i = 1 + val data = ByteArray(8) + data[0] = 7 + data[i] = gc[Calendar.HOUR_OF_DAY].toByte() + data[i + 1] = gc[Calendar.MINUTE].toByte() + data[i + 2] = gc[Calendar.SECOND].toByte() + val yearByte = getByteArrayFromUnsignedShort(gc[Calendar.YEAR], true) + data[i + 3] = yearByte[0] + data[i + 4] = yearByte[1] + data[i + 5] = (gc[Calendar.MONTH] + 1).toByte() + data[i + 6] = gc[Calendar.DAY_OF_MONTH].toByte() + + //aapsLogger.info(LTag.PUMPCOMM,"setPumpTime: Body: " + ByteUtil.getHex(data)); + return setCommand(MedtronicCommandType.SetRealTimeClock, data) + } + + private fun setCommand(commandType: MedtronicCommandType, body: ByteArray): Boolean { + for (retries in 0..MAX_COMMAND_TRIES) { + try { + if (doWakeUpBeforeCommand) wakeUp(false) + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: Body - %s", commandType.commandDescription, + ByteUtil.getHex(body))) + val msg = makePumpMessage(commandType, CarelinkLongMessageBody(body)) + val pumpMessage = runCommandWithArgs(msg) + if (debugSetCommands) aapsLogger.debug(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "%s: %s", commandType.commandDescription, pumpMessage.responseContent)) + if (pumpMessage.commandType === MedtronicCommandType.CommandACK) { + return true + } else { + aapsLogger.warn(LTag.PUMPCOMM, "We received non-ACK response from pump: " + pumpMessage.responseContent) + } + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + } + return false + } + + fun cancelTBR(): Boolean { + return setTemporaryBasal(TempBasalPair(0.0, false, 0)) + } + + fun getRemainingBattery(): BatteryStatusDTO? { + val responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.GetBatteryStatus) + return if (responseObject == null) null else responseObject as BatteryStatusDTO? + } + + fun setBasalProfile(basalProfile: BasalProfile): Boolean { + val basalProfileFrames = medtronicUtil.getBasalProfileFrames(basalProfile.rawData) + for (retries in 0..MAX_COMMAND_TRIES) { + var responseMessage: PumpMessage? = null + try { + responseMessage = runCommandWithFrames(MedtronicCommandType.SetBasalProfileSTD, + basalProfileFrames) + if (responseMessage!!.commandType === MedtronicCommandType.CommandACK) return true + } catch (e: RileyLinkCommunicationException) { + aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Error getting response from RileyLink (error=%s, retry=%d)", e.message, retries + 1)) + } + if (responseMessage != null) aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "Set Basal Profile: Invalid response: commandType=%s,rawData=%s", responseMessage.commandType, ByteUtil.shortHexString(responseMessage.rawContent))) else aapsLogger.warn(LTag.PUMPCOMM, "Set Basal Profile: Null response.") + } + return false + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt index 57bc0eab11..0a4db88ede 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt @@ -51,7 +51,7 @@ abstract class MedtronicHistoryDecoder : MedtronicHi } } - fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List? { + fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List { return processPageAndCreateRecords(rawHistoryPage, false) } @@ -120,7 +120,7 @@ abstract class MedtronicHistoryDecoder : MedtronicHi private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List { val dataClear = checkPage(rawHistoryPage, partial) val records: List = createRecords(dataClear) - for (record in records!!) { + for (record in records) { decodeRecord(record) } runPostDecodeTasks() diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt index 77f1ee32c1..83a20262cc 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt @@ -25,14 +25,14 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() override fun decodeRecord(record: CGMSHistoryEntry): RecordDecodeStatus? { return try { - decodeRecord(record, false) + decodeRecordInternal(record) } catch (ex: Exception) { LOG.error(" Error decoding: type={}, ex={}", record.entryType!!.name, ex.message, ex) RecordDecodeStatus.Error } } - fun decodeRecord(entry: CGMSHistoryEntry, ignore: Boolean): RecordDecodeStatus { + fun decodeRecordInternal(entry: CGMSHistoryEntry): RecordDecodeStatus { if (entry.dateTimeLength > 0) { parseDate(entry) } @@ -62,6 +62,7 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() } override fun postProcess() {} + override fun createRecords(dataClearInput: List): List { val dataClear = reverseList(dataClearInput, Byte::class.java) prepareStatistics() diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt index 0a2da5b5be..e9131694d2 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt @@ -79,7 +79,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( listRawData.add(opCode.toByte()) if (entryType === PumpHistoryEntryType.UnabsorbedInsulin || entryType === PumpHistoryEntryType.UnabsorbedInsulin512) { - val elements: Int = dataClear[counter]!!.toInt() + val elements: Int = dataClear[counter].toInt() listRawData.add(elements.toByte()) counter++ val els = getUnsignedInt(elements) @@ -106,12 +106,12 @@ class MedtronicPumpHistoryDecoder @Inject constructor( if (incompletePacket) break } if (entryType === PumpHistoryEntryType.None) { - aapsLogger!!.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch.") + aapsLogger.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch.") } else { if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) { pe.opCode = opCode.toByte() } - if (entryType.getHeadLength(medtronicUtil!!.medtronicPumpModel!!) == 0) special = true + if (entryType.getHeadLength(medtronicUtil.medtronicPumpModel!!) == 0) special = true pe.setData(listRawData as List, special) val decoded = decodeRecord(pe) if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) { @@ -132,7 +132,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( override fun decodeRecord(record: PumpHistoryEntry): RecordDecodeStatus? { return try { - decodeRecord(record, false) + decodeRecordInternal(record) } catch (ex: Exception) { aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex)) //ex.printStackTrace() @@ -140,7 +140,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( } } - private fun decodeRecord(entry: PumpHistoryEntry, x: Boolean): RecordDecodeStatus { + private fun decodeRecordInternal(entry: PumpHistoryEntry): RecordDecodeStatus { if (entry.dateTimeLength > 0) { decodeDateTime(entry) } @@ -169,6 +169,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( PumpHistoryEntryType.TempBasalDuration -> // decodeTempBasal(entry); RecordDecodeStatus.OK + PumpHistoryEntryType.TempBasalRate -> // decodeTempBasal(entry); RecordDecodeStatus.OK @@ -254,7 +255,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor( val body = entry.body!! val dto = BolusWizardDTO() var bolusStrokes = 10.0f - if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { + if (MedtronicDeviceType.isSameDevice(medtronicUtil.medtronicPumpModel!!, MedtronicDeviceType.Medtronic_523andHigher)) { // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 bolusStrokes = 40.0f dto.carbs = ((body[1] and 0x0c.toByte()).toInt() shl 6) + body[0] diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt index 7cb40c46e6..a5a7cbfaa8 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -69,10 +69,10 @@ class PumpHistoryEntry : MedtronicHistoryEntry() { override val dateLength: Int get() = entryType!!.dateLength - override fun equals(o: Any?): Boolean { - if (this === o) return true - if (o !is PumpHistoryEntry) return false - val that = o + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other !is PumpHistoryEntry) return false + val that = other return entryType == that.entryType && // atechDateTime === that.atechDateTime // && // // Objects.equals(this.decodedData, that.decodedData); diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt index b772119de8..09d694f061 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt @@ -81,8 +81,8 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis } override fun toString(): String { - return "PumpHistoryResult [unprocessed=" + (if (unprocessedEntries != null) "" + unprocessedEntries!!.size else "0") + // - ", valid=" + (if (validEntries != null) "" + validEntries!!.size else "0") + // + return "PumpHistoryResult [unprocessed=" + unprocessedEntries.size + // + ", valid=" + validEntries.size + // ", searchEntry=" + searchEntry + // ", searchDate=" + searchDate + // ", searchType=" + searchType + // diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt index 815ca14549..addcd5d2c3 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/ui/MedtronicUITask.kt @@ -53,19 +53,19 @@ class MedtronicUITask { aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. $commandType") when (commandType) { MedtronicCommandType.PumpModel -> { - result = communicationManager.pumpModel + result = communicationManager.getPumpModel() } MedtronicCommandType.GetBasalProfileSTD -> { - result = communicationManager.basalProfile + result = communicationManager.getBasalProfile() } MedtronicCommandType.GetRemainingInsulin -> { - result = communicationManager.remainingInsulin + result = communicationManager.getRemainingInsulin() } MedtronicCommandType.GetRealTimeClock -> { - result = communicationManager.pumpTime + result = communicationManager.getPumpTime() medtronicUtil.pumpTime = null } @@ -74,22 +74,22 @@ class MedtronicUITask { } MedtronicCommandType.GetBatteryStatus -> { - result = communicationManager.remainingBattery + result = communicationManager.getRemainingBattery() } MedtronicCommandType.SetTemporaryBasal -> { - val tbr = tBRSettings + val tbr = getTbrSettings() if (tbr != null) { - result = communicationManager.setTBR(tbr) + result = communicationManager.setTemporaryBasal(tbr) } } MedtronicCommandType.ReadTemporaryBasal -> { - result = communicationManager.temporaryBasal + result = communicationManager.getTemporaryBasal() } MedtronicCommandType.Settings, MedtronicCommandType.Settings_512 -> { - result = communicationManager.pumpSettings + result = communicationManager.getPumpSettings() } MedtronicCommandType.SetBolus -> { @@ -127,12 +127,11 @@ class MedtronicUITask { } } - // - // - private val tBRSettings: TempBasalPair - private get() = TempBasalPair(getDoubleFromParameters(0), // + private fun getTbrSettings(): TempBasalPair? { + return TempBasalPair(getDoubleFromParameters(0), // false, // getIntegerFromParameters(1)) + } private fun getFloatFromParameters(index: Int): Float { return parameters!![index] as Float diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt index 92720b72f2..b1af19654a 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/BasalProfile.kt @@ -96,7 +96,7 @@ class BasalProfile { fun dumpBasalProfile() { aapsLogger.debug(LTag.PUMPCOMM, "Basal Profile entries:") - val entries = entries + val entries = getEntries() for (i in entries.indices) { val entry = entries[i] val startString = entry.startTime!!.toString("HH:mm") @@ -109,7 +109,7 @@ class BasalProfile { val basalProfileAsString: String get() { val sb = StringBuffer("Basal Profile entries:\n") - val entries = entries + val entries = getEntries() for (i in entries.indices) { val entry = entries[i] val startString = entry.startTime!!.toString("HH:mm") @@ -124,7 +124,7 @@ class BasalProfile { fun basalProfileToString(): String { val sb = StringBuffer("Basal Profile [") - val entries = entries + val entries = getEntries() for (i in entries.indices) { val entry = entries[i] val startString = entry.startTime!!.toString("HH:mm") @@ -138,7 +138,7 @@ class BasalProfile { // and changes to the profiles themselves. fun getEntryForTime(`when`: Instant): BasalProfileEntry { var rval = BasalProfileEntry() - val entries = entries + val entries = getEntries() if (entries.size == 0) { aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): table is empty", `when`.toDateTime().toLocalTime().toString("HH:mm"))) @@ -181,31 +181,30 @@ class BasalProfile { }// readUnsignedByte(mRawData[i]); // an empty list - val entries: List - get() { - val entries: MutableList = ArrayList() - if (rawData == null || rawData!![2] == 0x3f.toByte()) { - aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.") - return entries // an empty list - } - var r: Int - var st: Int - var i = 0 - while (i < rawData!!.size - 2) { - if (rawData!![i] == 0.toByte() && rawData!![i + 1] == 0.toByte() && rawData!![i + 2] == 0.toByte()) break - if (rawData!![i] == 0.toByte() && rawData!![i + 1] == 0.toByte() && rawData!![i + 2] == 0x3f.toByte()) break - r = MedtronicUtil.makeUnsignedShort(rawData!![i + 1].toInt(), rawData!![i].toInt()) // readUnsignedByte(mRawData[i]); - st = readUnsignedByte(rawData!![i + 2]) - try { - entries.add(BasalProfileEntry(aapsLogger, r, st)) - } catch (ex: Exception) { - aapsLogger.error(LTag.PUMPCOMM, "Error decoding basal profile from bytes: " + ByteUtil.shortHexString(rawData)) - throw ex - } - i += 3 - } - return entries + fun getEntries(): List { + val entries: MutableList = ArrayList() + if (rawData[2] == 0x3f.toByte()) { + aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.") + return entries // an empty list } + var r: Int + var st: Int + var i = 0 + while (i < rawData.size - 2) { + if (rawData[i] == 0.toByte() && rawData[i + 1] == 0.toByte() && rawData[i + 2] == 0.toByte()) break + if (rawData[i] == 0.toByte() && rawData[i + 1] == 0.toByte() && rawData[i + 2] == 0x3f.toByte()) break + r = MedtronicUtil.makeUnsignedShort(rawData[i + 1].toInt(), rawData[i].toInt()) // readUnsignedByte(mRawData[i]); + st = readUnsignedByte(rawData[i + 2]) + try { + entries.add(BasalProfileEntry(aapsLogger, r, st)) + } catch (ex: Exception) { + aapsLogger.error(LTag.PUMPCOMM, "Error decoding basal profile from bytes: " + ByteUtil.shortHexString(rawData)) + throw ex + } + i += 3 + } + return entries + } /** * This is used to prepare new profile @@ -233,7 +232,7 @@ class BasalProfile { fun getProfilesByHour(pumpType: PumpType): Array { var entriesCopy: List? = null try { - entriesCopy = entries + entriesCopy = getEntries() } catch (ex: Exception) { aapsLogger.error(LTag.PUMPCOMM, "=============================================================================") aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: $ex", ex) @@ -280,7 +279,7 @@ class BasalProfile { fun verify(pumpType: PumpType): Boolean { try { - entries + getEntries() } catch (ex: Exception) { return false } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt index e5a047ab97..c1e08c7f18 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.kt @@ -38,14 +38,14 @@ class MedtronicHistoryActivity : DaggerActivity() { var manualChange = false var typeListFull: List? = null - private var _binding: MedtronicHistoryActivityBinding? = null + //private var _binding: MedtronicHistoryActivityBinding? = null //@Inject //var fragmentInjector: DispatchingAndroidInjector? = null // This property is only valid between onCreateView and // onDestroyView. - private val binding get() = _binding!! + //private val binding get() = _binding!! private fun filterHistory(group: PumpHistoryEntryGroup) { filteredHistoryList.clear() @@ -93,20 +93,17 @@ class MedtronicHistoryActivity : DaggerActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - //setContentView(R.layout.medtronic_history_activity) - - _binding = MedtronicHistoryActivityBinding.inflate(getLayoutInflater()) //(inflater, container, false) - - historyTypeSpinner = binding.medtronicHistorytype //findViewById(R.id.medtronic_historytype) - statusView = binding.medtronicHistorystatus //findViewById(R.id.medtronic_historystatus) - recyclerView = binding.medtronicHistoryRecyclerview //findViewById(R.id.medtronic_history_recyclerview) + setContentView(R.layout.medtronic_history_activity) + historyTypeSpinner = findViewById(R.id.medtronic_historytype) + statusView = findViewById(R.id.medtronic_historystatus) + recyclerView = findViewById(R.id.medtronic_history_recyclerview) recyclerView.setHasFixedSize(true) llm = LinearLayoutManager(this) recyclerView.setLayoutManager(llm) recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList) recyclerView.setAdapter(recyclerViewAdapter) statusView.setVisibility(View.GONE) - typeListFull = getTypeList(getTranslatedList(resourceHelper!!)) + typeListFull = getTypeList(PumpHistoryEntryGroup.getTranslatedList(resourceHelper)) val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull) historyTypeSpinner.setAdapter(spinnerAdapter) historyTypeSpinner.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener { @@ -163,11 +160,11 @@ class MedtronicHistoryActivity : DaggerActivity() { override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) { val record = historyList[position] - if (record != null) { + //if (record != null) { holder.timeView.text = record.dateTimeString holder.typeView.text = record.entryType!!.description holder.valueView.text = record.displayableValue - } + //} } override fun getItemCount(): Int { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt index b753ac5795..3fe1eb4d8e 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/RileyLinkStatusDeviceMedtronic.kt @@ -108,8 +108,8 @@ class RileyLinkStatusDeviceMedtronic : DaggerFragment(), RefreshableInterface { return i.toLong() } - override fun getView(i: Int, view: View, viewGroup: ViewGroup): View { - var view = view + override fun getView(i: Int, viewIn: View, viewGroup: ViewGroup): View { + var view = viewIn val viewHolder: ViewHolder // General ListView optimization code. if (view == null) { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt index 205742a336..d8fb29c42a 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/service/RileyLinkMedtronicService.kt @@ -164,6 +164,7 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi } else { val pumpType = medtronicPumpStatus.medtronicPumpMap[pumpTypePart] medtronicPumpStatus.medtronicDeviceType = medtronicPumpStatus.medtronicDeviceTypeMap[pumpTypePart] + medtronicPumpStatus.pumpType = pumpType!! medtronicPumpPlugin.pumpType = pumpType if (pumpTypePart.startsWith("7")) medtronicPumpStatus.reservoirFullUnits = 300 else medtronicPumpStatus.reservoirFullUnits = 176 } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt index ac690be476..72574a99b0 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/util/MedtronicUtil.kt @@ -291,10 +291,10 @@ class MedtronicUtil @Inject constructor( } fun getStrokesInt(amount: Double, strokesPerUnit: Int): Int { - var length = 1 + //var length = 1 var scrollRate = 1 if (strokesPerUnit >= 40) { - length = 2 + // length = 2 // 40-stroke pumps scroll faster for higher unit values if (amount > 10) scrollRate = 4 else if (amount > 1) scrollRate = 2