- kotlin changes almost done, 1 file left
This commit is contained in:
parent
6b7efdcb95
commit
08a5c50037
18 changed files with 793 additions and 1061 deletions
|
@ -1,10 +1,13 @@
|
||||||
package info.nightscout.androidaps.plugins.treatments;
|
package info.nightscout.androidaps.plugins.treatments;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import com.google.firebase.analytics.FirebaseAnalytics;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -14,9 +17,11 @@ import javax.inject.Singleton;
|
||||||
import dagger.android.HasAndroidInjector;
|
import dagger.android.HasAndroidInjector;
|
||||||
import info.nightscout.androidaps.Constants;
|
import info.nightscout.androidaps.Constants;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
|
import info.nightscout.androidaps.activities.ErrorHelperActivity;
|
||||||
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
import info.nightscout.androidaps.data.DetailedBolusInfo;
|
||||||
import info.nightscout.androidaps.data.ProfileIntervals;
|
import info.nightscout.androidaps.data.ProfileIntervals;
|
||||||
import info.nightscout.androidaps.database.AppRepository;
|
import info.nightscout.androidaps.database.AppRepository;
|
||||||
|
import info.nightscout.androidaps.database.embedments.InterfaceIDs;
|
||||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||||
import info.nightscout.androidaps.db.ProfileSwitch;
|
import info.nightscout.androidaps.db.ProfileSwitch;
|
||||||
import info.nightscout.androidaps.db.Source;
|
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.ProfileStore;
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
|
import info.nightscout.androidaps.interfaces.TreatmentServiceInterface;
|
||||||
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
import info.nightscout.androidaps.interfaces.TreatmentsInterface;
|
||||||
|
import info.nightscout.androidaps.interfaces.UpdateReturn;
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger;
|
import info.nightscout.androidaps.logging.AAPSLogger;
|
||||||
import info.nightscout.androidaps.logging.LTag;
|
import info.nightscout.androidaps.logging.LTag;
|
||||||
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper;
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
import info.nightscout.androidaps.plugins.general.overview.events.EventDismissNotification;
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
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.DateUtil;
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy;
|
import info.nightscout.androidaps.utils.FabricPrivacy;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
|
@ -67,6 +76,10 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
|
|
||||||
private final ProfileIntervals<ProfileSwitch> profiles = new ProfileIntervals<>();
|
private final ProfileIntervals<ProfileSwitch> profiles = new ProfileIntervals<>();
|
||||||
|
|
||||||
|
private final boolean useNewPumpSync = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TreatmentsPlugin(
|
public TreatmentsPlugin(
|
||||||
HasAndroidInjector injector,
|
HasAndroidInjector injector,
|
||||||
|
@ -245,38 +258,48 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public boolean addToHistoryTempBasal(TemporaryBasal tempBasal) {
|
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());
|
//log.debug("Adding new TemporaryBasal record" + tempBasal.toString());
|
||||||
boolean newRecordCreated = databaseHelper.createOrUpdate(tempBasal);
|
boolean newRecordCreated = databaseHelper.createOrUpdate(tempBasal);
|
||||||
if (newRecordCreated) {
|
if (newRecordCreated) {
|
||||||
if (tempBasal.durationInMinutes == 0)
|
// if (tempBasal.durationInMinutes == 0)
|
||||||
nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId);
|
// nsUpload.uploadTempBasalEnd(tempBasal.date, false, tempBasal.pumpId);
|
||||||
else if (tempBasal.isAbsolute)
|
// else if (tempBasal.isAbsolute)
|
||||||
nsUpload.uploadTempBasalStartAbsolute(tempBasal, null);
|
// nsUpload.uploadTempBasalStartAbsolute(tempBasal, null);
|
||||||
else
|
// else
|
||||||
nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date));
|
// nsUpload.uploadTempBasalStartPercent(tempBasal, profileFunction.getProfile(tempBasal.date));
|
||||||
}
|
}
|
||||||
return newRecordCreated;
|
return newRecordCreated;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public TreatmentUpdateReturn createOrUpdateMedtronic(Treatment treatment, boolean fromNightScout) {
|
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);
|
UpdateReturn resultRecord = getService().createOrUpdateMedtronic(treatment, fromNightScout);
|
||||||
|
|
||||||
return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord());
|
return new TreatmentUpdateReturn(resultRecord.getSuccess(), resultRecord.getNewRecord());
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return true if new record is created
|
// return true if new record is created
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@Override
|
@Override
|
||||||
public boolean addToHistoryTreatment(DetailedBolusInfo detailedBolusInfo, boolean allowUpdate) {
|
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;
|
boolean medtronicPump = activePlugin.getActivePump() instanceof MedtronicPumpPlugin;
|
||||||
|
|
||||||
getAapsLogger().debug(MedtronicHistoryData.doubleBolusDebug, LTag.DATATREATMENTS, "DoubleBolusDebug: addToHistoryTreatment::isMedtronicPump={} " + medtronicPump);
|
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);
|
getService().createOrUpdateMedtronic(carbsTreatment, false);
|
||||||
//log.debug("Adding new Treatment record" + carbsTreatment);
|
//log.debug("Adding new Treatment record" + carbsTreatment);
|
||||||
}
|
}
|
||||||
if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING)
|
// if (newRecordCreated && detailedBolusInfo.getBolusType() != DetailedBolusInfo.BolusType.PRIMING)
|
||||||
nsUpload.uploadTreatmentRecord(detailedBolusInfo);
|
// nsUpload.uploadTreatmentRecord(detailedBolusInfo);
|
||||||
|
|
||||||
if (!allowUpdate && !creatOrUpdateResult.getSuccess()) {
|
if (!allowUpdate && !creatOrUpdateResult.getSuccess()) {
|
||||||
getAapsLogger().error("Treatment could not be added to DB", new Exception());
|
getAapsLogger().error("Treatment could not be added to DB", new Exception());
|
||||||
|
@ -337,7 +360,7 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
return newRecordCreated;
|
return newRecordCreated;
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -12,6 +12,9 @@ android {
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
}
|
}
|
||||||
|
dataBinding {
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -74,11 +74,11 @@ abstract class PumpPluginAbstract protected constructor(
|
||||||
@JvmField protected var pumpState = PumpDriverState.NotInitialized
|
@JvmField protected var pumpState = PumpDriverState.NotInitialized
|
||||||
@JvmField protected var displayConnectionMessages = false
|
@JvmField protected var displayConnectionMessages = false
|
||||||
|
|
||||||
var pumpType: PumpType? = null
|
var pumpType: PumpType = PumpType.GENERIC_AAPS
|
||||||
get() = field
|
get() = field
|
||||||
set(value) {
|
set(value) {
|
||||||
field = value
|
field = value
|
||||||
pumpDescription.setPumpDescription(value!!)
|
pumpDescription.setPumpDescription(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -366,11 +366,11 @@ abstract class PumpPluginAbstract protected constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun manufacturer(): ManufacturerType {
|
override fun manufacturer(): ManufacturerType {
|
||||||
return pumpType!!.manufacturer!!
|
return pumpType.manufacturer!!
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun model(): PumpType {
|
override fun model(): PumpType {
|
||||||
return pumpType!!
|
return pumpType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ abstract class PumpPluginAbstract protected constructor(
|
||||||
val temporaryId = generateTempId(detailedBolusInfo.timestamp)
|
val temporaryId = generateTempId(detailedBolusInfo.timestamp)
|
||||||
val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin,
|
val response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin,
|
||||||
temporaryId, detailedBolusInfo.bolusType,
|
temporaryId, detailedBolusInfo.bolusType,
|
||||||
pumpType!!, serialNumber())
|
pumpType, serialNumber())
|
||||||
if (response && writeToInternalHistory) {
|
if (response && writeToInternalHistory) {
|
||||||
driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)
|
driverHistory[temporaryId] = PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)
|
||||||
sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory))
|
sp.putString(MedtronicConst.Statistics.InternalTemporaryDatabase, gson.toJson(driverHistory))
|
||||||
|
@ -403,6 +403,7 @@ abstract class PumpPluginAbstract protected constructor(
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) {
|
protected fun addTemporaryBasalRateWithTempId(temporaryBasal: TemporaryBasal?, b: Boolean) {
|
||||||
// long temporaryId = generateTempId(temporaryBasal.timestamp);
|
// long temporaryId = generateTempId(temporaryBasal.timestamp);
|
||||||
// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin,
|
// boolean response = pumpSync.addBolusWithTempId(temporaryBasal.timestamp, detailedBolusInfo.insulin,
|
||||||
|
|
|
@ -210,7 +210,6 @@ class MedtronicFragment : DaggerFragment() {
|
||||||
} ?: "-"
|
} ?: "-"
|
||||||
|
|
||||||
when (medtronicPumpStatus.pumpDeviceState) {
|
when (medtronicPumpStatus.pumpDeviceState) {
|
||||||
null,
|
|
||||||
PumpDeviceState.Sleeping -> binding.pumpStatusIcon.text = "{fa-bed} " // + pumpStatus.pumpDeviceState.name());
|
PumpDeviceState.Sleeping -> binding.pumpStatusIcon.text = "{fa-bed} " // + pumpStatus.pumpDeviceState.name());
|
||||||
PumpDeviceState.NeverContacted,
|
PumpDeviceState.NeverContacted,
|
||||||
PumpDeviceState.WakingUp,
|
PumpDeviceState.WakingUp,
|
||||||
|
|
|
@ -98,7 +98,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
.preferencesId(R.xml.pref_medtronic)
|
.preferencesId(R.xml.pref_medtronic)
|
||||||
.description(R.string.description_pump_medtronic), //
|
.description(R.string.description_pump_medtronic), //
|
||||||
PumpType.MEDTRONIC_522_722, // we default to most basic model, correct model from config is loaded later
|
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 {
|
), Pump, RileyLinkPumpDevice {
|
||||||
|
|
||||||
private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null
|
private var rileyLinkMedtronicService: RileyLinkMedtronicService? = null
|
||||||
|
@ -149,7 +149,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val logPrefix: String
|
private val logPrefix: String
|
||||||
private get() = "MedtronicPumpPlugin::"
|
get() = "MedtronicPumpPlugin::"
|
||||||
|
|
||||||
override fun initPumpStatusData() {
|
override fun initPumpStatusData() {
|
||||||
medtronicPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)
|
medtronicPumpStatus.lastConnection = sp.getLong(RileyLinkConst.Prefs.LastGoodDeviceCommunicationTime, 0L)
|
||||||
|
@ -225,7 +225,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
|
|
||||||
// Pump Plugin
|
// Pump Plugin
|
||||||
private val isServiceSet: Boolean
|
private val isServiceSet: Boolean
|
||||||
private get() = rileyLinkMedtronicService != null
|
get() = rileyLinkMedtronicService != null
|
||||||
|
|
||||||
override fun getRileyLinkService(): RileyLinkMedtronicService? {
|
override fun getRileyLinkService(): RileyLinkMedtronicService? {
|
||||||
return rileyLinkMedtronicService
|
return rileyLinkMedtronicService
|
||||||
|
@ -313,7 +313,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}//
|
}//
|
||||||
|
|
||||||
private val isPumpNotReachable: Boolean
|
private val isPumpNotReachable: Boolean
|
||||||
private get() {
|
get() {
|
||||||
val rileyLinkServiceState = rileyLinkServiceData.rileyLinkServiceState
|
val rileyLinkServiceState = rileyLinkServiceData.rileyLinkServiceState
|
||||||
if (rileyLinkServiceState == null) {
|
if (rileyLinkServiceState == null) {
|
||||||
aapsLogger.debug(LTag.PUMP, "RileyLink unreachable. RileyLinkServiceState is null.")
|
aapsLogger.debug(LTag.PUMP, "RileyLink unreachable. RileyLinkServiceState is null.")
|
||||||
|
@ -908,7 +908,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private val lastPumpEntryTime: Long
|
private val lastPumpEntryTime: Long
|
||||||
private get() {
|
get() {
|
||||||
val lastPumpEntryTime = sp.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L)
|
val lastPumpEntryTime = sp.getLong(MedtronicConst.Statistics.LastPumpHistoryEntry, 0L)
|
||||||
return try {
|
return try {
|
||||||
val localDateTime = DateTimeUtil.toLocalDateTime(lastPumpEntryTime)
|
val localDateTime = DateTimeUtil.toLocalDateTime(lastPumpEntryTime)
|
||||||
|
@ -1085,7 +1085,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
private fun isProfileValid(basalProfile: BasalProfile): String? {
|
private fun isProfileValid(basalProfile: BasalProfile): String? {
|
||||||
val stringBuilder = StringBuilder()
|
val stringBuilder = StringBuilder()
|
||||||
if (medtronicPumpStatus.maxBasal == null) return null
|
if (medtronicPumpStatus.maxBasal == null) return null
|
||||||
for (profileEntry in basalProfile.entries) {
|
for (profileEntry in basalProfile.getEntries()) {
|
||||||
if (profileEntry.rate > medtronicPumpStatus.maxBasal!!) {
|
if (profileEntry.rate > medtronicPumpStatus.maxBasal!!) {
|
||||||
stringBuilder.append(profileEntry.startTime!!.toString("HH:mm"))
|
stringBuilder.append(profileEntry.startTime!!.toString("HH:mm"))
|
||||||
stringBuilder.append("=")
|
stringBuilder.append("=")
|
||||||
|
@ -1099,7 +1099,7 @@ class MedtronicPumpPlugin @Inject constructor(
|
||||||
val basalProfile = BasalProfile(aapsLogger)
|
val basalProfile = BasalProfile(aapsLogger)
|
||||||
for (i in 0..23) {
|
for (i in 0..23) {
|
||||||
val rate = profile.getBasalTimeFromMidnight(i * 60 * 60)
|
val rate = profile.getBasalTimeFromMidnight(i * 60 * 60)
|
||||||
val v = pumpDescription.pumpType.determineCorrectBasalSize(rate)
|
val v = pumpType.determineCorrectBasalSize(rate)
|
||||||
val basalEntry = BasalProfileEntry(v, i, 0)
|
val basalEntry = BasalProfileEntry(v, i, 0)
|
||||||
basalProfile.addEntry(basalEntry)
|
basalProfile.addEntry(basalEntry)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
|
||||||
* <p>
|
|
||||||
* 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<PumpMessage> {
|
|
||||||
|
|
||||||
@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<List<Byte>> 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<Byte> 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<PumpHistoryEntry> 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> T sendAndGetResponseWithCheck(MedtronicCommandType commandType, byte[] bodyData, Class<T> 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<String, PumpSettingDTO> getPumpSettings() {
|
|
||||||
|
|
||||||
Object responseObject = sendAndGetResponseWithCheck(MedtronicCommandType.getSettings(medtronicUtil
|
|
||||||
.getMedtronicPumpModel()));
|
|
||||||
|
|
||||||
return responseObject == null ? null : (Map<String, PumpSettingDTO>) 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<List<Byte>> 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;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<PumpMessage?>() {
|
||||||
|
|
||||||
|
@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<List<Byte>>): 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 <T> sendAndGetResponseWithCheck(commandType: MedtronicCommandType, bodyData: ByteArray, clazz: Class<T>): 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<String, PumpSettingDTO>? {
|
||||||
|
val responseObject = sendAndGetResponseWithCheck(getSettings(medtronicUtil.medtronicPumpModel))
|
||||||
|
return if (responseObject == null) null else responseObject as Map<String, PumpSettingDTO>?
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -51,7 +51,7 @@ abstract class MedtronicHistoryDecoder<T : MedtronicHistoryEntry?> : MedtronicHi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List<T?>? {
|
fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List<T> {
|
||||||
return processPageAndCreateRecords(rawHistoryPage, false)
|
return processPageAndCreateRecords(rawHistoryPage, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ abstract class MedtronicHistoryDecoder<T : MedtronicHistoryEntry?> : MedtronicHi
|
||||||
private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List<T> {
|
private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List<T> {
|
||||||
val dataClear = checkPage(rawHistoryPage, partial)
|
val dataClear = checkPage(rawHistoryPage, partial)
|
||||||
val records: List<T> = createRecords(dataClear)
|
val records: List<T> = createRecords(dataClear)
|
||||||
for (record in records!!) {
|
for (record in records) {
|
||||||
decodeRecord(record)
|
decodeRecord(record)
|
||||||
}
|
}
|
||||||
runPostDecodeTasks()
|
runPostDecodeTasks()
|
||||||
|
|
|
@ -25,14 +25,14 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder<CGMSHistoryEntry>()
|
||||||
|
|
||||||
override fun decodeRecord(record: CGMSHistoryEntry): RecordDecodeStatus? {
|
override fun decodeRecord(record: CGMSHistoryEntry): RecordDecodeStatus? {
|
||||||
return try {
|
return try {
|
||||||
decodeRecord(record, false)
|
decodeRecordInternal(record)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
LOG.error(" Error decoding: type={}, ex={}", record.entryType!!.name, ex.message, ex)
|
LOG.error(" Error decoding: type={}, ex={}", record.entryType!!.name, ex.message, ex)
|
||||||
RecordDecodeStatus.Error
|
RecordDecodeStatus.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun decodeRecord(entry: CGMSHistoryEntry, ignore: Boolean): RecordDecodeStatus {
|
fun decodeRecordInternal(entry: CGMSHistoryEntry): RecordDecodeStatus {
|
||||||
if (entry.dateTimeLength > 0) {
|
if (entry.dateTimeLength > 0) {
|
||||||
parseDate(entry)
|
parseDate(entry)
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder<CGMSHistoryEntry>()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun postProcess() {}
|
override fun postProcess() {}
|
||||||
|
|
||||||
override fun createRecords(dataClearInput: List<Byte>): List<CGMSHistoryEntry> {
|
override fun createRecords(dataClearInput: List<Byte>): List<CGMSHistoryEntry> {
|
||||||
val dataClear = reverseList(dataClearInput, Byte::class.java)
|
val dataClear = reverseList(dataClearInput, Byte::class.java)
|
||||||
prepareStatistics()
|
prepareStatistics()
|
||||||
|
|
|
@ -79,7 +79,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor(
|
||||||
listRawData.add(opCode.toByte())
|
listRawData.add(opCode.toByte())
|
||||||
if (entryType === PumpHistoryEntryType.UnabsorbedInsulin
|
if (entryType === PumpHistoryEntryType.UnabsorbedInsulin
|
||||||
|| entryType === PumpHistoryEntryType.UnabsorbedInsulin512) {
|
|| entryType === PumpHistoryEntryType.UnabsorbedInsulin512) {
|
||||||
val elements: Int = dataClear[counter]!!.toInt()
|
val elements: Int = dataClear[counter].toInt()
|
||||||
listRawData.add(elements.toByte())
|
listRawData.add(elements.toByte())
|
||||||
counter++
|
counter++
|
||||||
val els = getUnsignedInt(elements)
|
val els = getUnsignedInt(elements)
|
||||||
|
@ -106,12 +106,12 @@ class MedtronicPumpHistoryDecoder @Inject constructor(
|
||||||
if (incompletePacket) break
|
if (incompletePacket) break
|
||||||
}
|
}
|
||||||
if (entryType === PumpHistoryEntryType.None) {
|
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 {
|
} else {
|
||||||
if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) {
|
if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) {
|
||||||
pe.opCode = opCode.toByte()
|
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<Byte>, special)
|
pe.setData(listRawData as List<Byte>, special)
|
||||||
val decoded = decodeRecord(pe)
|
val decoded = decodeRecord(pe)
|
||||||
if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) {
|
if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) {
|
||||||
|
@ -132,7 +132,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor(
|
||||||
|
|
||||||
override fun decodeRecord(record: PumpHistoryEntry): RecordDecodeStatus? {
|
override fun decodeRecord(record: PumpHistoryEntry): RecordDecodeStatus? {
|
||||||
return try {
|
return try {
|
||||||
decodeRecord(record, false)
|
decodeRecordInternal(record)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex))
|
aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex))
|
||||||
//ex.printStackTrace()
|
//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) {
|
if (entry.dateTimeLength > 0) {
|
||||||
decodeDateTime(entry)
|
decodeDateTime(entry)
|
||||||
}
|
}
|
||||||
|
@ -169,6 +169,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor(
|
||||||
|
|
||||||
PumpHistoryEntryType.TempBasalDuration -> // decodeTempBasal(entry);
|
PumpHistoryEntryType.TempBasalDuration -> // decodeTempBasal(entry);
|
||||||
RecordDecodeStatus.OK
|
RecordDecodeStatus.OK
|
||||||
|
|
||||||
PumpHistoryEntryType.TempBasalRate -> // decodeTempBasal(entry);
|
PumpHistoryEntryType.TempBasalRate -> // decodeTempBasal(entry);
|
||||||
RecordDecodeStatus.OK
|
RecordDecodeStatus.OK
|
||||||
|
|
||||||
|
@ -254,7 +255,7 @@ class MedtronicPumpHistoryDecoder @Inject constructor(
|
||||||
val body = entry.body!!
|
val body = entry.body!!
|
||||||
val dto = BolusWizardDTO()
|
val dto = BolusWizardDTO()
|
||||||
var bolusStrokes = 10.0f
|
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
|
// https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102
|
||||||
bolusStrokes = 40.0f
|
bolusStrokes = 40.0f
|
||||||
dto.carbs = ((body[1] and 0x0c.toByte()).toInt() shl 6) + body[0]
|
dto.carbs = ((body[1] and 0x0c.toByte()).toInt() shl 6) + body[0]
|
||||||
|
|
|
@ -69,10 +69,10 @@ class PumpHistoryEntry : MedtronicHistoryEntry() {
|
||||||
override val dateLength: Int
|
override val dateLength: Int
|
||||||
get() = entryType!!.dateLength
|
get() = entryType!!.dateLength
|
||||||
|
|
||||||
override fun equals(o: Any?): Boolean {
|
override fun equals(other: Any?): Boolean {
|
||||||
if (this === o) return true
|
if (this === other) return true
|
||||||
if (o !is PumpHistoryEntry) return false
|
if (other !is PumpHistoryEntry) return false
|
||||||
val that = o
|
val that = other
|
||||||
return entryType == that.entryType && //
|
return entryType == that.entryType && //
|
||||||
atechDateTime === that.atechDateTime // && //
|
atechDateTime === that.atechDateTime // && //
|
||||||
// Objects.equals(this.decodedData, that.decodedData);
|
// Objects.equals(this.decodedData, that.decodedData);
|
||||||
|
|
|
@ -81,8 +81,8 @@ class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHis
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "PumpHistoryResult [unprocessed=" + (if (unprocessedEntries != null) "" + unprocessedEntries!!.size else "0") + //
|
return "PumpHistoryResult [unprocessed=" + unprocessedEntries.size + //
|
||||||
", valid=" + (if (validEntries != null) "" + validEntries!!.size else "0") + //
|
", valid=" + validEntries.size + //
|
||||||
", searchEntry=" + searchEntry + //
|
", searchEntry=" + searchEntry + //
|
||||||
", searchDate=" + searchDate + //
|
", searchDate=" + searchDate + //
|
||||||
", searchType=" + searchType + //
|
", searchType=" + searchType + //
|
||||||
|
|
|
@ -53,19 +53,19 @@ class MedtronicUITask {
|
||||||
aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. $commandType")
|
aapsLogger.debug(LTag.PUMP, "MedtronicUITask: @@@ In execute. $commandType")
|
||||||
when (commandType) {
|
when (commandType) {
|
||||||
MedtronicCommandType.PumpModel -> {
|
MedtronicCommandType.PumpModel -> {
|
||||||
result = communicationManager.pumpModel
|
result = communicationManager.getPumpModel()
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.GetBasalProfileSTD -> {
|
MedtronicCommandType.GetBasalProfileSTD -> {
|
||||||
result = communicationManager.basalProfile
|
result = communicationManager.getBasalProfile()
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.GetRemainingInsulin -> {
|
MedtronicCommandType.GetRemainingInsulin -> {
|
||||||
result = communicationManager.remainingInsulin
|
result = communicationManager.getRemainingInsulin()
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.GetRealTimeClock -> {
|
MedtronicCommandType.GetRealTimeClock -> {
|
||||||
result = communicationManager.pumpTime
|
result = communicationManager.getPumpTime()
|
||||||
medtronicUtil.pumpTime = null
|
medtronicUtil.pumpTime = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,22 +74,22 @@ class MedtronicUITask {
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.GetBatteryStatus -> {
|
MedtronicCommandType.GetBatteryStatus -> {
|
||||||
result = communicationManager.remainingBattery
|
result = communicationManager.getRemainingBattery()
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.SetTemporaryBasal -> {
|
MedtronicCommandType.SetTemporaryBasal -> {
|
||||||
val tbr = tBRSettings
|
val tbr = getTbrSettings()
|
||||||
if (tbr != null) {
|
if (tbr != null) {
|
||||||
result = communicationManager.setTBR(tbr)
|
result = communicationManager.setTemporaryBasal(tbr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.ReadTemporaryBasal -> {
|
MedtronicCommandType.ReadTemporaryBasal -> {
|
||||||
result = communicationManager.temporaryBasal
|
result = communicationManager.getTemporaryBasal()
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.Settings, MedtronicCommandType.Settings_512 -> {
|
MedtronicCommandType.Settings, MedtronicCommandType.Settings_512 -> {
|
||||||
result = communicationManager.pumpSettings
|
result = communicationManager.getPumpSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
MedtronicCommandType.SetBolus -> {
|
MedtronicCommandType.SetBolus -> {
|
||||||
|
@ -127,12 +127,11 @@ class MedtronicUITask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
private fun getTbrSettings(): TempBasalPair? {
|
||||||
//
|
return TempBasalPair(getDoubleFromParameters(0), //
|
||||||
private val tBRSettings: TempBasalPair
|
|
||||||
private get() = TempBasalPair(getDoubleFromParameters(0), //
|
|
||||||
false, //
|
false, //
|
||||||
getIntegerFromParameters(1))
|
getIntegerFromParameters(1))
|
||||||
|
}
|
||||||
|
|
||||||
private fun getFloatFromParameters(index: Int): Float {
|
private fun getFloatFromParameters(index: Int): Float {
|
||||||
return parameters!![index] as Float
|
return parameters!![index] as Float
|
||||||
|
|
|
@ -96,7 +96,7 @@ class BasalProfile {
|
||||||
|
|
||||||
fun dumpBasalProfile() {
|
fun dumpBasalProfile() {
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Basal Profile entries:")
|
aapsLogger.debug(LTag.PUMPCOMM, "Basal Profile entries:")
|
||||||
val entries = entries
|
val entries = getEntries()
|
||||||
for (i in entries.indices) {
|
for (i in entries.indices) {
|
||||||
val entry = entries[i]
|
val entry = entries[i]
|
||||||
val startString = entry.startTime!!.toString("HH:mm")
|
val startString = entry.startTime!!.toString("HH:mm")
|
||||||
|
@ -109,7 +109,7 @@ class BasalProfile {
|
||||||
val basalProfileAsString: String
|
val basalProfileAsString: String
|
||||||
get() {
|
get() {
|
||||||
val sb = StringBuffer("Basal Profile entries:\n")
|
val sb = StringBuffer("Basal Profile entries:\n")
|
||||||
val entries = entries
|
val entries = getEntries()
|
||||||
for (i in entries.indices) {
|
for (i in entries.indices) {
|
||||||
val entry = entries[i]
|
val entry = entries[i]
|
||||||
val startString = entry.startTime!!.toString("HH:mm")
|
val startString = entry.startTime!!.toString("HH:mm")
|
||||||
|
@ -124,7 +124,7 @@ class BasalProfile {
|
||||||
|
|
||||||
fun basalProfileToString(): String {
|
fun basalProfileToString(): String {
|
||||||
val sb = StringBuffer("Basal Profile [")
|
val sb = StringBuffer("Basal Profile [")
|
||||||
val entries = entries
|
val entries = getEntries()
|
||||||
for (i in entries.indices) {
|
for (i in entries.indices) {
|
||||||
val entry = entries[i]
|
val entry = entries[i]
|
||||||
val startString = entry.startTime!!.toString("HH:mm")
|
val startString = entry.startTime!!.toString("HH:mm")
|
||||||
|
@ -138,7 +138,7 @@ class BasalProfile {
|
||||||
// and changes to the profiles themselves.
|
// and changes to the profiles themselves.
|
||||||
fun getEntryForTime(`when`: Instant): BasalProfileEntry {
|
fun getEntryForTime(`when`: Instant): BasalProfileEntry {
|
||||||
var rval = BasalProfileEntry()
|
var rval = BasalProfileEntry()
|
||||||
val entries = entries
|
val entries = getEntries()
|
||||||
if (entries.size == 0) {
|
if (entries.size == 0) {
|
||||||
aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): table is empty",
|
aapsLogger.warn(LTag.PUMPCOMM, String.format(Locale.ENGLISH, "getEntryForTime(%s): table is empty",
|
||||||
`when`.toDateTime().toLocalTime().toString("HH:mm")))
|
`when`.toDateTime().toLocalTime().toString("HH:mm")))
|
||||||
|
@ -181,31 +181,30 @@ class BasalProfile {
|
||||||
}// readUnsignedByte(mRawData[i]);
|
}// readUnsignedByte(mRawData[i]);
|
||||||
|
|
||||||
// an empty list
|
// an empty list
|
||||||
val entries: List<BasalProfileEntry>
|
fun getEntries(): List<BasalProfileEntry> {
|
||||||
get() {
|
val entries: MutableList<BasalProfileEntry> = ArrayList()
|
||||||
val entries: MutableList<BasalProfileEntry> = ArrayList()
|
if (rawData[2] == 0x3f.toByte()) {
|
||||||
if (rawData == null || rawData!![2] == 0x3f.toByte()) {
|
aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.")
|
||||||
aapsLogger.warn(LTag.PUMPCOMM, "Raw Data is empty.")
|
return entries // an empty list
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
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
|
* This is used to prepare new profile
|
||||||
|
@ -233,7 +232,7 @@ class BasalProfile {
|
||||||
fun getProfilesByHour(pumpType: PumpType): Array<Double> {
|
fun getProfilesByHour(pumpType: PumpType): Array<Double> {
|
||||||
var entriesCopy: List<BasalProfileEntry>? = null
|
var entriesCopy: List<BasalProfileEntry>? = null
|
||||||
try {
|
try {
|
||||||
entriesCopy = entries
|
entriesCopy = getEntries()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
aapsLogger.error(LTag.PUMPCOMM, "=============================================================================")
|
aapsLogger.error(LTag.PUMPCOMM, "=============================================================================")
|
||||||
aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: $ex", ex)
|
aapsLogger.error(LTag.PUMPCOMM, " Error generating entries. Ex.: $ex", ex)
|
||||||
|
@ -280,7 +279,7 @@ class BasalProfile {
|
||||||
|
|
||||||
fun verify(pumpType: PumpType): Boolean {
|
fun verify(pumpType: PumpType): Boolean {
|
||||||
try {
|
try {
|
||||||
entries
|
getEntries()
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,14 +38,14 @@ class MedtronicHistoryActivity : DaggerActivity() {
|
||||||
var manualChange = false
|
var manualChange = false
|
||||||
var typeListFull: List<TypeList>? = null
|
var typeListFull: List<TypeList>? = null
|
||||||
|
|
||||||
private var _binding: MedtronicHistoryActivityBinding? = null
|
//private var _binding: MedtronicHistoryActivityBinding? = null
|
||||||
|
|
||||||
//@Inject
|
//@Inject
|
||||||
//var fragmentInjector: DispatchingAndroidInjector<Fragment>? = null
|
//var fragmentInjector: DispatchingAndroidInjector<Fragment>? = null
|
||||||
|
|
||||||
// This property is only valid between onCreateView and
|
// This property is only valid between onCreateView and
|
||||||
// onDestroyView.
|
// onDestroyView.
|
||||||
private val binding get() = _binding!!
|
//private val binding get() = _binding!!
|
||||||
|
|
||||||
private fun filterHistory(group: PumpHistoryEntryGroup) {
|
private fun filterHistory(group: PumpHistoryEntryGroup) {
|
||||||
filteredHistoryList.clear()
|
filteredHistoryList.clear()
|
||||||
|
@ -93,20 +93,17 @@ class MedtronicHistoryActivity : DaggerActivity() {
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
//setContentView(R.layout.medtronic_history_activity)
|
setContentView(R.layout.medtronic_history_activity)
|
||||||
|
historyTypeSpinner = findViewById(R.id.medtronic_historytype)
|
||||||
_binding = MedtronicHistoryActivityBinding.inflate(getLayoutInflater()) //(inflater, container, false)
|
statusView = findViewById(R.id.medtronic_historystatus)
|
||||||
|
recyclerView = findViewById(R.id.medtronic_history_recyclerview)
|
||||||
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)
|
|
||||||
recyclerView.setHasFixedSize(true)
|
recyclerView.setHasFixedSize(true)
|
||||||
llm = LinearLayoutManager(this)
|
llm = LinearLayoutManager(this)
|
||||||
recyclerView.setLayoutManager(llm)
|
recyclerView.setLayoutManager(llm)
|
||||||
recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList)
|
recyclerViewAdapter = RecyclerViewAdapter(filteredHistoryList)
|
||||||
recyclerView.setAdapter(recyclerViewAdapter)
|
recyclerView.setAdapter(recyclerViewAdapter)
|
||||||
statusView.setVisibility(View.GONE)
|
statusView.setVisibility(View.GONE)
|
||||||
typeListFull = getTypeList(getTranslatedList(resourceHelper!!))
|
typeListFull = getTypeList(PumpHistoryEntryGroup.getTranslatedList(resourceHelper))
|
||||||
val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull)
|
val spinnerAdapter = ArrayAdapter(this, R.layout.spinner_centered, typeListFull)
|
||||||
historyTypeSpinner.setAdapter(spinnerAdapter)
|
historyTypeSpinner.setAdapter(spinnerAdapter)
|
||||||
historyTypeSpinner.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener {
|
historyTypeSpinner.setOnItemSelectedListener(object : AdapterView.OnItemSelectedListener {
|
||||||
|
@ -163,11 +160,11 @@ class MedtronicHistoryActivity : DaggerActivity() {
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: HistoryViewHolder, position: Int) {
|
||||||
val record = historyList[position]
|
val record = historyList[position]
|
||||||
if (record != null) {
|
//if (record != null) {
|
||||||
holder.timeView.text = record.dateTimeString
|
holder.timeView.text = record.dateTimeString
|
||||||
holder.typeView.text = record.entryType!!.description
|
holder.typeView.text = record.entryType!!.description
|
||||||
holder.valueView.text = record.displayableValue
|
holder.valueView.text = record.displayableValue
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
|
|
|
@ -108,8 +108,8 @@ class RileyLinkStatusDeviceMedtronic : DaggerFragment(), RefreshableInterface {
|
||||||
return i.toLong()
|
return i.toLong()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getView(i: Int, view: View, viewGroup: ViewGroup): View {
|
override fun getView(i: Int, viewIn: View, viewGroup: ViewGroup): View {
|
||||||
var view = view
|
var view = viewIn
|
||||||
val viewHolder: ViewHolder
|
val viewHolder: ViewHolder
|
||||||
// General ListView optimization code.
|
// General ListView optimization code.
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
|
|
|
@ -164,6 +164,7 @@ class RileyLinkMedtronicService // This empty constructor must be kept, otherwi
|
||||||
} else {
|
} else {
|
||||||
val pumpType = medtronicPumpStatus.medtronicPumpMap[pumpTypePart]
|
val pumpType = medtronicPumpStatus.medtronicPumpMap[pumpTypePart]
|
||||||
medtronicPumpStatus.medtronicDeviceType = medtronicPumpStatus.medtronicDeviceTypeMap[pumpTypePart]
|
medtronicPumpStatus.medtronicDeviceType = medtronicPumpStatus.medtronicDeviceTypeMap[pumpTypePart]
|
||||||
|
medtronicPumpStatus.pumpType = pumpType!!
|
||||||
medtronicPumpPlugin.pumpType = pumpType
|
medtronicPumpPlugin.pumpType = pumpType
|
||||||
if (pumpTypePart.startsWith("7")) medtronicPumpStatus.reservoirFullUnits = 300 else medtronicPumpStatus.reservoirFullUnits = 176
|
if (pumpTypePart.startsWith("7")) medtronicPumpStatus.reservoirFullUnits = 300 else medtronicPumpStatus.reservoirFullUnits = 176
|
||||||
}
|
}
|
||||||
|
|
|
@ -291,10 +291,10 @@ class MedtronicUtil @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getStrokesInt(amount: Double, strokesPerUnit: Int): Int {
|
fun getStrokesInt(amount: Double, strokesPerUnit: Int): Int {
|
||||||
var length = 1
|
//var length = 1
|
||||||
var scrollRate = 1
|
var scrollRate = 1
|
||||||
if (strokesPerUnit >= 40) {
|
if (strokesPerUnit >= 40) {
|
||||||
length = 2
|
// length = 2
|
||||||
|
|
||||||
// 40-stroke pumps scroll faster for higher unit values
|
// 40-stroke pumps scroll faster for higher unit values
|
||||||
if (amount > 10) scrollRate = 4 else if (amount > 1) scrollRate = 2
|
if (amount > 10) scrollRate = 4 else if (amount > 1) scrollRate = 2
|
||||||
|
|
Loading…
Reference in a new issue