diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig new file mode 100644 index 0000000000..a0bffe268a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/common/PumpPluginAbstract.java.orig @@ -0,0 +1,535 @@ +package info.nightscout.androidaps.plugins.pump.common; + +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.convertedToAbsolute; +import static info.nightscout.androidaps.extensions.PumpStateExtensionKt.getPlannedRemainingMinutes; + +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; + +import androidx.annotation.NonNull; + +import org.json.JSONException; +import org.json.JSONObject; + +<<<<<<< HEAD +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +======= +>>>>>>> meallink +import dagger.android.HasAndroidInjector; +import info.nightscout.androidaps.core.R; +import info.nightscout.androidaps.data.DetailedBolusInfo; +import info.nightscout.androidaps.data.Profile; +import info.nightscout.androidaps.data.PumpEnactResult; +import info.nightscout.androidaps.events.EventAppExit; +import info.nightscout.androidaps.events.EventCustomActionsChanged; +import info.nightscout.androidaps.extensions.PumpStateExtensionKt; +import info.nightscout.androidaps.interfaces.ActivePluginProvider; +import info.nightscout.androidaps.interfaces.CommandQueueProvider; +import info.nightscout.androidaps.interfaces.ConstraintsInterface; +import info.nightscout.androidaps.interfaces.PluginDescription; +import info.nightscout.androidaps.interfaces.PumpDescription; +import info.nightscout.androidaps.interfaces.PumpInterface; +import info.nightscout.androidaps.interfaces.PumpPluginBase; +import info.nightscout.androidaps.interfaces.PumpSync; +import info.nightscout.androidaps.logging.AAPSLogger; +import info.nightscout.androidaps.logging.LTag; +import info.nightscout.androidaps.plugins.bus.RxBusWrapper; +import info.nightscout.androidaps.plugins.common.ManufacturerType; +import info.nightscout.androidaps.plugins.general.overview.events.EventOverviewBolusProgress; +import info.nightscout.androidaps.plugins.pump.common.data.PumpDbEntry; +import info.nightscout.androidaps.plugins.pump.common.data.PumpStatus; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpDriverState; +import info.nightscout.androidaps.plugins.pump.common.defs.PumpType; +import info.nightscout.androidaps.utils.DateUtil; +import info.nightscout.androidaps.utils.DecimalFormatter; +import info.nightscout.androidaps.utils.FabricPrivacy; +import info.nightscout.androidaps.utils.resources.ResourceHelper; +import info.nightscout.androidaps.utils.rx.AapsSchedulers; +import info.nightscout.androidaps.utils.sharedPreferences.SP; +import io.reactivex.disposables.CompositeDisposable; + +/** + * Created by andy on 23.04.18. + */ + +// When using this class, make sure that your first step is to create mConnection (see MedtronicPumpPlugin) + +public abstract class PumpPluginAbstract extends PumpPluginBase implements PumpInterface, ConstraintsInterface { + private final CompositeDisposable disposable = new CompositeDisposable(); + + protected HasAndroidInjector injector; + protected AAPSLogger aapsLogger; + protected RxBusWrapper rxBus; + protected ActivePluginProvider activePlugin; + protected Context context; + protected FabricPrivacy fabricPrivacy; + protected ResourceHelper resourceHelper; + protected CommandQueueProvider commandQueue; + protected SP sp; + protected DateUtil dateUtil; + protected PumpDescription pumpDescription = new PumpDescription(); + protected ServiceConnection serviceConnection; + protected boolean serviceRunning = false; + protected PumpDriverState pumpState = PumpDriverState.NotInitialized; + protected boolean displayConnectionMessages = false; + protected PumpType pumpType; + protected AapsSchedulers aapsSchedulers; + protected PumpSync pumpSync; +<<<<<<< HEAD + +======= +>>>>>>> meallink + + protected PumpPluginAbstract( + PluginDescription pluginDescription, + PumpType pumpType, + HasAndroidInjector injector, + ResourceHelper resourceHelper, + AAPSLogger aapsLogger, + CommandQueueProvider commandQueue, + RxBusWrapper rxBus, + ActivePluginProvider activePlugin, + SP sp, + Context context, + FabricPrivacy fabricPrivacy, + DateUtil dateUtil, + AapsSchedulers aapsSchedulers, + PumpSync pumpSync + ) { + + super(pluginDescription, injector, aapsLogger, resourceHelper, commandQueue); + this.aapsLogger = aapsLogger; + this.rxBus = rxBus; + this.activePlugin = activePlugin; + this.context = context; + this.fabricPrivacy = fabricPrivacy; + this.resourceHelper = resourceHelper; + this.sp = sp; + this.commandQueue = commandQueue; + + pumpDescription.setPumpDescription(pumpType); + this.pumpType = pumpType; + this.dateUtil = dateUtil; + this.aapsSchedulers = aapsSchedulers; + this.pumpSync = pumpSync; + } + + + public abstract void initPumpStatusData(); + + + @Override + protected void onStart() { + super.onStart(); + + initPumpStatusData(); + + Intent intent = new Intent(context, getServiceClass()); + context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); + + serviceRunning = true; + + disposable.add(rxBus + .toObservable(EventAppExit.class) + .observeOn(aapsSchedulers.getIo()) + .subscribe(event -> context.unbindService(serviceConnection), fabricPrivacy::logException) + ); + onStartCustomActions(); + } + + + @Override + protected void onStop() { + aapsLogger.debug(LTag.PUMP, this.deviceID() + " onStop()"); + + context.unbindService(serviceConnection); + + serviceRunning = false; + + disposable.clear(); + super.onStop(); + } + + + /** + * If we need to run any custom actions in onStart (triggering events, etc) + */ + public abstract void onStartCustomActions(); + + /** + * Service class (same one you did serviceConnection for) + * + * @return Class + */ + public abstract Class getServiceClass(); + + public abstract PumpStatus getPumpStatusData(); + + + public boolean isInitialized() { + return pumpState.isInitialized(); + } + + + public boolean isSuspended() { + return pumpState == PumpDriverState.Suspended; + } + + + public boolean isBusy() { + return pumpState == PumpDriverState.Busy; + } + + + public boolean isConnected() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "isConnected [PumpPluginAbstract]."); + return pumpState.isConnected(); + } + + + public boolean isConnecting() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "isConnecting [PumpPluginAbstract]."); + return pumpState == PumpDriverState.Connecting; + } + + + public void connect(@NonNull String reason) { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "connect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); + } + + + public void disconnect(@NonNull String reason) { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "disconnect (reason={}) [PumpPluginAbstract] - default (empty) implementation." + reason); + } + + + public void stopConnecting() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "stopConnecting [PumpPluginAbstract] - default (empty) implementation."); + } + + + @Override + public boolean isHandshakeInProgress() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "isHandshakeInProgress [PumpPluginAbstract] - default (empty) implementation."); + return false; + } + + + @Override + public void finishHandshaking() { + if (displayConnectionMessages) + aapsLogger.debug(LTag.PUMP, "finishHandshaking [PumpPluginAbstract] - default (empty) implementation."); + } + + // Upload to pump new basal profile + @NonNull public PumpEnactResult setNewBasalProfile(@NonNull Profile profile) { + aapsLogger.debug(LTag.PUMP, "setNewBasalProfile [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + public boolean isThisProfileSet(@NonNull Profile profile) { + aapsLogger.debug(LTag.PUMP, "isThisProfileSet [PumpPluginAbstract] - Not implemented."); + return true; + } + + + public long lastDataTime() { + aapsLogger.debug(LTag.PUMP, "lastDataTime [PumpPluginAbstract]."); + return getPumpStatusData().lastConnection; + } + + + public double getBaseBasalRate() { + aapsLogger.debug(LTag.PUMP, "getBaseBasalRate [PumpPluginAbstract] - Not implemented."); + return 0.0d; + } // base basal rate, not temp basal + + + public void stopBolusDelivering() { + aapsLogger.debug(LTag.PUMP, "stopBolusDelivering [PumpPluginAbstract] - Not implemented."); + } + + + @NonNull @Override + public PumpEnactResult setTempBasalAbsolute(double absoluteRate, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { + aapsLogger.debug(LTag.PUMP, "setTempBasalAbsolute [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull @Override + public PumpEnactResult setTempBasalPercent(int percent, int durationInMinutes, @NonNull Profile profile, boolean enforceNew, @NonNull PumpSync.TemporaryBasalType tbrType) { + aapsLogger.debug(LTag.PUMP, "setTempBasalPercent [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull public PumpEnactResult setExtendedBolus(double insulin, int durationInMinutes) { + aapsLogger.debug(LTag.PUMP, "setExtendedBolus [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + // some pumps might set a very short temp close to 100% as cancelling a temp can be noisy + // when the cancel request is requested by the user (forced), the pump should always do a real cancel + + @NonNull public PumpEnactResult cancelTempBasal(boolean enforceNew) { + aapsLogger.debug(LTag.PUMP, "cancelTempBasal [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull public PumpEnactResult cancelExtendedBolus() { + aapsLogger.debug(LTag.PUMP, "cancelExtendedBolus [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + // Status to be passed to NS + + // public JSONObject getJSONStatus(Profile profile, String profileName) { + // return pumpDriver.getJSONStatus(profile, profileName); + // } + + public String deviceID() { + aapsLogger.debug(LTag.PUMP, "deviceID [PumpPluginAbstract] - Not implemented."); + return "FakeDevice"; + } + + + // Pump capabilities + + @NonNull public PumpDescription getPumpDescription() { + return pumpDescription; + } + + + // Short info for SMS, Wear etc + + public boolean isFakingTempsByExtendedBoluses() { + aapsLogger.debug(LTag.PUMP, "isFakingTempsByExtendedBoluses [PumpPluginAbstract] - Not implemented."); + return false; + } + + + @NonNull @Override + public PumpEnactResult loadTDDs() { + aapsLogger.debug(LTag.PUMP, "loadTDDs [PumpPluginAbstract] - Not implemented."); + return getOperationNotSupportedWithCustomText(R.string.pump_operation_not_supported_by_pump_driver); + } + + + @NonNull @Override + public JSONObject getJSONStatus(@NonNull Profile profile, @NonNull String profileName, @NonNull String version) { + + if ((getPumpStatusData().lastConnection + 60 * 60 * 1000L) < System.currentTimeMillis()) { + return new JSONObject(); + } + + long now = System.currentTimeMillis(); + JSONObject pump = new JSONObject(); + JSONObject battery = new JSONObject(); + JSONObject status = new JSONObject(); + JSONObject extended = new JSONObject(); + try { + battery.put("percent", getPumpStatusData().batteryRemaining); + status.put("status", getPumpStatusData().pumpStatusType != null ? getPumpStatusData().pumpStatusType.getStatus() : "normal"); + extended.put("Version", version); + try { + extended.put("ActiveProfile", profileName); + } catch (Exception ignored) { + } + +<<<<<<< HEAD + // TODO fix + TemporaryBasal tb = activePlugin.getActiveTreatments().getTempBasalFromHistory(System.currentTimeMillis()); +======= + PumpSync.PumpState.TemporaryBasal tb = pumpSync.expectedPumpState().getTemporaryBasal(); +>>>>>>> meallink + if (tb != null) { + extended.put("TempBasalAbsoluteRate", convertedToAbsolute(tb, now, profile)); + extended.put("TempBasalStart", dateUtil.dateAndTimeString(tb.getTimestamp())); + extended.put("TempBasalRemaining", getPlannedRemainingMinutes(tb)); + } + +<<<<<<< HEAD + // TODO fix + ExtendedBolus eb = activePlugin.getActiveTreatments().getExtendedBolusFromHistory(System.currentTimeMillis()); +======= + PumpSync.PumpState.ExtendedBolus eb = pumpSync.expectedPumpState().getExtendedBolus(); +>>>>>>> meallink + if (eb != null) { + extended.put("ExtendedBolusAbsoluteRate", eb.getRate()); + extended.put("ExtendedBolusStart", dateUtil.dateAndTimeString(eb.getTimestamp())); + extended.put("ExtendedBolusRemaining", getPlannedRemainingMinutes(eb)); + } + + status.put("timestamp", dateUtil.toISOString(dateUtil.now())); + + pump.put("battery", battery); + pump.put("status", status); + pump.put("extended", extended); + pump.put("reservoir", getPumpStatusData().reservoirRemainingUnits); + pump.put("clock", dateUtil.toISOString(dateUtil.now())); + } catch (JSONException e) { + aapsLogger.error("Unhandled exception", e); + } + return pump; + } + + + // FIXME i18n, null checks: iob, TDD + @NonNull @Override + public String shortStatus(boolean veryShort) { + String ret = ""; + if (getPumpStatusData().lastConnection != 0) { + long agoMsec = System.currentTimeMillis() - getPumpStatusData().lastConnection; + int agoMin = (int) (agoMsec / 60d / 1000d); + ret += "LastConn: " + agoMin + " min ago\n"; + } + if (getPumpStatusData().lastBolusTime != null && getPumpStatusData().lastBolusTime.getTime() != 0) { + ret += "LastBolus: " + DecimalFormatter.INSTANCE.to2Decimal(getPumpStatusData().lastBolusAmount) + "U @" + // + android.text.format.DateFormat.format("HH:mm", getPumpStatusData().lastBolusTime) + "\n"; + } +<<<<<<< HEAD + // TODO fix + TemporaryBasal activeTemp = activePlugin.getActiveTreatments().getRealTempBasalFromHistory(System.currentTimeMillis()); +======= + PumpSync.PumpState.TemporaryBasal activeTemp = pumpSync.expectedPumpState().getTemporaryBasal(); +>>>>>>> meallink + if (activeTemp != null) { + ret += "Temp: " + PumpStateExtensionKt.toStringFull(activeTemp, dateUtil) + "\n"; + } +<<<<<<< HEAD + // TODO fix + ExtendedBolus activeExtendedBolus = activePlugin.getActiveTreatments().getExtendedBolusFromHistory( + System.currentTimeMillis()); +======= + PumpSync.PumpState.ExtendedBolus activeExtendedBolus = pumpSync.expectedPumpState().getExtendedBolus(); +>>>>>>> meallink + if (activeExtendedBolus != null) { + ret += "Extended: " + PumpStateExtensionKt.toStringFull(activeExtendedBolus, dateUtil) + "\n"; + } + // if (!veryShort) { + // ret += "TDD: " + DecimalFormatter.to0Decimal(pumpStatus.dailyTotalUnits) + " / " + // + pumpStatus.maxDailyTotalUnits + " U\n"; + // } + ret += "IOB: " + getPumpStatusData().iob + "U\n"; + ret += "Reserv: " + DecimalFormatter.INSTANCE.to0Decimal(getPumpStatusData().reservoirRemainingUnits) + "U\n"; + ret += "Batt: " + getPumpStatusData().batteryRemaining + "\n"; + return ret; + } + + + @NonNull @Override + public PumpEnactResult deliverTreatment(DetailedBolusInfo detailedBolusInfo) { + + try { + if (detailedBolusInfo.insulin == 0 && detailedBolusInfo.carbs == 0) { + // neither carbs nor bolus requested + aapsLogger.error("deliverTreatment: Invalid input"); + return new PumpEnactResult(getInjector()).success(false).enacted(false).bolusDelivered(0d).carbsDelivered(0d) + .comment(R.string.invalidinput); + } else if (detailedBolusInfo.insulin > 0) { + // bolus needed, ask pump to deliver it + return deliverBolus(detailedBolusInfo); + } else { + //if (MedtronicHistoryData.doubleBolusDebug) + // aapsLogger.debug("DoubleBolusDebug: deliverTreatment::(carb only entry)"); + + // TODO fix + // no bolus required, carb only treatment + activePlugin.getActiveTreatments().addToHistoryTreatment(detailedBolusInfo, true); + + EventOverviewBolusProgress bolusingEvent = EventOverviewBolusProgress.INSTANCE; + bolusingEvent.setT(new EventOverviewBolusProgress.Treatment(0, 0, detailedBolusInfo.getBolusType() == DetailedBolusInfo.BolusType.SMB)); + bolusingEvent.setPercent(100); + rxBus.send(bolusingEvent); + + aapsLogger.debug(LTag.PUMP, "deliverTreatment: Carb only treatment."); + + return new PumpEnactResult(getInjector()).success(true).enacted(true).bolusDelivered(0d) + .carbsDelivered(detailedBolusInfo.carbs).comment(R.string.common_resultok); + } + } finally { + triggerUIChange(); + } + + } + + + protected void refreshCustomActionsList() { + rxBus.send(new EventCustomActionsChanged()); + } + + + @NonNull public ManufacturerType manufacturer() { + return pumpType.getManufacturer(); + } + + @NonNull + public PumpType model() { + return pumpType; + } + + + public PumpType getPumpType() { + return pumpType; + } + + + public void setPumpType(PumpType pumpType) { + this.pumpType = pumpType; + this.pumpDescription.setPumpDescription(pumpType); + } + + + public boolean canHandleDST() { + return false; + } + + + protected abstract PumpEnactResult deliverBolus(DetailedBolusInfo detailedBolusInfo); + + protected abstract void triggerUIChange(); + + private PumpEnactResult getOperationNotSupportedWithCustomText(int resourceId) { + return new PumpEnactResult(getInjector()).success(false).enacted(false).comment(resourceId); + } + + // PumpSync + + Map driverHistory = new HashMap<>(); + + public abstract long generateTempId(long timeMillis); + + public boolean addBolusWithTempId(DetailedBolusInfo detailedBolusInfo, boolean writeToInternalHistory) { + long temporaryId = generateTempId(detailedBolusInfo.timestamp); + boolean response = pumpSync.addBolusWithTempId(detailedBolusInfo.timestamp, detailedBolusInfo.insulin, + generateTempId(detailedBolusInfo.timestamp), detailedBolusInfo.getBolusType(), + getPumpType(), serialNumber()); + + if (response && writeToInternalHistory) { + driverHistory.put(temporaryId, new PumpDbEntry(temporaryId, model(), serialNumber(), detailedBolusInfo)); + } + + return response; + } + + public void removeTemporaryId(long temporaryId) { + driverHistory.remove(temporaryId); + } + + +} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java deleted file mode 100644 index 2b33249503..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.java +++ /dev/null @@ -1,182 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import org.apache.commons.lang3.StringUtils; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javax.inject.Inject; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public abstract class MedtronicHistoryDecoder implements MedtronicHistoryDecoderInterface { - - @Inject protected AAPSLogger aapsLogger; - @Inject protected MedtronicUtil medtronicUtil; - - protected ByteUtil bitUtils; - - // STATISTICS (remove at later time or not) - protected boolean statisticsEnabled = true; - protected Map unknownOpCodes; - protected Map> mapStatistics; - - - public MedtronicHistoryDecoder() { - } - - - // public abstract Class getHistoryEntryClass(); - - // public abstract RecordDecodeStatus decodeRecord(T record); - - public abstract void postProcess(); - - - protected abstract void runPostDecodeTasks(); - - - // TODO_ extend this to also use bigger pages (for now we support only 1024 pages) - private List checkPage(RawHistoryPage page, boolean partial) throws RuntimeException { - List byteList = new ArrayList(); - - // if (!partial && page.getData().length != 1024 /* page.commandType.getRecordLength() */) { - // LOG.error("Page size is not correct. Size should be {}, but it was {} instead.", 1024, - // page.getData().length); - // // throw exception perhaps - // return byteList; - // } - - if (medtronicUtil.getMedtronicPumpModel() == null) { - aapsLogger.error(LTag.PUMPCOMM, "Device Type is not defined."); - return byteList; - } - - if (page.getData().length != 1024) { - return ByteUtil.getListFromByteArray(page.getData()); - } else if (page.isChecksumOK()) { - return ByteUtil.getListFromByteArray(page.getOnlyData()); - } else { - return null; - } - } - - - public List processPageAndCreateRecords(RawHistoryPage rawHistoryPage) { - return processPageAndCreateRecords(rawHistoryPage, false); - } - - - protected void prepareStatistics() { - if (!statisticsEnabled) - return; - - unknownOpCodes = new HashMap<>(); - mapStatistics = new HashMap<>(); - - for (RecordDecodeStatus stat : RecordDecodeStatus.values()) { - mapStatistics.put(stat, new HashMap<>()); - } - } - - - protected void addToStatistics(MedtronicHistoryEntryInterface pumpHistoryEntry, RecordDecodeStatus status, Integer opCode) { - if (!statisticsEnabled) - return; - - if (opCode != null) { - if (!unknownOpCodes.containsKey(opCode)) { - unknownOpCodes.put(opCode, opCode); - } - return; - } - - if (!mapStatistics.get(status).containsKey(pumpHistoryEntry.getEntryTypeName())) { - mapStatistics.get(status).put(pumpHistoryEntry.getEntryTypeName(), ""); - } - } - - - protected void showStatistics() { - StringBuilder sb = new StringBuilder(); - - for (Map.Entry unknownEntry : unknownOpCodes.entrySet()) { - StringUtil.appendToStringBuilder(sb, "" + unknownEntry.getKey(), ", "); - } - - aapsLogger.info(LTag.PUMPCOMM, "STATISTICS OF PUMP DECODE"); - - if (unknownOpCodes.size() > 0) { - aapsLogger.warn(LTag.PUMPCOMM, "Unknown Op Codes: " + sb.toString()); - } - - for (Map.Entry> entry : mapStatistics.entrySet()) { - sb = new StringBuilder(); - - if (entry.getKey() != RecordDecodeStatus.OK) { - if (entry.getValue().size() == 0) - continue; - - for (Map.Entry entrysub : entry.getValue().entrySet()) { - StringUtil.appendToStringBuilder(sb, entrysub.getKey(), ", "); - } - - String spaces = StringUtils.repeat(" ", 14 - entry.getKey().name().length()); - - aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s%s - %d. Elements: %s", entry.getKey().name(), spaces, entry.getValue().size(), sb.toString())); - } else { - aapsLogger.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s - %d", entry.getKey().name(), entry.getValue().size())); - } - } - } - - - private int getUnsignedByte(byte value) { - if (value < 0) - return value + 256; - else - return value; - } - - - protected int getUnsignedInt(int value) { - if (value < 0) - return value + 256; - else - return value; - } - - - public String getFormattedFloat(float value, int decimals) { - return StringUtil.getFormatedValueUS(value, decimals); - } - - - private List processPageAndCreateRecords(RawHistoryPage rawHistoryPage, boolean partial) { - List dataClear = checkPage(rawHistoryPage, partial); - List records = createRecords(dataClear); - - for (T record : records) { - decodeRecord(record); - } - - runPostDecodeTasks(); - - return records; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt new file mode 100644 index 0000000000..a6a8744299 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoder.kt @@ -0,0 +1,132 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import org.apache.commons.lang3.StringUtils +import java.util.* +import javax.inject.Inject +import kotlin.jvm.Throws + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +abstract class MedtronicHistoryDecoder : MedtronicHistoryDecoderInterface { + + @JvmField @Inject + var aapsLogger: AAPSLogger? = null + + @JvmField @Inject + var medtronicUtil: MedtronicUtil? = null + protected var bitUtils: ByteUtil? = null + + // STATISTICS (remove at later time or not) + protected var statisticsEnabled = true + @JvmField protected var unknownOpCodes: MutableMap? = null + protected var mapStatistics: MutableMap>? = null + + // public abstract Class getHistoryEntryClass(); + // public abstract RecordDecodeStatus decodeRecord(T record); + abstract fun postProcess() + protected abstract fun runPostDecodeTasks() + + // TODO_ extend this to also use bigger pages (for now we support only 1024 pages) + @Throws(RuntimeException::class) + private fun checkPage(page: RawHistoryPage, partial: Boolean): List { + val byteList: List = ArrayList() + + if (medtronicUtil!!.medtronicPumpModel == null) { + aapsLogger!!.error(LTag.PUMPCOMM, "Device Type is not defined.") + return byteList + } + return if (page.data.size != 1024) { + ByteUtil.getListFromByteArray(page.data) + } else if (page.isChecksumOK) { + ByteUtil.getListFromByteArray(page.onlyData) + } else { + byteList + } + } + + fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage): List? { + return processPageAndCreateRecords(rawHistoryPage, false) + } + + protected fun prepareStatistics() { + if (!statisticsEnabled) return + unknownOpCodes = HashMap() + mapStatistics = HashMap() + for (stat in RecordDecodeStatus.values()) { + (mapStatistics as HashMap>)[stat] = HashMap() + } + } + + protected fun addToStatistics(pumpHistoryEntry: MedtronicHistoryEntryInterface, status: RecordDecodeStatus?, opCode: Int?) { + if (!statisticsEnabled) return + if (opCode != null) { + if (!unknownOpCodes!!.containsKey(opCode)) { + unknownOpCodes!![opCode] = opCode + } + return + } + if (!mapStatistics!![status]!!.containsKey(pumpHistoryEntry.entryTypeName)) { + mapStatistics!![status]!!.put(pumpHistoryEntry.entryTypeName!!, "") + } + } + + protected fun showStatistics() { + var sb = StringBuilder() + for ((key) in unknownOpCodes!!) { + StringUtil.appendToStringBuilder(sb, "" + key, ", ") + } + aapsLogger!!.info(LTag.PUMPCOMM, "STATISTICS OF PUMP DECODE") + if (unknownOpCodes!!.size > 0) { + aapsLogger!!.warn(LTag.PUMPCOMM, "Unknown Op Codes: $sb") + } + for ((key, value) in mapStatistics!!) { + sb = StringBuilder() + if (key !== RecordDecodeStatus.OK) { + if (value.size == 0) continue + for ((key1) in value) { + StringUtil.appendToStringBuilder(sb, key1, ", ") + } + val spaces = StringUtils.repeat(" ", 14 - key.name.length) + aapsLogger!!.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s%s - %d. Elements: %s", key.name, spaces, value.size, sb.toString())) + } else { + aapsLogger!!.info(LTag.PUMPCOMM, String.format(Locale.ENGLISH, " %s - %d", key.name, value.size)) + } + } + } + + private fun getUnsignedByte(value: Byte): Int { + return if (value < 0) value + 256 else value.toInt() + } + + protected fun getUnsignedInt(value: Int): Int { + return if (value < 0) value + 256 else value + } + + protected fun getUnsignedInt(value: Byte): Int { + return if (value < 0) value + 256 else value.toInt() + } + + fun getFormattedFloat(value: Float, decimals: Int): String { + return StringUtil.getFormatedValueUS(value, decimals) + } + + private fun processPageAndCreateRecords(rawHistoryPage: RawHistoryPage, partial: Boolean): List { + val dataClear = checkPage(rawHistoryPage, partial) + val records: List = createRecords(dataClear) + for (record in records!!) { + decodeRecord(record) + } + runPostDecodeTasks() + return records + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java deleted file mode 100644 index b98b2d7d33..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.java +++ /dev/null @@ -1,15 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import java.util.List; - -/** - * Created by andy on 3/10/19. - */ - -public interface MedtronicHistoryDecoderInterface { - - RecordDecodeStatus decodeRecord(T record); - - List createRecords(List dataClear); - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt new file mode 100644 index 0000000000..1137371843 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryDecoderInterface.kt @@ -0,0 +1,10 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +/** + * Created by andy on 3/10/19. + */ +interface MedtronicHistoryDecoderInterface { + + fun decodeRecord(record: T): RecordDecodeStatus? + fun createRecords(dataClear: List): List +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java deleted file mode 100644 index b5d41f6bfa..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.java +++ /dev/null @@ -1,316 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import com.google.gson.annotations.Expose; - -import org.slf4j.Logger; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public abstract class MedtronicHistoryEntry implements MedtronicHistoryEntryInterface { - - protected List rawData; - - public static final Logger LOG = StacktraceLoggerWrapper.getLogger(MedtronicHistoryEntry.class); - - protected int[] sizes = new int[3]; - - protected byte[] head; - protected byte[] datetime; - protected byte[] body; - - // protected LocalDateTime dateTime; - - public long id; - - @Expose - public String DT; - - @Expose - public Long atechDateTime; - - @Expose - protected Map decodedData; - - public long phoneDateTime; // time on phone - - /** - * Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255) - */ - protected Long pumpId; - - /** - * if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's - * are not actually - * linked)) - */ - public boolean linked = false; - - /** - * Linked object, see linked - */ - public Object linkedObject = null; - - - public void setLinkedObject(Object linkedObject) { - this.linked = true; - this.linkedObject = linkedObject; - } - - - public void setData(List listRawData, boolean doNotProcess) { - this.rawData = listRawData; - - // System.out.println("Head: " + sizes[0] + ", dates: " + sizes[1] + - // ", body=" + sizes[2]); - - if (doNotProcess) - return; - - head = new byte[getHeadLength() - 1]; - for (int i = 1; i < (getHeadLength()); i++) { - head[i - 1] = listRawData.get(i); - } - - if (getDateTimeLength() > 0) { - datetime = new byte[getDateTimeLength()]; - - for (int i = getHeadLength(), j = 0; j < getDateTimeLength(); i++, j++) { - datetime[j] = listRawData.get(i); - } - } - - if (getBodyLength() > 0) { - body = new byte[getBodyLength()]; - - for (int i = (getHeadLength() + getDateTimeLength()), j = 0; j < getBodyLength(); i++, j++) { - body[j] = listRawData.get(i); - } - - } - - } - - - public String getDateTimeString() { - return this.DT == null ? "Unknown" : this.DT; - } - - - public String getDecodedDataAsString() { - if (decodedData == null) - if (isNoDataEntry()) - return "No data"; - else - return ""; - else - return decodedData.toString(); - } - - - public boolean hasData() { - return (decodedData != null) || (isNoDataEntry()) || getEntryTypeName().equals("UnabsorbedInsulin"); - } - - - public boolean isNoDataEntry() { - return (sizes[0] == 2 && sizes[1] == 5 && sizes[2] == 0); - } - - - public Map getDecodedData() { - return this.decodedData; - } - - - public Object getDecodedDataEntry(String key) { - return this.decodedData != null ? this.decodedData.get(key) : null; - } - - - public boolean hasDecodedDataEntry(String key) { - return this.decodedData.containsKey(key); - } - - - public boolean showRaw() { - return getEntryTypeName().equals("EndResultTotals"); - } - - - public int getHeadLength() { - return sizes[0]; - } - - - public int getDateTimeLength() { - return sizes[1]; - } - - - public int getBodyLength() { - return sizes[2]; - } - - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - - if (this.DT == null) { - LOG.error("DT is null. RawData=" + ByteUtil.getHex(this.rawData)); - } - - sb.append(getToStringStart()); - sb.append(", DT: " + (this.DT == null ? "null" : StringUtil.getStringInLength(this.DT, 19))); - sb.append(", length="); - sb.append(getHeadLength()); - sb.append(","); - sb.append(getDateTimeLength()); - sb.append(","); - sb.append(getBodyLength()); - sb.append("("); - sb.append((getHeadLength() + getDateTimeLength() + getBodyLength())); - sb.append(")"); - - boolean hasData = hasData(); - - if (hasData) { - sb.append(", data=" + getDecodedDataAsString()); - } - - if (hasData && !showRaw()) { - sb.append("]"); - return sb.toString(); - } - - if (head != null) { - sb.append(", head="); - sb.append(ByteUtil.shortHexString(this.head)); - } - - if (datetime != null) { - sb.append(", datetime="); - sb.append(ByteUtil.shortHexString(this.datetime)); - } - - if (body != null) { - sb.append(", body="); - sb.append(ByteUtil.shortHexString(this.body)); - } - - sb.append(", rawData="); - sb.append(ByteUtil.shortHexString(this.rawData)); - sb.append("]"); - - // sb.append(" DT: "); - // sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss")); - - // sb.append(" Ext: "); - - return sb.toString(); - } - - - public abstract int getOpCode(); - - - public abstract String getToStringStart(); - - - public List getRawData() { - return rawData; - } - - - public byte getRawDataByIndex(int index) { - return rawData.get(index); - } - - - public int getUnsignedRawDataByIndex(int index) { - return ByteUtil.convertUnsignedByteToInt(rawData.get(index)); - } - - - public void setRawData(List rawData) { - this.rawData = rawData; - } - - - public byte[] getHead() { - return head; - } - - - public void setHead(byte[] head) { - this.head = head; - } - - - public byte[] getDatetime() { - return datetime; - } - - - public void setDatetime(byte[] datetime) { - this.datetime = datetime; - } - - - public byte[] getBody() { - return body; - } - - - public void setBody(byte[] body) { - this.body = body; - } - - - public void setAtechDateTime(long dt) { - this.atechDateTime = dt; - this.DT = DateTimeUtil.toString(this.atechDateTime); - } - - - public void addDecodedData(String key, Object value) { - if (decodedData == null) - decodedData = new HashMap<>(); - - decodedData.put(key, value); - } - - - public String toShortString() { - if (head == null) { - return "Unidentified record. "; - } else { - return "HistoryRecord: head=[" + ByteUtil.shortHexString(this.head) + "]"; - } - } - - public boolean containsDecodedData(String key) { - if (decodedData == null) - return false; - - return decodedData.containsKey(key); - } - - // if we extend to CGMS this need to be changed back - // public abstract PumpHistoryEntryType getEntryType(); - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt new file mode 100644 index 0000000000..72e3174178 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntry.kt @@ -0,0 +1,222 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +import android.util.Log +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +abstract class MedtronicHistoryEntry : MedtronicHistoryEntryInterface { + + @JvmField var rawData: List? = null + @JvmField protected var sizes = IntArray(3) + var head: ByteArray? = null + var datetime: ByteArray? = null + var body: ByteArray? = null + + // protected LocalDateTime dateTime; + @JvmField var id: Long = 0 + + @JvmField @Expose + var DT: String? = null + + @JvmField @Expose + var atechDateTime: Long? = null + + @Expose + protected var decodedData: MutableMap? = null + var phoneDateTime // time on phone + : Long = 0 + + /** + * Pump id that will be used with AAPS object (time * 1000 + historyType (max is FF = 255) + */ + protected open var pumpId: Long? = null + + /** + * if history object is already linked to AAPS object (either Treatment, TempBasal or TDD (tdd's + * are not actually + * linked)) + */ + var linked = false + + /** + * Linked object, see linked + */ + var linkedObject: Any? = null + get() = field //= linkedObject + set(value) { + linked = true + field = value + } + + // fun setLinkedObject(linkedObject: Any?) { + // linked = true + // this.linkedObject = linkedObject + // } + + override fun setData(listRawData: List?, doNotProcess: Boolean) { + rawData = listRawData + + // System.out.println("Head: " + sizes[0] + ", dates: " + sizes[1] + + // ", body=" + sizes[2]); + if (!doNotProcess) { + head = ByteArray(headLength - 1) + for (i in 1 until headLength) { + head!![i - 1] = listRawData!![i]!! + } + if (dateTimeLength > 0) { + datetime = ByteArray(dateTimeLength) + var i = headLength + var j = 0 + while (j < dateTimeLength) { + datetime!![j] = listRawData!![i]!! + i++ + j++ + } + } + if (bodyLength > 0) { + body = ByteArray(bodyLength) + var i = headLength + dateTimeLength + var j = 0 + while (j < bodyLength) { + body!![j] = listRawData!![i]!! + i++ + j++ + } + } + } + return + } + + val dateTimeString: String + get() = if (DT == null) "Unknown" else DT!! + + val decodedDataAsString: String + get() = if (decodedData == null) if (isNoDataEntry) "No data" else "" else decodedData.toString() + + fun hasData(): Boolean { + return decodedData != null || isNoDataEntry || entryTypeName == "UnabsorbedInsulin" + } + + val isNoDataEntry: Boolean + get() = sizes[0] == 2 && sizes[1] == 5 && sizes[2] == 0 + + // fun getDecodedData(): Map? { + // return decodedData + // } + + fun getDecodedDataEntry(key: String?): Any? { + return if (decodedData != null) decodedData!![key] else null + } + + fun hasDecodedDataEntry(key: String?): Boolean { + return decodedData!!.containsKey(key) + } + + fun showRaw(): Boolean { + return entryTypeName == "EndResultTotals" + } + + val headLength: Int + get() = sizes[0] + + val dateTimeLength: Int + get() = sizes[1] + + val bodyLength: Int + get() = sizes[2] + + override fun toString(): String { + val sb = StringBuilder() + if (DT == null) { + Log.e("", "DT is null. RawData=" + ByteUtil.getHex(rawData)) + } + sb.append(toStringStart) + sb.append(", DT: " + if (DT == null) "null" else StringUtil.getStringInLength(DT, 19)) + sb.append(", length=") + sb.append(headLength) + sb.append(",") + sb.append(dateTimeLength) + sb.append(",") + sb.append(bodyLength) + sb.append("(") + sb.append(headLength + dateTimeLength + bodyLength) + sb.append(")") + val hasData = hasData() + if (hasData) { + sb.append(", data=$decodedDataAsString") + } + if (hasData && !showRaw()) { + sb.append("]") + return sb.toString() + } + if (head != null) { + sb.append(", head=") + sb.append(ByteUtil.shortHexString(head)) + } + if (datetime != null) { + sb.append(", datetime=") + sb.append(ByteUtil.shortHexString(datetime)) + } + if (body != null) { + sb.append(", body=") + sb.append(ByteUtil.shortHexString(body)) + } + sb.append(", rawData=") + sb.append(ByteUtil.shortHexString(rawData)) + sb.append("]") + + // sb.append(" DT: "); + // sb.append(this.dateTime == null ? " - " : this.dateTime.toString("dd.MM.yyyy HH:mm:ss")); + + // sb.append(" Ext: "); + return sb.toString() + } + + abstract val opCode: Byte? + abstract val toStringStart: String? + + fun getRawDataByIndex(index: Int): Byte { + return rawData!![index] + } + + fun getRawDataByIndexInt(index: Int): Int { + return rawData!![index].toInt() + } + + fun getUnsignedRawDataByIndex(index: Int): Int { + return ByteUtil.convertUnsignedByteToInt(rawData!![index]) + } + + fun setAtechDateTime(dt: Long) { + atechDateTime = dt + DT = DateTimeUtil.toString(atechDateTime!!) + } + + fun addDecodedData(key: String, value: Any?) { + if (decodedData == null) decodedData = HashMap() + decodedData!![key] = value + } + + fun toShortString(): String { + return if (head == null) { + "Unidentified record. " + } else { + "HistoryRecord: head=[" + ByteUtil.shortHexString(head) + "]" + } + } + + fun containsDecodedData(key: String?): Boolean { + return if (decodedData == null) false else decodedData!!.containsKey(key) + } // if we extend to CGMS this need to be changed back + // public abstract PumpHistoryEntryType getEntryType(); +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java deleted file mode 100644 index 38b7e1dbeb..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import java.util.List; - -/** - * Created by andy on 7/24/18. - */ -public interface MedtronicHistoryEntryInterface { - - String getEntryTypeName(); - - void setData(List listRawData, boolean doNotProcess); - - int getDateLength(); - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt new file mode 100644 index 0000000000..32f6d4458a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/MedtronicHistoryEntryInterface.kt @@ -0,0 +1,11 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +/** + * Created by andy on 7/24/18. + */ +interface MedtronicHistoryEntryInterface { + + val entryTypeName: String? + fun setData(listRawData: List?, doNotProcess: Boolean) + val dateLength: Int +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java deleted file mode 100644 index 182e09b1bd..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.java +++ /dev/null @@ -1,87 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -import java.util.Arrays; -import java.util.Locale; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.CRC; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * Created by geoff on 6/4/16. - */ -public class RawHistoryPage { - - private final AAPSLogger aapsLogger; - - private byte[] data = new byte[0]; - - - public RawHistoryPage(AAPSLogger aapsLogger) { - this.aapsLogger = aapsLogger; - } - - - public void appendData(byte[] newdata) { - data = ByteUtil.concat(data, newdata); - } - - - public byte[] getData() { - return data; - } - - - byte[] getOnlyData() { - return Arrays.copyOfRange(data, 0, 1022); - } - - - public int getLength() { - return data.length; - } - - - public boolean isChecksumOK() { - if (getLength() != 1024) { - return false; - } - byte[] computedCRC = CRC.calculate16CCITT(ByteUtil.substring(data, 0, 1022)); - - int crcCalculated = ByteUtil.toInt(computedCRC[0], computedCRC[1]); - int crcStored = ByteUtil.toInt(data[1022], data[1023]); - - if (crcCalculated != crcStored) { - aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Stored CRC (%d) is different than calculated (%d), but ignored for now.", crcStored, - crcCalculated)); - } else { - if (MedtronicUtil.isLowLevelDebug()) - aapsLogger.debug(LTag.PUMPBTCOMM, "CRC ok."); - } - - return crcCalculated == crcStored; - } - - - public void dumpToDebug() { - int linesize = 80; - int offset = 0; - - StringBuilder sb = new StringBuilder(); - - while (offset < data.length) { - int bytesToLog = linesize; - if (offset + linesize > data.length) { - bytesToLog = data.length - offset; - } - sb.append(ByteUtil.shortHexString(ByteUtil.substring(data, offset, bytesToLog)) + " "); - // sb.append("\n"); - - offset += linesize; - } - - aapsLogger.info(LTag.PUMPBTCOMM, "History Page Data:\n" + sb.toString()); - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt new file mode 100644 index 0000000000..792120b688 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RawHistoryPage.kt @@ -0,0 +1,61 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.CRC +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import java.util.* + +/** + * Created by geoff on 6/4/16. + */ +class RawHistoryPage(private val aapsLogger: AAPSLogger) { + + var data = ByteArray(0) + private set + + fun appendData(newdata: ByteArray?) { + data = ByteUtil.concat(data, newdata) + } + + val onlyData: ByteArray + get() = Arrays.copyOfRange(data, 0, 1022) + + val length: Int + get() = data.size + + val isChecksumOK: Boolean + get() { + if (length != 1024) { + return false + } + val computedCRC = CRC.calculate16CCITT(ByteUtil.substring(data, 0, 1022)) + val crcCalculated = ByteUtil.toInt(computedCRC[0].toInt(), computedCRC[1].toInt()) + val crcStored = ByteUtil.toInt(data[1022].toInt(), data[1023].toInt()) + if (crcCalculated != crcStored) { + aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Stored CRC (%d) is different than calculated (%d), but ignored for now.", crcStored, + crcCalculated)) + } else { + if (MedtronicUtil.isLowLevelDebug()) aapsLogger.debug(LTag.PUMPBTCOMM, "CRC ok.") + } + return crcCalculated == crcStored + } + + fun dumpToDebug() { + val linesize = 80 + var offset = 0 + val sb = StringBuilder() + while (offset < data.size) { + var bytesToLog = linesize + if (offset + linesize > data.size) { + bytesToLog = data.size - offset + } + sb.append(ByteUtil.shortHexString(ByteUtil.substring(data, offset, bytesToLog)) + " ") + // sb.append("\n"); + offset += linesize + } + aapsLogger.info(LTag.PUMPBTCOMM, "History Page Data:\n$sb") + } + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java deleted file mode 100644 index 18cb02cfad..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.java +++ /dev/null @@ -1,30 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - * - * Author: Andy {andy.rozman@gmail.com} - */ - -public enum RecordDecodeStatus { - OK("OK "), // - Ignored("IGNORE "), // - NotSupported("N/A YET"), // - Error("ERROR "), // - WIP("WIP "), // - Unknown("UNK "); - - String description; - - - RecordDecodeStatus(String description) { - this.description = description; - - } - - - public String getDescription() { - return description; - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt new file mode 100644 index 0000000000..82194b1f03 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/RecordDecodeStatus.kt @@ -0,0 +1,19 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class RecordDecodeStatus(var description: String) { + + OK("OK "), // + Ignored("IGNORE "), // + NotSupported("N/A YET"), // + Error("ERROR "), // + WIP("WIP "), // + Unknown("UNK "); + +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java deleted file mode 100644 index 4d35426fb8..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.java +++ /dev/null @@ -1,92 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms; - -import org.apache.commons.lang3.StringUtils; -import org.joda.time.LocalDateTime; - -import java.util.List; - -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.comm.history.MedtronicHistoryEntry; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - * - * Author: Andy {andy.rozman@gmail.com} - */ - -public class CGMSHistoryEntry extends MedtronicHistoryEntry { - - private CGMSHistoryEntryType entryType; - private Integer opCode; // this is set only when we have unknown entry... - - - public CGMSHistoryEntryType getEntryType() { - return entryType; - } - - - public void setEntryType(CGMSHistoryEntryType entryType) { - this.entryType = entryType; - - this.sizes[0] = entryType.getHeadLength(); - this.sizes[1] = entryType.getDateLength(); - this.sizes[2] = entryType.getBodyLength(); - } - - - @Override - public String getEntryTypeName() { - return this.entryType.name(); - } - - - public void setData(List listRawData, boolean doNotProcess) { - if (this.entryType.schemaSet) { - super.setData(listRawData, doNotProcess); - } else { - this.rawData = listRawData; - } - } - - - @Override - public int getDateLength() { - return this.entryType.getDateLength(); - } - - - @Override - public int getOpCode() { - if (opCode == null) - return entryType.getOpCode(); - else - return opCode; - } - - - public void setOpCode(Integer opCode) { - this.opCode = opCode; - } - - - public boolean hasTimeStamp() { - return (this.entryType.hasDate()); - } - - - @Override - public String getToStringStart() { - - return "CGMSHistoryEntry [type=" + StringUtils.rightPad(entryType.name(), 18) + " [" - + StringUtils.leftPad("" + getOpCode(), 3) + ", 0x" + ByteUtil.getCorrectHexValue(getOpCode()) + "]"; - } - - - public void setDateTime(LocalDateTime timeStamp, int getIndex) { - - setAtechDateTime(DateTimeUtil.toATechDate(timeStamp.plusMinutes(getIndex * 5))); - - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt new file mode 100644 index 0000000000..2ede3d65c1 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntry.kt @@ -0,0 +1,55 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms + +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.comm.history.MedtronicHistoryEntry +import org.apache.commons.lang3.StringUtils +import org.joda.time.LocalDateTime + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * Author: Andy {andy.rozman@gmail.com} + */ +class CGMSHistoryEntry : MedtronicHistoryEntry() { + + var entryType: CGMSHistoryEntryType? = null + private set + + override var opCode: Byte? = null // this is set only when we have unknown entry... + get() = if (field == null) entryType!!.code.toByte() else field + + fun setEntryType(entryType: CGMSHistoryEntryType) { + this.entryType = entryType + sizes[0] = entryType.headLength + sizes[1] = entryType.dateLength + sizes[2] = entryType.bodyLength + } + + override val entryTypeName: String + get() = entryType!!.name + + override fun setData(listRawData: List?, doNotProcess: Boolean) { + if (entryType!!.schemaSet) { + super.setData(listRawData, doNotProcess) + } else { + rawData = listRawData + } + } + + override val dateLength: Int + get() = entryType!!.dateLength + + fun hasTimeStamp(): Boolean { + return entryType!!.hasDate() + } + + override val toStringStart: String + get() = ("CGMSHistoryEntry [type=" + StringUtils.rightPad(entryType!!.name, 18) + " [" + + StringUtils.leftPad("" + opCode, 3) + ", 0x" + ByteUtil.getCorrectHexValue(opCode!!) + "]") + + fun setDateTime(timeStamp: LocalDateTime, getIndex: Int) { + setAtechDateTime(DateTimeUtil.toATechDate(timeStamp.plusMinutes(getIndex * 5))) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java deleted file mode 100644 index 64161c720a..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.java +++ /dev/null @@ -1,135 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms; - -import java.util.HashMap; -import java.util.Map; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - * - * Author: Andy {andy.rozman@gmail.com} - */ - -public enum CGMSHistoryEntryType { - - None(0, "None", 1, 0, 0, DateType.None), // - - DataEnd(0x01, "DataEnd", 1, 0, 0, DateType.PreviousTimeStamp), // - SensorWeakSignal(0x02, "SensorWeakSignal", 1, 0, 0, DateType.PreviousTimeStamp), // - SensorCal(0x03, "SensorCal", 1, 0, 1, DateType.PreviousTimeStamp), // - SensorPacket(0x04, "SensorPacket", 1, 0, 1, DateType.PreviousTimeStamp), - SensorError(0x05, "SensorError", 1, 0, 1, DateType.PreviousTimeStamp), - SensorDataLow(0x06, "SensorDataLow", 1, 0, 1, DateType.PreviousTimeStamp), - SensorDataHigh(0x07, "SensorDataHigh", 1, 0, 1, DateType.PreviousTimeStamp), - SensorTimestamp(0x08, "SensorTimestamp", 1, 4, 0, DateType.MinuteSpecific), // - BatteryChange(0x0a, "BatteryChange", 1, 4, 0, DateType.MinuteSpecific), // - SensorStatus(0x0b, "SensorStatus", 1, 4, 0, DateType.MinuteSpecific), // - DateTimeChange(0x0c, "DateTimeChange", 1, 4, 0, DateType.SecondSpecific), // - SensorSync(0x0d, "SensorSync',packet_size=4", 1, 4, 0, DateType.MinuteSpecific), // - CalBGForGH(0x0e, "CalBGForGH',packet_size=5", 1, 4, 1, DateType.MinuteSpecific), // - SensorCalFactor(0x0f, "SensorCalFactor", 1, 4, 2, DateType.MinuteSpecific), // - Something10(0x10, "10-Something", 1, 4, 0, DateType.MinuteSpecific), // - Something19(0x13, "19-Something", 1, 0, 0, DateType.PreviousTimeStamp), - GlucoseSensorData(0xFF, "GlucoseSensorData", 1, 0, 0, DateType.PreviousTimeStamp); - - private static final Map opCodeMap = new HashMap<>(); - - static { - for (CGMSHistoryEntryType type : values()) { - opCodeMap.put(type.opCode, type); - } - } - - public boolean schemaSet; - private final int opCode; - private final String description; - private final int headLength; - private final int dateLength; - private final int bodyLength; - private final int totalLength; - private final DateType dateType; - - - CGMSHistoryEntryType(int opCode, String name, int head, int date, int body, DateType dateType) { - this.opCode = opCode; - this.description = name; - this.headLength = head; - this.dateLength = date; - this.bodyLength = body; - this.totalLength = (head + date + body); - this.schemaSet = true; - this.dateType = dateType; - } - - - // private CGMSHistoryEntryType(int opCode, String name, int length) - // { - // this.opCode = opCode; - // this.description = name; - // this.headLength = 0; - // this.dateLength = 0; - // this.bodyLength = 0; - // this.totalLength = length + 1; // opCode - // } - - public static CGMSHistoryEntryType getByCode(int opCode) { - if (opCodeMap.containsKey(opCode)) { - return opCodeMap.get(opCode); - } else - return CGMSHistoryEntryType.None; - } - - - public int getCode() { - return this.opCode; - } - - - public int getTotalLength() { - return totalLength; - } - - - public int getOpCode() { - return opCode; - } - - - public String getDescription() { - return description; - } - - - public int getHeadLength() { - return headLength; - } - - - public int getDateLength() { - return dateLength; - } - - - public int getBodyLength() { - return bodyLength; - } - - - public DateType getDateType() { - return dateType; - } - - - public boolean hasDate() { - return (this.dateType == DateType.MinuteSpecific) || (this.dateType == DateType.SecondSpecific); - } - - public enum DateType { - None, // - MinuteSpecific, // - SecondSpecific, // - PreviousTimeStamp // - - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt new file mode 100644 index 0000000000..a0cc7573c7 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/CGMSHistoryEntryType.kt @@ -0,0 +1,62 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms + +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class CGMSHistoryEntryType(val code: Int, val description: String, val headLength: Int, val dateLength: Int, val bodyLength: Int, dateType: DateType) { + + None(0, "None", 1, 0, 0, DateType.None), // + DataEnd(0x01, "DataEnd", 1, 0, 0, DateType.PreviousTimeStamp), // + SensorWeakSignal(0x02, "SensorWeakSignal", 1, 0, 0, DateType.PreviousTimeStamp), // + SensorCal(0x03, "SensorCal", 1, 0, 1, DateType.PreviousTimeStamp), // + SensorPacket(0x04, "SensorPacket", 1, 0, 1, DateType.PreviousTimeStamp), SensorError(0x05, "SensorError", 1, 0, 1, DateType.PreviousTimeStamp), SensorDataLow(0x06, "SensorDataLow", 1, 0, 1, DateType.PreviousTimeStamp), SensorDataHigh(0x07, "SensorDataHigh", 1, 0, 1, DateType.PreviousTimeStamp), SensorTimestamp(0x08, "SensorTimestamp", 1, 4, 0, DateType.MinuteSpecific), // + BatteryChange(0x0a, "BatteryChange", 1, 4, 0, DateType.MinuteSpecific), // + SensorStatus(0x0b, "SensorStatus", 1, 4, 0, DateType.MinuteSpecific), // + DateTimeChange(0x0c, "DateTimeChange", 1, 4, 0, DateType.SecondSpecific), // + SensorSync(0x0d, "SensorSync',packet_size=4", 1, 4, 0, DateType.MinuteSpecific), // + CalBGForGH(0x0e, "CalBGForGH',packet_size=5", 1, 4, 1, DateType.MinuteSpecific), // + SensorCalFactor(0x0f, "SensorCalFactor", 1, 4, 2, DateType.MinuteSpecific), // + Something10(0x10, "10-Something", 1, 4, 0, DateType.MinuteSpecific), // + Something19(0x13, "19-Something", 1, 0, 0, DateType.PreviousTimeStamp), GlucoseSensorData(0xFF, "GlucoseSensorData", 1, 0, 0, DateType.PreviousTimeStamp); + + companion object { + private val opCodeMap: MutableMap = HashMap() + @JvmStatic fun getByCode(opCode: Int): CGMSHistoryEntryType? { + return if (opCodeMap.containsKey(opCode)) { + opCodeMap[opCode] + } else None + } + + init { + for (type in values()) { + opCodeMap[type.code] = type + } + } + } + + @JvmField var schemaSet: Boolean + val totalLength: Int + val dateType: DateType + + fun hasDate(): Boolean { + return dateType == DateType.MinuteSpecific || dateType == DateType.SecondSpecific + } + + enum class DateType { + None, // + MinuteSpecific, // + SecondSpecific, // + PreviousTimeStamp // + } + + init { + totalLength = headLength + dateLength + bodyLength + schemaSet = true + this.dateType = dateType + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java deleted file mode 100644 index 9d040fc105..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.java +++ /dev/null @@ -1,469 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms; - -import org.joda.time.LocalDateTime; -import org.slf4j.Logger; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.logging.StacktraceLoggerWrapper; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public class MedtronicCGMSHistoryDecoder extends MedtronicHistoryDecoder { - - private static final Logger LOG = StacktraceLoggerWrapper.getLogger(LTag.PUMPCOMM); - - - // CGMSValuesWriter cgmsValuesWriter = null; - - public MedtronicCGMSHistoryDecoder() { - } - - - public RecordDecodeStatus decodeRecord(CGMSHistoryEntry record) { - try { - return decodeRecord(record, false); - } catch (Exception ex) { - LOG.error(" Error decoding: type={}, ex={}", record.getEntryType().name(), ex.getMessage(), ex); - return RecordDecodeStatus.Error; - } - } - - - public RecordDecodeStatus decodeRecord(CGMSHistoryEntry entry, boolean x) { - - if (entry.getDateTimeLength() > 0) { - parseDate(entry); - } - - switch (entry.getEntryType()) { - - case SensorPacket: - decodeSensorPacket(entry); - break; - - case SensorError: - decodeSensorError(entry); - break; - - case SensorDataLow: - decodeDataHighLow(entry, 40); - break; - - case SensorDataHigh: - decodeDataHighLow(entry, 400); - break; - - case SensorTimestamp: - decodeSensorTimestamp(entry); - break; - - case SensorCal: - decodeSensorCal(entry); - break; - - case SensorCalFactor: - decodeSensorCalFactor(entry); - break; - - case SensorSync: - decodeSensorSync(entry); - break; - - case SensorStatus: - decodeSensorStatus(entry); - break; - - case CalBGForGH: - decodeCalBGForGH(entry); - break; - - case GlucoseSensorData: - decodeGlucoseSensorData(entry); - break; - - // just timestamp - case BatteryChange: - case Something10: - case DateTimeChange: - break; - - // just relative timestamp - case Something19: - case DataEnd: - case SensorWeakSignal: - break; - - case None: - break; - - } - - return RecordDecodeStatus.NotSupported; - } - - - @Override - public void postProcess() { - - } - - - public List createRecords(List dataClearInput) { - - List dataClear = reverseList(dataClearInput, Byte.class); - - prepareStatistics(); - - int counter = 0; - - List outList = new ArrayList(); - - // create CGMS entries (without dates) - do { - int opCode = getUnsignedInt(dataClear.get(counter)); - counter++; - - CGMSHistoryEntryType entryType; - - if (opCode == 0) { - // continue; - } else if ((opCode > 0) && (opCode < 20)) { - entryType = CGMSHistoryEntryType.getByCode(opCode); - - if (entryType == CGMSHistoryEntryType.None) { - this.unknownOpCodes.put(opCode, opCode); - LOG.warn("GlucoseHistoryEntry with unknown code: " + opCode); - - CGMSHistoryEntry pe = new CGMSHistoryEntry(); - pe.setEntryType(CGMSHistoryEntryType.None); - pe.setOpCode(opCode); - - pe.setData(Arrays.asList((byte) opCode), false); - - outList.add(pe); - } else { - // System.out.println("OpCode: " + opCode); - - List listRawData = new ArrayList(); - listRawData.add((byte) opCode); - - for (int j = 0; j < (entryType.getTotalLength() - 1); j++) { - listRawData.add(dataClear.get(counter)); - counter++; - } - - CGMSHistoryEntry pe = new CGMSHistoryEntry(); - pe.setEntryType(entryType); - - pe.setOpCode(opCode); - pe.setData(listRawData, false); - - // System.out.println("Record: " + pe); - - outList.add(pe); - } - } else { - CGMSHistoryEntry pe = new CGMSHistoryEntry(); - pe.setEntryType(CGMSHistoryEntryType.GlucoseSensorData); - - pe.setData(Arrays.asList((byte) opCode), false); - - outList.add(pe); - } - - } while (counter < dataClear.size()); - - List reversedOutList = reverseList(outList, CGMSHistoryEntry.class); - - Long timeStamp = null; - LocalDateTime dateTime = null; - int getIndex = 0; - - for (CGMSHistoryEntry entry : reversedOutList) { - - decodeRecord(entry); - - if (entry.hasTimeStamp()) { - timeStamp = entry.atechDateTime; - dateTime = DateTimeUtil.toLocalDateTime(timeStamp); - getIndex = 0; - } else if (entry.getEntryType() == CGMSHistoryEntryType.GlucoseSensorData) { - getIndex++; - if (dateTime != null) - entry.setDateTime(dateTime, getIndex); - } else { - if (dateTime != null) - entry.setDateTime(dateTime, getIndex); - } - - LOG.debug("Record: {}", entry); - } - - return reversedOutList; - - } - - - private List reverseList(List dataClearInput, Class clazz) { - - List outList = new ArrayList(); - - for (int i = dataClearInput.size() - 1; i > 0; i--) { - outList.add(dataClearInput.get(i)); - } - - return outList; - } - - - private int parseMinutes(int one) { - return (one & Integer.parseInt("0111111", 2)); - } - - - private int parseHours(int one) { - return (one & 0x1F); - } - - - private int parseDay(int one) { - return one & 0x1F; - } - - - private int parseMonths(int first_byte, int second_byte) { - - int first_two_bits = first_byte >> 6; - int second_two_bits = second_byte >> 6; - - return (first_two_bits << 2) + second_two_bits; - } - - - private int parseYear(int year) { - return (year & 0x0F) + 2000; - } - - - private Long parseDate(CGMSHistoryEntry entry) { - - if (!entry.getEntryType().hasDate()) - return null; - - byte[] data = entry.getDatetime(); - - if (entry.getEntryType().getDateType() == CGMSHistoryEntryType.DateType.MinuteSpecific) { - - Long atechDateTime = DateTimeUtil.toATechDate(parseYear(data[3]), parseMonths(data[0], data[1]), - parseDay(data[2]), parseHours(data[0]), parseMinutes(data[1]), 0); - - entry.setAtechDateTime(atechDateTime); - - return atechDateTime; - - } else if (entry.getEntryType().getDateType() == CGMSHistoryEntryType.DateType.SecondSpecific) { - LOG.warn("parseDate for SecondSpecific type is not implemented."); - throw new RuntimeException(); - // return null; - } else - return null; - - } - - - private void decodeGlucoseSensorData(CGMSHistoryEntry entry) { - int sgv = entry.getUnsignedRawDataByIndex(0) * 2; - entry.addDecodedData("sgv", sgv); - } - - - private void decodeCalBGForGH(CGMSHistoryEntry entry) { - - int amount = ((entry.getRawDataByIndex(3) & 0b00100000) << 3) | entry.getRawDataByIndex(5); - // - String originType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - case 0x00: - originType = "rf"; - break; - - default: - originType = "unknown"; - - } - - entry.addDecodedData("amount", amount); - entry.addDecodedData("originType", originType); - - } - - - private void decodeSensorSync(CGMSHistoryEntry entry) { - - String syncType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - case 0x01: - syncType = "new"; - break; - - case 0x02: - syncType = "old"; - break; - - default: - syncType = "find"; - break; - - } - - entry.addDecodedData("syncType", syncType); - } - - - private void decodeSensorStatus(CGMSHistoryEntry entry) { - - String statusType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - case 0x00: - statusType = "off"; - break; - - case 0x01: - statusType = "on"; - break; - - case 0x02: - statusType = "lost"; - break; - - default: - statusType = "unknown"; - } - - entry.addDecodedData("statusType", statusType); - - } - - - private void decodeSensorCalFactor(CGMSHistoryEntry entry) { - - double factor = (entry.getRawDataByIndex(5) << 8 | entry.getRawDataByIndex(6)) / 1000.0d; - - entry.addDecodedData("factor", factor); - } - - - private void decodeSensorCal(CGMSHistoryEntry entry) { - - String calibrationType; - - switch (entry.getRawDataByIndex(1)) { - case 0x00: - calibrationType = "meter_bg_now"; - break; - - case 0x01: - calibrationType = "waiting"; - break; - - case 0x02: - calibrationType = "cal_error"; - break; - - default: - calibrationType = "unknown"; - } - - entry.addDecodedData("calibrationType", calibrationType); - - } - - - private void decodeSensorTimestamp(CGMSHistoryEntry entry) { - - String sensorTimestampType; - - switch (entry.getRawDataByIndex(3) >> 5 & 0b00000011) { - - case 0x00: - sensorTimestampType = "LastRf"; - break; - - case 0x01: - sensorTimestampType = "PageEnd"; - break; - - case 0x02: - sensorTimestampType = "Gap"; - break; - - default: - sensorTimestampType = "Unknown"; - break; - - } - - entry.addDecodedData("sensorTimestampType", sensorTimestampType); - } - - - private void decodeSensorPacket(CGMSHistoryEntry entry) { - - String packetType; - - switch (entry.getRawDataByIndex(1)) { - case 0x02: - packetType = "init"; - break; - - default: - packetType = "unknown"; - } - - entry.addDecodedData("packetType", packetType); - } - - - private void decodeSensorError(CGMSHistoryEntry entry) { - - String errorType; - - switch (entry.getRawDataByIndex(1)) { - case 0x01: - errorType = "end"; - break; - - default: - errorType = "unknown"; - } - - entry.addDecodedData("errorType", errorType); - } - - - private void decodeDataHighLow(CGMSHistoryEntry entry, int sgv) { - entry.addDecodedData("sgv", sgv); - } - - - @Override - protected void runPostDecodeTasks() { - this.showStatistics(); - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt new file mode 100644 index 0000000000..d56798dd3a --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/cgms/MedtronicCGMSHistoryDecoder.kt @@ -0,0 +1,269 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms + +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.logging.StacktraceLoggerWrapper.Companion.getLogger +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryDecoder +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms.CGMSHistoryEntryType +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.cgms.CGMSHistoryEntryType.Companion.getByCode +import okhttp3.internal.and +import org.joda.time.LocalDateTime +import org.slf4j.Logger +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +class MedtronicCGMSHistoryDecoder : MedtronicHistoryDecoder() { + + override fun decodeRecord(record: CGMSHistoryEntry): RecordDecodeStatus? { + return try { + decodeRecord(record, false) + } catch (ex: Exception) { + LOG.error(" Error decoding: type={}, ex={}", record.entryType!!.name, ex.message, ex) + RecordDecodeStatus.Error + } + } + + fun decodeRecord(entry: CGMSHistoryEntry, ignore: Boolean): RecordDecodeStatus { + if (entry.dateTimeLength > 0) { + parseDate(entry) + } + when (entry.entryType) { + CGMSHistoryEntryType.SensorPacket -> decodeSensorPacket(entry) + CGMSHistoryEntryType.SensorError -> decodeSensorError(entry) + CGMSHistoryEntryType.SensorDataLow -> decodeDataHighLow(entry, 40) + CGMSHistoryEntryType.SensorDataHigh -> decodeDataHighLow(entry, 400) + CGMSHistoryEntryType.SensorTimestamp -> decodeSensorTimestamp(entry) + CGMSHistoryEntryType.SensorCal -> decodeSensorCal(entry) + CGMSHistoryEntryType.SensorCalFactor -> decodeSensorCalFactor(entry) + CGMSHistoryEntryType.SensorSync -> decodeSensorSync(entry) + CGMSHistoryEntryType.SensorStatus -> decodeSensorStatus(entry) + CGMSHistoryEntryType.CalBGForGH -> decodeCalBGForGH(entry) + CGMSHistoryEntryType.GlucoseSensorData -> decodeGlucoseSensorData(entry) + + CGMSHistoryEntryType.BatteryChange, CGMSHistoryEntryType.Something10, CGMSHistoryEntryType.DateTimeChange -> { + } + + CGMSHistoryEntryType.Something19, CGMSHistoryEntryType.DataEnd, CGMSHistoryEntryType.SensorWeakSignal -> { + } + + CGMSHistoryEntryType.None -> { + } + } + return RecordDecodeStatus.NotSupported + } + + override fun postProcess() {} + override fun createRecords(dataClearInput: List): List { + val dataClear = reverseList(dataClearInput, Byte::class.java) + prepareStatistics() + var counter = 0 + val outList: MutableList = ArrayList() + + // create CGMS entries (without dates) + do { + val opCode = getUnsignedInt(dataClear[counter]) + counter++ + var entryType: CGMSHistoryEntryType? + if (opCode == 0) { + // continue; + } else if (opCode > 0 && opCode < 20) { + entryType = getByCode(opCode) + if (entryType === CGMSHistoryEntryType.None) { + unknownOpCodes!![opCode] = opCode + LOG.warn("GlucoseHistoryEntry with unknown code: $opCode") + val pe = CGMSHistoryEntry() + pe.setEntryType(CGMSHistoryEntryType.None) + pe.opCode = opCode.toByte() + pe.setData(Arrays.asList(opCode.toByte()), false) + outList.add(pe) + } else { + // System.out.println("OpCode: " + opCode); + val listRawData: MutableList = ArrayList() + listRawData.add(opCode.toByte()) + for (j in 0 until entryType!!.totalLength - 1) { + listRawData.add(dataClear[counter]) + counter++ + } + val pe = CGMSHistoryEntry() + pe.setEntryType(entryType) + pe.opCode = opCode.toByte() + pe.setData(listRawData, false) + + // System.out.println("Record: " + pe); + outList.add(pe) + } + } else { + val pe = CGMSHistoryEntry() + pe.setEntryType(CGMSHistoryEntryType.GlucoseSensorData) + pe.setData(Arrays.asList(opCode.toByte()), false) + outList.add(pe) + } + } while (counter < dataClear.size) + val reversedOutList = reverseList(outList, CGMSHistoryEntry::class.java) + var timeStamp: Long? = null + var dateTime: LocalDateTime? = null + var getIndex = 0 + for (entry in reversedOutList) { + decodeRecord(entry) + if (entry.hasTimeStamp()) { + timeStamp = entry.atechDateTime + dateTime = DateTimeUtil.toLocalDateTime(timeStamp!!) + getIndex = 0 + } else if (entry.entryType === CGMSHistoryEntryType.GlucoseSensorData) { + getIndex++ + if (dateTime != null) entry.setDateTime(dateTime, getIndex) + } else { + if (dateTime != null) entry.setDateTime(dateTime, getIndex) + } + LOG.debug("Record: {}", entry) + } + return reversedOutList + } + + private fun reverseList(dataClearInput: List, clazz: Class): List { + val outList: MutableList = ArrayList() + for (i in dataClearInput.size - 1 downTo 1) { + outList.add(dataClearInput[i]) + } + return outList + } + + private fun parseMinutes(one: Int): Int { + return one and "0111111".toInt(2) + } + + private fun parseHours(one: Int): Int { + return one and 0x1F + } + + private fun parseDay(one: Int): Int { + return one and 0x1F + } + + private fun parseMonths(first_byte: Int, second_byte: Int): Int { + val first_two_bits = first_byte shr 6 + val second_two_bits = second_byte shr 6 + return (first_two_bits shl 2) + second_two_bits + } + + private fun parseYear(year: Int): Int { + return (year and 0x0F) + 2000 + } + + private fun parseDate(entry: CGMSHistoryEntry): Long? { + if (!entry.entryType!!.hasDate()) return null + val data = entry.datetime + return if (entry.entryType!!.dateType === CGMSHistoryEntryType.DateType.MinuteSpecific) { + val atechDateTime = DateTimeUtil.toATechDate(parseYear(data!![3].toInt()), parseMonths(data[0].toInt(), data[1].toInt()), + parseDay(data[2].toInt()), parseHours(data[0].toInt()), parseMinutes(data[1].toInt()), 0) + entry.setAtechDateTime(atechDateTime) + atechDateTime + } else if (entry.entryType!!.dateType === CGMSHistoryEntryType.DateType.SecondSpecific) { + LOG.warn("parseDate for SecondSpecific type is not implemented.") + throw RuntimeException() + // return null; + } else null + } + + private fun decodeGlucoseSensorData(entry: CGMSHistoryEntry) { + val sgv = entry.getUnsignedRawDataByIndex(0) * 2 + entry.addDecodedData("sgv", sgv) + } + + private fun decodeCalBGForGH(entry: CGMSHistoryEntry) { + val amount: Int = entry.getRawDataByIndex(3) and 32 shl 3 or entry.getRawDataByIndexInt(5) + // + val originType: String + originType = when (entry.getRawDataByIndexInt(3) shr 5 and 3) { + 0x00 -> "rf" + else -> "unknown" + } + entry.addDecodedData("amount", amount) + entry.addDecodedData("originType", originType) + } + + private fun decodeSensorSync(entry: CGMSHistoryEntry) { + val syncType: String + syncType = when (entry.getRawDataByIndexInt(3) shr 5 and 3) { + 0x01 -> "new" + 0x02 -> "old" + else -> "find" + } + entry.addDecodedData("syncType", syncType) + } + + private fun decodeSensorStatus(entry: CGMSHistoryEntry) { + val statusType: String + statusType = when (entry.getRawDataByIndexInt(3) shr 5 and 3) { + 0x00 -> "off" + 0x01 -> "on" + 0x02 -> "lost" + else -> "unknown" + } + entry.addDecodedData("statusType", statusType) + } + + private fun decodeSensorCalFactor(entry: CGMSHistoryEntry) { + val factor: Double = (entry.getRawDataByIndexInt(5) shl 8 or entry.getRawDataByIndexInt(6)) / 1000.0 + entry.addDecodedData("factor", factor) + } + + private fun decodeSensorCal(entry: CGMSHistoryEntry) { + val calibrationType: String + calibrationType = when (entry.getRawDataByIndexInt(1)) { + 0x00 -> "meter_bg_now" + 0x01 -> "waiting" + 0x02 -> "cal_error" + else -> "unknown" + } + entry.addDecodedData("calibrationType", calibrationType) + } + + private fun decodeSensorTimestamp(entry: CGMSHistoryEntry) { + val sensorTimestampType: String + sensorTimestampType = when (entry.getRawDataByIndex(3).toInt() shr 5 and 3) { + 0x00 -> "LastRf" + 0x01 -> "PageEnd" + 0x02 -> "Gap" + else -> "Unknown" + } + entry.addDecodedData("sensorTimestampType", sensorTimestampType) + } + + private fun decodeSensorPacket(entry: CGMSHistoryEntry) { + val packetType: String + packetType = when (entry.getRawDataByIndex(1)) { + 0x02.toByte() -> "init" + else -> "unknown" + } + entry.addDecodedData("packetType", packetType) + } + + private fun decodeSensorError(entry: CGMSHistoryEntry) { + val errorType: String + errorType = when (entry.getRawDataByIndexInt(1)) { + 0x01 -> "end" + else -> "unknown" + } + entry.addDecodedData("errorType", errorType) + } + + private fun decodeDataHighLow(entry: CGMSHistoryEntry, sgv: Int) { + entry.addDecodedData("sgv", sgv) + } + + override fun runPostDecodeTasks() { + showStatistics() + } + + companion object { + private val LOG: Logger = getLogger(LTag.PUMPCOMM) + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java deleted file mode 100644 index b8d57edb7c..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.java +++ /dev/null @@ -1,724 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import javax.inject.Inject; -import javax.inject.Singleton; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -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.comm.history.MedtronicHistoryDecoder; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusWizardDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.DailyTotalsDTO; -import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpBolusType; -import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -@Singleton -public class MedtronicPumpHistoryDecoder extends MedtronicHistoryDecoder { - - private PumpHistoryEntry tbrPreviousRecord; - private PumpHistoryEntry changeTimeRecord; - - @Inject - public MedtronicPumpHistoryDecoder( - AAPSLogger aapsLogger, - MedtronicUtil medtronicUtil - ) { - super.aapsLogger = aapsLogger; - this.medtronicUtil = medtronicUtil; - } - - - public List createRecords(List dataClear) { - prepareStatistics(); - - int counter = 0; - int record = 0; - boolean incompletePacket; - - List outList = new ArrayList<>(); - String skipped = null; - - if (dataClear.size() == 0) { - aapsLogger.error(LTag.PUMPBTCOMM, "Empty page."); - return outList; - } - - do { - int opCode = dataClear.get(counter); - boolean special = false; - incompletePacket = false; - boolean skippedRecords = false; - - if (opCode == 0) { - counter++; - if (skipped == null) - skipped = "0x00"; - else - skipped += " 0x00"; - continue; - } else { - if (skipped != null) { - aapsLogger.warn(LTag.PUMPBTCOMM, " ... Skipped " + skipped); - skipped = null; - skippedRecords = true; - } - } - - if (skippedRecords) { - aapsLogger.error(LTag.PUMPBTCOMM, "We had some skipped bytes, which might indicate error in pump history. Please report this problem."); - } - - PumpHistoryEntryType entryType = PumpHistoryEntryType.getByCode(opCode); - - PumpHistoryEntry pe = new PumpHistoryEntry(); - pe.setEntryType(medtronicUtil.getMedtronicPumpModel(), entryType); - pe.setOffset(counter); - - counter++; - - if (counter >= 1022) { - break; - } - - List listRawData = new ArrayList<>(); - listRawData.add((byte) opCode); - - if (entryType == PumpHistoryEntryType.UnabsorbedInsulin - || entryType == PumpHistoryEntryType.UnabsorbedInsulin512) { - int elements = dataClear.get(counter); - listRawData.add((byte) elements); - counter++; - - int els = getUnsignedInt(elements); - - for (int k = 0; k < (els - 2); k++) { - if (counter < 1022) { - listRawData.add(dataClear.get(counter)); - counter++; - } - } - - special = true; - } else { - - for (int j = 0; j < (entryType.getTotalLength(medtronicUtil.getMedtronicPumpModel()) - 1); j++) { - - try { - listRawData.add(dataClear.get(counter)); - counter++; - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPBTCOMM, "OpCode: " + ByteUtil.shortHexString((byte) opCode) + ", Invalid package: " - + ByteUtil.getHex(listRawData)); - // throw ex; - incompletePacket = true; - break; - } - - } - - if (incompletePacket) - break; - - } - - if (entryType == PumpHistoryEntryType.None) { - aapsLogger.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch."); - } else { - - if (pe.getEntryType() == PumpHistoryEntryType.UnknownBasePacket) { - pe.setOpCode(opCode); - } - - if (entryType.getHeadLength(medtronicUtil.getMedtronicPumpModel()) == 0) - special = true; - - pe.setData(listRawData, special); - - RecordDecodeStatus decoded = decodeRecord(pe); - - if ((decoded == RecordDecodeStatus.OK) || (decoded == RecordDecodeStatus.Ignored)) { - //Log.i(TAG, "#" + record + " " + decoded.getDescription() + " " + pe); - } else { - aapsLogger.warn(LTag.PUMPBTCOMM, "#" + record + " " + decoded.getDescription() + " " + pe); - } - - addToStatistics(pe, decoded, null); - - record++; - - if (decoded == RecordDecodeStatus.OK) // we add only OK records, all others are ignored - { - outList.add(pe); - } - } - - } while (counter < dataClear.size()); - - return outList; - } - - - public RecordDecodeStatus decodeRecord(PumpHistoryEntry record) { - try { - return decodeRecord(record, false); - } catch (Exception ex) { - aapsLogger.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.getEntryType().name(), ex.getMessage(), ex)); - return RecordDecodeStatus.Error; - } - } - - - private RecordDecodeStatus decodeRecord(PumpHistoryEntry entry, boolean x) { - - if (entry.getDateTimeLength() > 0) { - decodeDateTime(entry); - } - - switch (entry.getEntryType()) { - - // Valid entries, but not processed - case ChangeBasalPattern: - case CalBGForPH: - case ChangeRemoteId: - case ClearAlarm: - case ChangeAlarmNotifyMode: // ChangeUtility: - case EnableDisableRemote: - case BGReceived: // Ian3F: CGMS - case SensorAlert: // Ian08 CGMS - case ChangeTimeFormat: - case ChangeReservoirWarningTime: - case ChangeBolusReminderEnable: - case SetBolusReminderTime: - case ChangeChildBlockEnable: - case BolusWizardEnabled: - case ChangeBGReminderOffset: - case ChangeAlarmClockTime: - case ChangeMeterId: - case ChangeParadigmID: - case JournalEntryMealMarker: - case JournalEntryExerciseMarker: - case DeleteBolusReminderTime: - case SetAutoOff: - case SelfTest: - case JournalEntryInsulinMarker: - case JournalEntryOtherMarker: - case BolusWizardSetup512: - case ChangeSensorSetup2: - case ChangeSensorAlarmSilenceConfig: - case ChangeSensorRateOfChangeAlertSetup: - case ChangeBolusScrollStepSize: - case BolusWizardSetup: - case ChangeVariableBolus: - case ChangeAudioBolus: - case ChangeBGReminderEnable: - case ChangeAlarmClockEnable: - case BolusReminder: - case DeleteAlarmClockTime: - case ChangeCarbUnits: - case ChangeWatchdogEnable: - case ChangeOtherDeviceID: - case ReadOtherDevicesIDs: - case BGReceived512: - case SensorStatus: - case ReadCaptureEventEnabled: - case ChangeCaptureEventEnable: - case ReadOtherDevicesStatus: - return RecordDecodeStatus.OK; - - case Sensor_0x54: - case Sensor_0x55: - case Sensor_0x51: - case Sensor_0x52: -// case EventUnknown_MM522_0x45: -// case EventUnknown_MM522_0x46: -// case EventUnknown_MM522_0x47: -// case EventUnknown_MM522_0x48: -// case EventUnknown_MM522_0x49: -// case EventUnknown_MM522_0x4a: -// case EventUnknown_MM522_0x4b: -// case EventUnknown_MM522_0x4c: -// case EventUnknown_MM512_0x10: - case EventUnknown_MM512_0x2e: -// case EventUnknown_MM512_0x37: -// case EventUnknown_MM512_0x38: -// case EventUnknown_MM512_0x4e: -// case EventUnknown_MM522_0x70: -// case EventUnknown_MM512_0x88: -// case EventUnknown_MM512_0x94: -// case EventUnknown_MM522_0xE8: -// case EventUnknown_0x4d: -// case EventUnknown_MM522_0x25: -// case EventUnknown_MM522_0x05: - aapsLogger.debug(LTag.PUMPBTCOMM, " -- ignored Unknown Pump Entry: " + entry); - return RecordDecodeStatus.Ignored; - - case UnabsorbedInsulin: - case UnabsorbedInsulin512: - return RecordDecodeStatus.Ignored; - - // **** Implemented records **** - - case DailyTotals522: - case DailyTotals523: - case DailyTotals515: - case EndResultTotals: - return decodeDailyTotals(entry); - - case ChangeBasalProfile_OldProfile: - case ChangeBasalProfile_NewProfile: - return decodeBasalProfile(entry); - - case BasalProfileStart: - return decodeBasalProfileStart(entry); - - case ChangeTime: - changeTimeRecord = entry; - return RecordDecodeStatus.OK; - - case NewTimeSet: - decodeChangeTime(entry); - return RecordDecodeStatus.OK; - - case TempBasalDuration: - // decodeTempBasal(entry); - return RecordDecodeStatus.OK; - - case TempBasalRate: - // decodeTempBasal(entry); - return RecordDecodeStatus.OK; - - case Bolus: - decodeBolus(entry); - return RecordDecodeStatus.OK; - - case BatteryChange: - decodeBatteryActivity(entry); - return RecordDecodeStatus.OK; - - case LowReservoir: - decodeLowReservoir(entry); - return RecordDecodeStatus.OK; - - case LowBattery: - case SuspendPump: - case ResumePump: - case Rewind: - case NoDeliveryAlarm: - case ChangeTempBasalType: - case ChangeMaxBolus: - case ChangeMaxBasal: - case ClearSettings: - case SaveSettings: - return RecordDecodeStatus.OK; - - case BolusWizard: - return decodeBolusWizard(entry); - - case BolusWizard512: - return decodeBolusWizard512(entry); - - case Prime: - decodePrime(entry); - return RecordDecodeStatus.OK; - - case TempBasalCombined: - return RecordDecodeStatus.Ignored; - - case None: - case UnknownBasePacket: - return RecordDecodeStatus.Error; - - default: { - aapsLogger.debug(LTag.PUMPBTCOMM, "Not supported: " + entry.getEntryType()); - return RecordDecodeStatus.NotSupported; - } - - } - - // return RecordDecodeStatus.Error; - - } - - - private RecordDecodeStatus decodeDailyTotals(PumpHistoryEntry entry) { - - entry.addDecodedData("Raw Data", ByteUtil.getHex(entry.getRawData())); - - DailyTotalsDTO totals = new DailyTotalsDTO(entry); - - entry.addDecodedData("Object", totals); - - return RecordDecodeStatus.OK; - } - - - private RecordDecodeStatus decodeBasalProfile(PumpHistoryEntry entry) { - - // LOG.debug("decodeBasalProfile: {}", entry); - - BasalProfile basalProfile = new BasalProfile(aapsLogger); - basalProfile.setRawDataFromHistory(entry.getBody()); - - // LOG.debug("decodeBasalProfile BasalProfile: {}", basalProfile); - - entry.addDecodedData("Object", basalProfile); - - return RecordDecodeStatus.OK; - } - - - private void decodeChangeTime(PumpHistoryEntry entry) { - if (changeTimeRecord == null) - return; - - entry.setDisplayableValue(entry.getDateTimeString()); - - this.changeTimeRecord = null; - } - - - private void decodeBatteryActivity(PumpHistoryEntry entry) { - // this.writeData(PumpBaseType.Event, entry.getHead()[0] == 0 ? PumpEventType.BatteryRemoved : - // PumpEventType.BatteryReplaced, entry.getATechDate()); - - entry.setDisplayableValue(entry.getHead()[0] == 0 ? "Battery Removed" : "Battery Replaced"); - } - - - private static String getFormattedValue(float value, int decimals) { - return String.format(Locale.ENGLISH, "%." + decimals + "f", value); - } - - - private RecordDecodeStatus decodeBasalProfileStart(PumpHistoryEntry entry) { - byte[] body = entry.getBody(); - // int bodyOffset = headerSize + timestampSize; - int offset = body[0] * 1000 * 30 * 60; - Float rate = null; - int index = entry.getHead()[0]; - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - rate = body[1] * 0.025f; - } - - //LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index, body); - - if (rate == null) { - aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Basal Profile Start (ERROR): offset=%d, rate=%.3f, index=%d, body_raw=%s", offset, rate, index, ByteUtil.getHex(body))); - return RecordDecodeStatus.Error; - } else { - entry.addDecodedData("Value", getFormattedFloat(rate, 3)); - entry.setDisplayableValue(getFormattedFloat(rate, 3)); - return RecordDecodeStatus.OK; - } - - } - - - private RecordDecodeStatus decodeBolusWizard(PumpHistoryEntry entry) { - byte[] body = entry.getBody(); - - BolusWizardDTO dto = new BolusWizardDTO(); - - float bolusStrokes = 10.0f; - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 - bolusStrokes = 40.0f; - - dto.carbs = ((body[1] & 0x0c) << 6) + body[0]; - - dto.bloodGlucose = ((body[1] & 0x03) << 8) + entry.getHead()[0]; - dto.carbRatio = body[1] / 10.0f; - // carb_ratio (?) = (((self.body[2] & 0x07) << 8) + self.body[3]) / - // 10.0s - dto.insulinSensitivity = new Float(body[4]); - dto.bgTargetLow = (int) body[5]; - dto.bgTargetHigh = (int) body[14]; - dto.correctionEstimate = (((body[9] & 0x38) << 5) + body[6]) / bolusStrokes; - dto.foodEstimate = ((body[7] << 8) + body[8]) / bolusStrokes; - dto.unabsorbedInsulin = ((body[10] << 8) + body[11]) / bolusStrokes; - dto.bolusTotal = ((body[12] << 8) + body[13]) / bolusStrokes; - } else { - dto.bloodGlucose = (((body[1] & 0x0F) << 8) | entry.getHead()[0]); - dto.carbs = (int) body[0]; - dto.carbRatio = Float.valueOf(body[2]); - dto.insulinSensitivity = new Float(body[3]); - dto.bgTargetLow = (int) body[4]; - dto.bgTargetHigh = (int) body[12]; - dto.bolusTotal = body[11] / bolusStrokes; - dto.foodEstimate = body[6] / bolusStrokes; - dto.unabsorbedInsulin = body[9] / bolusStrokes; - dto.bolusTotal = body[11] / bolusStrokes; - dto.correctionEstimate = (body[7] + (body[5] & 0x0F)) / bolusStrokes; - } - - if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { - dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.byteValue()); - } - - dto.atechDateTime = entry.atechDateTime; - entry.addDecodedData("Object", dto); - entry.setDisplayableValue(dto.getDisplayableValue()); - - return RecordDecodeStatus.OK; - } - - - private RecordDecodeStatus decodeBolusWizard512(PumpHistoryEntry entry) { - byte[] body = entry.getBody(); - - BolusWizardDTO dto = new BolusWizardDTO(); - - float bolusStrokes = 10.0f; - - dto.bloodGlucose = ((body[1] & 0x03 << 8) | entry.getHead()[0]); - dto.carbs = (body[1] & 0xC) << 6 | body[0]; // (int)body[0]; - dto.carbRatio = Float.valueOf(body[2]); - dto.insulinSensitivity = new Float(body[3]); - dto.bgTargetLow = (int) body[4]; - dto.foodEstimate = body[6] / 10.0f; - dto.correctionEstimate = (body[7] + (body[5] & 0x0F)) / bolusStrokes; - dto.unabsorbedInsulin = body[9] / bolusStrokes; - dto.bolusTotal = body[11] / bolusStrokes; - dto.bgTargetHigh = dto.bgTargetLow; - - if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { - dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.byteValue()); - } - - dto.atechDateTime = entry.atechDateTime; - entry.addDecodedData("Object", dto); - entry.setDisplayableValue(dto.getDisplayableValue()); - - return RecordDecodeStatus.OK; - } - - - private void decodeLowReservoir(PumpHistoryEntry entry) { - float amount = (getUnsignedInt(entry.getHead()[0]) * 1.0f / 10.0f) * 2; - - entry.setDisplayableValue(getFormattedValue(amount, 1)); - } - - - private void decodePrime(PumpHistoryEntry entry) { - float amount = ByteUtil.toInt(entry.getHead()[2], entry.getHead()[3]) / 10.0f; - float fixed = ByteUtil.toInt(entry.getHead()[0], entry.getHead()[1]) / 10.0f; - -// amount = (double)(asUINT8(data[4]) << 2) / 40.0; -// programmedAmount = (double)(asUINT8(data[2]) << 2) / 40.0; -// primeType = programmedAmount == 0 ? "manual" : "fixed"; - - entry.addDecodedData("Amount", amount); - entry.addDecodedData("FixedAmount", fixed); - - entry.setDisplayableValue("Amount=" + getFormattedValue(amount, 2) + ", Fixed Amount=" - + getFormattedValue(fixed, 2)); - } - - - private void decodeChangeTempBasalType(PumpHistoryEntry entry) { - entry.addDecodedData("isPercent", ByteUtil.asUINT8(entry.getRawDataByIndex(0)) == 1); // index moved from 1 -> 0 - } - - - private void decodeBgReceived(PumpHistoryEntry entry) { - entry.addDecodedData("amount", (ByteUtil.asUINT8(entry.getRawDataByIndex(0)) << 3) + (ByteUtil.asUINT8(entry.getRawDataByIndex(3)) >> 5)); - entry.addDecodedData("meter", ByteUtil.substring(entry.getRawData(), 6, 3)); // index moved from 1 -> 0 - } - - - private void decodeCalBGForPH(PumpHistoryEntry entry) { - entry.addDecodedData("amount", ((ByteUtil.asUINT8(entry.getRawDataByIndex(5)) & 0x80) << 1) + ByteUtil.asUINT8(entry.getRawDataByIndex(0))); // index moved from 1 -> 0 - } - - - private void decodeNoDeliveryAlarm(PumpHistoryEntry entry) { - //rawtype = asUINT8(data[1]); - // not sure if this is actually NoDelivery Alarm? - } - - - @Override - public void postProcess() { - } - - - @Override - protected void runPostDecodeTasks() { - this.showStatistics(); - } - - - private void decodeBolus(PumpHistoryEntry entry) { - BolusDTO bolus = new BolusDTO(); - - byte[] data = entry.getHead(); - - if (MedtronicDeviceType.isSameDevice(medtronicUtil.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { - bolus.setRequestedAmount(ByteUtil.toInt(data[0], data[1]) / 40.0d); - bolus.setDeliveredAmount(ByteUtil.toInt(data[2], data[3]) / 40.0d); - bolus.setInsulinOnBoard(ByteUtil.toInt(data[4], data[5]) / 40.0d); - bolus.setDuration(data[6] * 30); - } else { - bolus.setRequestedAmount(ByteUtil.asUINT8(data[0]) / 10.0d); - bolus.setDeliveredAmount(ByteUtil.asUINT8(data[1]) / 10.0d); - bolus.setDuration(ByteUtil.asUINT8(data[2]) * 30); - } - - bolus.setBolusType((bolus.getDuration() != null && (bolus.getDuration() > 0)) ? PumpBolusType.Extended - : PumpBolusType.Normal); - bolus.setAtechDateTime(entry.atechDateTime); - - entry.addDecodedData("Object", bolus); - entry.setDisplayableValue(bolus.getDisplayableValue()); - - } - - - private void decodeTempBasal(PumpHistoryEntry entry) { - - if (this.tbrPreviousRecord == null) { - // LOG.debug(this.tbrPreviousRecord.toString()); - this.tbrPreviousRecord = entry; - return; - } - - decodeTempBasal(this.tbrPreviousRecord, entry); - - tbrPreviousRecord = null; - } - - - public void decodeTempBasal(PumpHistoryEntry tbrPreviousRecord, PumpHistoryEntry entry) { - - PumpHistoryEntry tbrRate = null, tbrDuration = null; - - if (entry.getEntryType() == PumpHistoryEntryType.TempBasalRate) { - tbrRate = entry; - } else { - tbrDuration = entry; - } - - if (tbrRate != null) { - tbrDuration = tbrPreviousRecord; - } else { - tbrRate = tbrPreviousRecord; - } - -// TempBasalPair tbr = new TempBasalPair( -// tbrRate.getHead()[0], -// tbrDuration.getHead()[0], -// (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); - - TempBasalPair tbr = new TempBasalPair( - tbrRate.getHead()[0], - tbrRate.getBody()[0], - tbrDuration.getHead()[0], - (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); - - // System.out.println("TBR: amount=" + tbr.getInsulinRate() + ", duration=" + tbr.getDurationMinutes() - // // + " min. Packed: " + tbr.getValue() - // ); - - entry.addDecodedData("Object", tbr); - entry.setDisplayableValue(tbr.getDescription()); - - } - - - private void decodeDateTime(PumpHistoryEntry entry) { - byte[] dt = entry.getDatetime(); - - if (dt == null) { - aapsLogger.warn(LTag.PUMPBTCOMM, "DateTime not set."); - } - - if (entry.getDateTimeLength() == 5) { - - int seconds = dt[0] & 0x3F; - int minutes = dt[1] & 0x3F; - int hour = dt[2] & 0x1F; - - int month = ((dt[0] >> 4) & 0x0c) + ((dt[1] >> 6) & 0x03); - // ((dt[0] & 0xC0) >> 6) | ((dt[1] & 0xC0) >> 4); - - int dayOfMonth = dt[3] & 0x1F; - int year = fix2DigitYear(dt[4] & 0x3F); // Assuming this is correct, need to verify. Otherwise this will be - // a problem in 2016. - - entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)); - - } else if (entry.getDateTimeLength() == 2) { - int low = ByteUtil.asUINT8(dt[0]) & 0x1F; - int mhigh = (ByteUtil.asUINT8(dt[0]) & 0xE0) >> 4; - int mlow = (ByteUtil.asUINT8(dt[1]) & 0x80) >> 7; - int month = mhigh + mlow; - // int dayOfMonth = low + 1; - int dayOfMonth = dt[0] & 0x1F; - int year = 2000 + (ByteUtil.asUINT8(dt[1]) & 0x7F); - - int hour = 0; - int minutes = 0; - int seconds = 0; - - //LOG.debug("DT: {} {} {}", year, month, dayOfMonth); - - if (dayOfMonth == 32) { - aapsLogger.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Entry: Day 32 %s = [%s] %s", entry.getEntryType().name(), - ByteUtil.getHex(entry.getRawData()), entry)); - } - - if (isEndResults(entry.getEntryType())) { - hour = 23; - minutes = 59; - seconds = 59; - } - - entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)); - - } else { - aapsLogger.warn(LTag.PUMPBTCOMM, "Unknown datetime format: " + entry.getDateTimeLength()); - } - - } - - - private boolean isEndResults(PumpHistoryEntryType entryType) { - - return (entryType == PumpHistoryEntryType.EndResultTotals || - entryType == PumpHistoryEntryType.DailyTotals515 || - entryType == PumpHistoryEntryType.DailyTotals522 || - entryType == PumpHistoryEntryType.DailyTotals523); - } - - - private int fix2DigitYear(int year) { - if (year > 90) { - year += 1900; - } else { - year += 2000; - } - - return year; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt new file mode 100644 index 0000000000..e0613567d8 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/MedtronicPumpHistoryDecoder.kt @@ -0,0 +1,502 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +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.comm.history.MedtronicHistoryDecoder +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.RecordDecodeStatus +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump.PumpHistoryEntryType.Companion.getByCode +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BasalProfile +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.BolusWizardDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.DailyTotalsDTO +import info.nightscout.androidaps.plugins.pump.medtronic.data.dto.TempBasalPair +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import info.nightscout.androidaps.plugins.pump.medtronic.defs.PumpBolusType +import info.nightscout.androidaps.plugins.pump.medtronic.util.MedtronicUtil +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +@Singleton +class MedtronicPumpHistoryDecoder @Inject constructor( + aapsLogger: AAPSLogger?, + medtronicUtil: MedtronicUtil? +) : MedtronicHistoryDecoder() { + + private var tbrPreviousRecord: PumpHistoryEntry? = null + private var changeTimeRecord: PumpHistoryEntry? = null + override fun createRecords(dataClear: List): List { + prepareStatistics() + var counter = 0 + var record = 0 + var incompletePacket: Boolean + val outList: MutableList = ArrayList() + var skipped: String? = null + if (dataClear!!.size == 0) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "Empty page.") + return outList + } + do { + val opCode: Int = dataClear[counter]!!.toInt() + var special = false + incompletePacket = false + var skippedRecords = false + if (opCode == 0) { + counter++ + if (skipped == null) skipped = "0x00" else skipped += " 0x00" + continue + } else { + if (skipped != null) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, " ... Skipped $skipped") + skipped = null + skippedRecords = true + } + } + if (skippedRecords) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "We had some skipped bytes, which might indicate error in pump history. Please report this problem.") + } + val entryType = getByCode(opCode.toByte()) + val pe = PumpHistoryEntry() + pe.setEntryType(medtronicUtil!!.medtronicPumpModel, entryType!!) + pe.offset = counter + counter++ + if (counter >= 1022) { + break + } + val listRawData: MutableList = ArrayList() + listRawData.add(opCode.toByte()) + if (entryType === PumpHistoryEntryType.UnabsorbedInsulin + || entryType === PumpHistoryEntryType.UnabsorbedInsulin512) { + val elements: Int = dataClear[counter]!!.toInt() + listRawData.add(elements.toByte()) + counter++ + val els = getUnsignedInt(elements) + for (k in 0 until els - 2) { + if (counter < 1022) { + listRawData.add(dataClear[counter]) + counter++ + } + } + special = true + } else { + for (j in 0 until entryType.getTotalLength(medtronicUtil!!.medtronicPumpModel) - 1) { + try { + listRawData.add(dataClear[counter]) + counter++ + } catch (ex: Exception) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "OpCode: " + ByteUtil.shortHexString(opCode.toByte()) + ", Invalid package: " + + ByteUtil.getHex(listRawData)) + // throw ex; + incompletePacket = true + break + } + } + if (incompletePacket) break + } + if (entryType === PumpHistoryEntryType.None) { + aapsLogger!!.error(LTag.PUMPBTCOMM, "Error in code. We should have not come into this branch.") + } else { + if (pe.entryType === PumpHistoryEntryType.UnknownBasePacket) { + pe.opCode = opCode.toByte() + } + if (entryType.getHeadLength(medtronicUtil!!.medtronicPumpModel) == 0) special = true + pe.setData(listRawData as List, special) + val decoded = decodeRecord(pe) + if (decoded === RecordDecodeStatus.OK || decoded === RecordDecodeStatus.Ignored) { + //Log.i(TAG, "#" + record + " " + decoded.getDescription() + " " + pe); + } else { + aapsLogger!!.warn(LTag.PUMPBTCOMM, "#" + record + " " + decoded!!.description + " " + pe) + } + addToStatistics(pe, decoded, null) + record++ + if (decoded === RecordDecodeStatus.OK) // we add only OK records, all others are ignored + { + outList.add(pe) + } + } + } while (counter < dataClear.size) + return outList + } + + override fun decodeRecord(record: PumpHistoryEntry): RecordDecodeStatus? { + return try { + decodeRecord(record, false) + } catch (ex: Exception) { + aapsLogger!!.error(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, " Error decoding: type=%s, ex=%s", record.entryType!!.name, ex.message, ex)) + RecordDecodeStatus.Error + } + } + + private fun decodeRecord(entry: PumpHistoryEntry, x: Boolean): RecordDecodeStatus { + if (entry.dateTimeLength > 0) { + decodeDateTime(entry) + } + return when (entry.entryType) { + PumpHistoryEntryType.ChangeBasalPattern, PumpHistoryEntryType.CalBGForPH, PumpHistoryEntryType.ChangeRemoteId, PumpHistoryEntryType.ClearAlarm, PumpHistoryEntryType.ChangeAlarmNotifyMode, PumpHistoryEntryType.EnableDisableRemote, PumpHistoryEntryType.BGReceived, PumpHistoryEntryType.SensorAlert, PumpHistoryEntryType.ChangeTimeFormat, PumpHistoryEntryType.ChangeReservoirWarningTime, PumpHistoryEntryType.ChangeBolusReminderEnable, PumpHistoryEntryType.SetBolusReminderTime, PumpHistoryEntryType.ChangeChildBlockEnable, PumpHistoryEntryType.BolusWizardEnabled, PumpHistoryEntryType.ChangeBGReminderOffset, PumpHistoryEntryType.ChangeAlarmClockTime, PumpHistoryEntryType.ChangeMeterId, PumpHistoryEntryType.ChangeParadigmID, PumpHistoryEntryType.JournalEntryMealMarker, PumpHistoryEntryType.JournalEntryExerciseMarker, PumpHistoryEntryType.DeleteBolusReminderTime, PumpHistoryEntryType.SetAutoOff, PumpHistoryEntryType.SelfTest, PumpHistoryEntryType.JournalEntryInsulinMarker, PumpHistoryEntryType.JournalEntryOtherMarker, PumpHistoryEntryType.BolusWizardSetup512, PumpHistoryEntryType.ChangeSensorSetup2, PumpHistoryEntryType.ChangeSensorAlarmSilenceConfig, PumpHistoryEntryType.ChangeSensorRateOfChangeAlertSetup, PumpHistoryEntryType.ChangeBolusScrollStepSize, PumpHistoryEntryType.BolusWizardSetup, PumpHistoryEntryType.ChangeVariableBolus, PumpHistoryEntryType.ChangeAudioBolus, PumpHistoryEntryType.ChangeBGReminderEnable, PumpHistoryEntryType.ChangeAlarmClockEnable, PumpHistoryEntryType.BolusReminder, PumpHistoryEntryType.DeleteAlarmClockTime, PumpHistoryEntryType.ChangeCarbUnits, PumpHistoryEntryType.ChangeWatchdogEnable, PumpHistoryEntryType.ChangeOtherDeviceID, PumpHistoryEntryType.ReadOtherDevicesIDs, PumpHistoryEntryType.BGReceived512, PumpHistoryEntryType.SensorStatus, PumpHistoryEntryType.ReadCaptureEventEnabled, PumpHistoryEntryType.ChangeCaptureEventEnable, PumpHistoryEntryType.ReadOtherDevicesStatus -> RecordDecodeStatus.OK + + PumpHistoryEntryType.Sensor_0x54, PumpHistoryEntryType.Sensor_0x55, PumpHistoryEntryType.Sensor_0x51, PumpHistoryEntryType.Sensor_0x52, PumpHistoryEntryType.EventUnknown_MM512_0x2e -> { + // case EventUnknown_MM512_0x37: +// case EventUnknown_MM512_0x38: +// case EventUnknown_MM512_0x4e: +// case EventUnknown_MM522_0x70: +// case EventUnknown_MM512_0x88: +// case EventUnknown_MM512_0x94: +// case EventUnknown_MM522_0xE8: +// case EventUnknown_0x4d: +// case EventUnknown_MM522_0x25: +// case EventUnknown_MM522_0x05: + aapsLogger!!.debug(LTag.PUMPBTCOMM, " -- ignored Unknown Pump Entry: $entry") + RecordDecodeStatus.Ignored + } + + PumpHistoryEntryType.UnabsorbedInsulin, PumpHistoryEntryType.UnabsorbedInsulin512 -> RecordDecodeStatus.Ignored + PumpHistoryEntryType.DailyTotals522, PumpHistoryEntryType.DailyTotals523, PumpHistoryEntryType.DailyTotals515, PumpHistoryEntryType.EndResultTotals -> decodeDailyTotals(entry) + PumpHistoryEntryType.ChangeBasalProfile_OldProfile, PumpHistoryEntryType.ChangeBasalProfile_NewProfile -> decodeBasalProfile(entry) + PumpHistoryEntryType.BasalProfileStart -> decodeBasalProfileStart(entry) + + PumpHistoryEntryType.ChangeTime -> { + changeTimeRecord = entry + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.NewTimeSet -> { + decodeChangeTime(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.TempBasalDuration -> // decodeTempBasal(entry); + RecordDecodeStatus.OK + PumpHistoryEntryType.TempBasalRate -> // decodeTempBasal(entry); + RecordDecodeStatus.OK + + PumpHistoryEntryType.Bolus -> { + decodeBolus(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.BatteryChange -> { + decodeBatteryActivity(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.LowReservoir -> { + decodeLowReservoir(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.LowBattery, PumpHistoryEntryType.SuspendPump, PumpHistoryEntryType.ResumePump, PumpHistoryEntryType.Rewind, PumpHistoryEntryType.NoDeliveryAlarm, PumpHistoryEntryType.ChangeTempBasalType, PumpHistoryEntryType.ChangeMaxBolus, PumpHistoryEntryType.ChangeMaxBasal, PumpHistoryEntryType.ClearSettings, PumpHistoryEntryType.SaveSettings -> RecordDecodeStatus.OK + PumpHistoryEntryType.BolusWizard -> decodeBolusWizard(entry) + PumpHistoryEntryType.BolusWizard512 -> decodeBolusWizard512(entry) + + PumpHistoryEntryType.Prime -> { + decodePrime(entry) + RecordDecodeStatus.OK + } + + PumpHistoryEntryType.TempBasalCombined -> RecordDecodeStatus.Ignored + PumpHistoryEntryType.None, PumpHistoryEntryType.UnknownBasePacket -> RecordDecodeStatus.Error + + else -> { + aapsLogger!!.debug(LTag.PUMPBTCOMM, "Not supported: " + entry.entryType) + RecordDecodeStatus.NotSupported + } + } + + // return RecordDecodeStatus.Error; + } + + private fun decodeDailyTotals(entry: PumpHistoryEntry): RecordDecodeStatus { + entry.addDecodedData("Raw Data", ByteUtil.getHex(entry.rawData)) + val totals = DailyTotalsDTO(entry) + entry.addDecodedData("Object", totals) + return RecordDecodeStatus.OK + } + + private fun decodeBasalProfile(entry: PumpHistoryEntry): RecordDecodeStatus { + + // LOG.debug("decodeBasalProfile: {}", entry); + val basalProfile = BasalProfile(aapsLogger) + basalProfile.setRawDataFromHistory(entry.body) + + // LOG.debug("decodeBasalProfile BasalProfile: {}", basalProfile); + entry.addDecodedData("Object", basalProfile) + return RecordDecodeStatus.OK + } + + private fun decodeChangeTime(entry: PumpHistoryEntry) { + if (changeTimeRecord == null) return + entry.displayableValue = entry.dateTimeString + changeTimeRecord = null + } + + private fun decodeBatteryActivity(entry: PumpHistoryEntry) { + // this.writeData(PumpBaseType.Event, entry.getHead()[0] == 0 ? PumpEventType.BatteryRemoved : + // PumpEventType.BatteryReplaced, entry.getATechDate()); + entry.displayableValue = if (entry.head!![0] == 0.toByte()) "Battery Removed" else "Battery Replaced" + } + + private fun decodeBasalProfileStart(entry: PumpHistoryEntry): RecordDecodeStatus { + val body = entry.body + // int bodyOffset = headerSize + timestampSize; + val offset = body!![0] * 1000 * 30 * 60 + var rate: Float? = null + val index = entry.head!![0].toInt() + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + rate = body[1] * 0.025f + } + + //LOG.info("Basal Profile Start: offset={}, rate={}, index={}, body_raw={}", offset, rate, index, body); + return if (rate == null) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Basal Profile Start (ERROR): offset=%d, rate=%.3f, index=%d, body_raw=%s", offset, rate, index, ByteUtil.getHex(body))) + RecordDecodeStatus.Error + } else { + entry.addDecodedData("Value", getFormattedFloat(rate, 3)) + entry.displayableValue = getFormattedFloat(rate, 3) + RecordDecodeStatus.OK + } + } + + private fun decodeBolusWizard(entry: PumpHistoryEntry): RecordDecodeStatus { + val body = entry.body as IntArray + val dto = BolusWizardDTO() + var bolusStrokes = 10.0f + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.medtronicPumpModel, MedtronicDeviceType.Medtronic_523andHigher)) { + // https://github.com/ps2/minimed_rf/blob/master/lib/minimed_rf/log_entries/bolus_wizard.rb#L102 + bolusStrokes = 40.0f + dto.carbs = (body[1] and 0x0c shl 6) + body[0] + dto.bloodGlucose = (body[1] and 0x03 shl 8) + entry.head!![0] + dto.carbRatio = body[1] / 10.0f + // carb_ratio (?) = (((self.body[2] & 0x07) << 8) + self.body[3]) / + // 10.0s + dto.insulinSensitivity = body[4].toFloat() + dto.bgTargetLow = body[5] as Int + dto.bgTargetHigh = body[14] as Int + dto.correctionEstimate = ((body[9] and 0x38 shl 5) + body[6]) / bolusStrokes + dto.foodEstimate = ((body[7] shl 8) + body[8]) / bolusStrokes + dto.unabsorbedInsulin = ((body[10] shl 8) + body[11]) / bolusStrokes + dto.bolusTotal = ((body[12] shl 8) + body[13]) / bolusStrokes + } else { + dto.bloodGlucose = body.get(1) and 0x0F shl 8 or entry.head!!.get(0).toInt() + dto.carbs = body.get(0) as Int + dto.carbRatio = body.get(2).toFloat() + dto.insulinSensitivity = body.get(3).toFloat() + dto.bgTargetLow = body.get(4) as Int + dto.bgTargetHigh = body.get(12) as Int + dto.bolusTotal = body.get(11) / bolusStrokes + dto.foodEstimate = body.get(6) / bolusStrokes + dto.unabsorbedInsulin = body.get(9) / bolusStrokes + dto.bolusTotal = body.get(11) / bolusStrokes + dto.correctionEstimate = (body.get(7) + (body.get(5) and 0x0F)) / bolusStrokes + } + if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { + dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.toByte()) + } + dto.atechDateTime = entry.atechDateTime!! + entry.addDecodedData("Object", dto) + entry.displayableValue = dto.displayableValue + return RecordDecodeStatus.OK + } + + private fun decodeBolusWizard512(entry: PumpHistoryEntry): RecordDecodeStatus { + val body = entry.body as IntArray + val dto = BolusWizardDTO() + val bolusStrokes = 10.0f + dto.bloodGlucose = body.get(1) and 0x03 shl 8 or entry.head!!.get(0).toInt() + dto.carbs = body!!.get(1).toInt() and 0xC shl 6 or body.get(0).toInt() // (int)body[0]; + dto.carbRatio = body!!.get(2).toFloat() + dto.insulinSensitivity = body!!.get(3).toFloat() + dto.bgTargetLow = body.get(4) + dto.foodEstimate = body.get(6) / 10.0f + dto.correctionEstimate = (body.get(7) + (body.get(5) and 0x0F)) / bolusStrokes + dto.unabsorbedInsulin = body.get(9) / bolusStrokes + dto.bolusTotal = body.get(11) / bolusStrokes + dto.bgTargetHigh = dto.bgTargetLow + if (dto.bloodGlucose != null && dto.bloodGlucose < 0) { + dto.bloodGlucose = ByteUtil.convertUnsignedByteToInt(dto.bloodGlucose.toByte()) + } + dto.atechDateTime = entry.atechDateTime!! + entry.addDecodedData("Object", dto) + entry.displayableValue = dto.displayableValue + return RecordDecodeStatus.OK + } + + private fun decodeLowReservoir(entry: PumpHistoryEntry) { + val amount = getUnsignedInt(entry.head!!.get(0)) * 1.0f / 10.0f * 2 + entry.displayableValue = getFormattedValue(amount, 1) + } + + private fun decodePrime(entry: PumpHistoryEntry) { + val amount = ByteUtil.toInt(entry.head!!.get(2), entry.head!!.get(3)) / 10.0f + val fixed = ByteUtil.toInt(entry.head!!.get(0), entry.head!!.get(1)) / 10.0f + +// amount = (double)(asUINT8(data[4]) << 2) / 40.0; +// programmedAmount = (double)(asUINT8(data[2]) << 2) / 40.0; +// primeType = programmedAmount == 0 ? "manual" : "fixed"; + entry.addDecodedData("Amount", amount) + entry.addDecodedData("FixedAmount", fixed) + entry.displayableValue = ("Amount=" + getFormattedValue(amount, 2) + ", Fixed Amount=" + + getFormattedValue(fixed, 2)) + } + + private fun decodeChangeTempBasalType(entry: PumpHistoryEntry) { + entry.addDecodedData("isPercent", ByteUtil.asUINT8(entry.getRawDataByIndex(0)) == 1) // index moved from 1 -> 0 + } + + private fun decodeBgReceived(entry: PumpHistoryEntry) { + entry.addDecodedData("amount", (ByteUtil.asUINT8(entry.getRawDataByIndex(0)) shl 3) + (ByteUtil.asUINT8(entry.getRawDataByIndex(3)) shr 5)) + entry.addDecodedData("meter", ByteUtil.substring(entry.rawData, 6, 3)) // index moved from 1 -> 0 + } + + private fun decodeCalBGForPH(entry: PumpHistoryEntry) { + entry.addDecodedData("amount", (ByteUtil.asUINT8(entry.getRawDataByIndex(5)) and 0x80 shl 1) + ByteUtil.asUINT8(entry.getRawDataByIndex(0))) // index moved from 1 -> 0 + } + + private fun decodeNoDeliveryAlarm(entry: PumpHistoryEntry) { + //rawtype = asUINT8(data[1]); + // not sure if this is actually NoDelivery Alarm? + } + + override fun postProcess() {} + + override fun runPostDecodeTasks() { + showStatistics() + } + + private fun decodeBolus(entry: PumpHistoryEntry) { + val bolus = BolusDTO() + val data = entry.head as IntArray + if (MedtronicDeviceType.isSameDevice(medtronicUtil!!.getMedtronicPumpModel(), MedtronicDeviceType.Medtronic_523andHigher)) { + bolus.requestedAmount = ByteUtil.toInt(data.get(0), data.get(1)) / 40.0 + bolus.deliveredAmount = ByteUtil.toInt(data.get(2), data.get(3)) / 40.0 + bolus.insulinOnBoard = ByteUtil.toInt(data.get(4), data.get(5)) / 40.0 + bolus.duration = data.get(6) * 30 + } else { + bolus.requestedAmount = ByteUtil.asUINT8(data.get(0)) / 10.0 + bolus.deliveredAmount = ByteUtil.asUINT8(data.get(1)) / 10.0 + bolus.duration = ByteUtil.asUINT8(data.get(2)) * 30 + } + bolus.bolusType = if (bolus.duration != null && bolus.duration > 0) PumpBolusType.Extended else PumpBolusType.Normal + bolus.setAtechDateTime(entry.atechDateTime!!) + entry.addDecodedData("Object", bolus) + entry.displayableValue = bolus.displayableValue + } + + // private fun decodeTempBasal(entry: PumpHistoryEntry) { + // if (tbrPreviousRecord == null) { + // // LOG.debug(this.tbrPreviousRecord.toString()); + // tbrPreviousRecord = entry + // return + // } + // decodeTempBasal(tbrPreviousRecord, entry) + // tbrPreviousRecord = null + // } + + fun decodeTempBasal(tbrPreviousRecord: PumpHistoryEntry, entry: PumpHistoryEntry) { + var tbrRate: PumpHistoryEntry? = null + var tbrDuration: PumpHistoryEntry? = null + if (entry.entryType === PumpHistoryEntryType.TempBasalRate) { + tbrRate = entry + } else { + tbrDuration = entry + } + if (tbrRate != null) { + tbrDuration = tbrPreviousRecord + } else { + tbrRate = tbrPreviousRecord + } + +// TempBasalPair tbr = new TempBasalPair( +// tbrRate.getHead()[0], +// tbrDuration.getHead()[0], +// (ByteUtil.asUINT8(tbrRate.getDatetime()[4]) >> 3) == 0); + val tbr = TempBasalPair( + tbrRate!!.head!!.get(0), + tbrRate!!.body!!.get(0), + tbrDuration!!.head!!.get(0).toInt(), + ByteUtil.asUINT8(tbrRate!!.datetime!!.get(4)) shr 3 == 0) + + // System.out.println("TBR: amount=" + tbr.getInsulinRate() + ", duration=" + tbr.getDurationMinutes() + // // + " min. Packed: " + tbr.getValue() + // ); + entry.addDecodedData("Object", tbr) + entry.displayableValue = tbr.description + } + + private fun decodeDateTime(entry: PumpHistoryEntry) { + val dt = entry.datetime as IntArray + if (dt == null) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, "DateTime not set.") + } + if (entry.dateTimeLength == 5) { + val seconds: Int = (dt!!.get(0) and 0x3F).toInt() + val minutes: Int = (dt!!.get(1) and 0x3F).toInt() + val hour: Int = (dt.get(2) and 0x1F).toInt() + val month: Int = (dt.get(0) shr 4 and 0x0c) + (dt.get(1) shr 6 and 0x03) + // ((dt[0] & 0xC0) >> 6) | ((dt[1] & 0xC0) >> 4); + val dayOfMonth: Int = dt.get(3) and 0x1F + val year = fix2DigitYear(dt.get(4) and 0x3F) // Assuming this is correct, need to verify. Otherwise this will be + // a problem in 2016. + entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)) + } else if (entry.dateTimeLength == 2) { + val low = ByteUtil.asUINT8(dt.get(0)) and 0x1F + val mhigh = ByteUtil.asUINT8(dt.get(0)) and 0xE0 shr 4 + val mlow = ByteUtil.asUINT8(dt.get(1)) and 0x80 shr 7 + val month = mhigh + mlow + // int dayOfMonth = low + 1; + val dayOfMonth: Int = dt.get(0) and 0x1F + val year = 2000 + (ByteUtil.asUINT8(dt.get(1)) and 0x7F) + var hour = 0 + var minutes = 0 + var seconds = 0 + + //LOG.debug("DT: {} {} {}", year, month, dayOfMonth); + if (dayOfMonth == 32) { + aapsLogger!!.warn(LTag.PUMPBTCOMM, String.format(Locale.ENGLISH, "Entry: Day 32 %s = [%s] %s", entry.entryType!!.name, + ByteUtil.getHex(entry.rawData), entry)) + } + if (isEndResults(entry.entryType)) { + hour = 23 + minutes = 59 + seconds = 59 + } + entry.setAtechDateTime(DateTimeUtil.toATechDate(year, month, dayOfMonth, hour, minutes, seconds)) + } else { + aapsLogger!!.warn(LTag.PUMPBTCOMM, "Unknown datetime format: " + entry.dateTimeLength) + } + } + + private fun isEndResults(entryType: PumpHistoryEntryType?): Boolean { + return entryType === PumpHistoryEntryType.EndResultTotals || entryType === PumpHistoryEntryType.DailyTotals515 || entryType === PumpHistoryEntryType.DailyTotals522 || entryType === PumpHistoryEntryType.DailyTotals523 + } + + private fun fix2DigitYear(year: Int): Int { + var year = year + year += if (year > 90) { + 1900 + } else { + 2000 + } + return year + } + + companion object { + private fun getFormattedValue(value: Float, decimals: Int): String { + return String.format(Locale.ENGLISH, "%." + decimals + "f", value) + } + } + + init { + super.aapsLogger = aapsLogger + this.medtronicUtil = medtronicUtil + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java deleted file mode 100644 index 3866e3e6ba..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.java +++ /dev/null @@ -1,174 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import com.google.gson.annotations.Expose; - -import java.util.Objects; - -import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil; -import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil; -import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public class PumpHistoryEntry extends MedtronicHistoryEntry { - - @Expose - private PumpHistoryEntryType entryType; - private Integer opCode; // this is set only when we have unknown entry... - private int offset; - private String displayableValue = ""; - - - public PumpHistoryEntryType getEntryType() { - return entryType; - } - - - public void setEntryType(MedtronicDeviceType medtronicDeviceType, PumpHistoryEntryType entryType) { - this.entryType = entryType; - - this.sizes[0] = entryType.getHeadLength(medtronicDeviceType); - this.sizes[1] = entryType.getDateLength(); - this.sizes[2] = entryType.getBodyLength(medtronicDeviceType); - - if (this.entryType != null && this.atechDateTime != null) - setPumpId(); - } - - - private void setPumpId() { - this.pumpId = this.entryType.getCode() + (this.atechDateTime * 1000L); - } - - - @Override - public int getOpCode() { - if (opCode == null) - return entryType.getOpCode(); - else - return opCode; - } - - - public void setOpCode(Integer opCode) { - this.opCode = opCode; - } - - - @Override - public String getToStringStart() { - return "PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType.name(), 20) + " [" - + StringUtil.getStringInLength("" + getOpCode(), 3) + ", 0x" - + ByteUtil.shortHexString((byte) getOpCode()) + "]"; - } - - - public String toString() { - return super.toString(); -// Object object = this.getDecodedDataEntry("Object"); -// -// if (object == null) { -// return super.toString(); -// } else { -// return super.toString() + "PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType.name(), 20) + ", DT: " + DT + ", Object=" + object.toString() + "]"; -// } - } - - - public int getOffset() { - return offset; - } - - - public void setOffset(int offset) { - this.offset = offset; - } - - - @Override - public String getEntryTypeName() { - return this.entryType.name(); - } - - - @Override - public int getDateLength() { - return this.entryType.getDateLength(); - } - - - @Override - public boolean equals(Object o) { - if (this == o) - return true; - - if (!(o instanceof PumpHistoryEntry)) - return false; - - PumpHistoryEntry that = (PumpHistoryEntry) o; - - return entryType == that.entryType && // - this.atechDateTime == that.atechDateTime; // && // - // Objects.equals(this.decodedData, that.decodedData); - } - - - @Override - public int hashCode() { - return Objects.hash(entryType, opCode, offset); - } - - - // public boolean isAfter(LocalDateTime dateTimeIn) { - // // LOG.debug("Entry: " + this.dateTime); - // // LOG.debug("Datetime: " + dateTimeIn); - // // LOG.debug("Item after: " + this.dateTime.isAfter(dateTimeIn)); - // return this.dateTime.isAfter(dateTimeIn); - // } - - public boolean isAfter(long atechDateTime) { - if (this.atechDateTime == null) { - LOG.error("Date is null. Show object: " + toString()); - return false; // FIXME shouldn't happen - } - - return atechDateTime < this.atechDateTime; - } - - - public void setDisplayableValue(String displayableValue) { - this.displayableValue = displayableValue; - } - - - public String getDisplayableValue() { - return displayableValue; - } - - public static class Comparator implements java.util.Comparator { - - @Override - public int compare(PumpHistoryEntry o1, PumpHistoryEntry o2) { - int data = (int) (o2.atechDateTime - o1.atechDateTime); - - if (data != 0) - return data; - - return o2.getEntryType().getCode() - o1.getEntryType().getCode(); - } - } - - - public Long getPumpId() { - setPumpId(); - - return pumpId; - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt new file mode 100644 index 0000000000..e1c0daf2ea --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntry.kt @@ -0,0 +1,117 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import android.util.Log +import com.google.gson.annotations.Expose +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil +import info.nightscout.androidaps.plugins.pump.medtronic.comm.history.MedtronicHistoryEntry +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +class PumpHistoryEntry : MedtronicHistoryEntry() { + + @Expose var entryType: PumpHistoryEntryType? = null + private set + + override var opCode: Byte? = null + // this is set only when we have unknown entry... + get() = if (field == null) entryType!!.code else field + set(value) { + field = value + } + + // // override fun getOpCode(): Int { + // // return + // // } + // + // fun setOpCode(opCode: Int?) { + // this.opCode = opCode + // } + + var offset = 0 + var displayableValue = "" + + fun setEntryType(medtronicDeviceType: MedtronicDeviceType?, entryType: PumpHistoryEntryType) { + this.entryType = entryType + sizes[0] = entryType.getHeadLength(medtronicDeviceType) + sizes[1] = entryType.dateLength + sizes[2] = entryType.getBodyLength(medtronicDeviceType) + if (this.entryType != null && atechDateTime != null) setPumpId() + } + + private fun setPumpId() { + pumpId = entryType!!.code + atechDateTime!! * 1000L + } + + override val toStringStart: String + get() = ("PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType!!.name, 20) + " [" + + StringUtil.getStringInLength("" + opCode, 3) + ", 0x" + + ByteUtil.shortHexString(opCode!!) + "]") + + override fun toString(): String { + return super.toString() + // Object object = this.getDecodedDataEntry("Object"); +// +// if (object == null) { +// return super.toString(); +// } else { +// return super.toString() + "PumpHistoryEntry [type=" + StringUtil.getStringInLength(entryType.name(), 20) + ", DT: " + DT + ", Object=" + object.toString() + "]"; +// } + } + + override val entryTypeName: String + get() = entryType!!.name + + override val dateLength: Int + get() = entryType!!.dateLength + + override fun equals(o: Any?): Boolean { + if (this === o) return true + if (o !is PumpHistoryEntry) return false + val that = o + return entryType == that.entryType && // + atechDateTime === that.atechDateTime // && // + // Objects.equals(this.decodedData, that.decodedData); + } + + override fun hashCode(): Int { + return Objects.hash(entryType, opCode, offset) + } + + // public boolean isAfter(LocalDateTime dateTimeIn) { + // // LOG.debug("Entry: " + this.dateTime); + // // LOG.debug("Datetime: " + dateTimeIn); + // // LOG.debug("Item after: " + this.dateTime.isAfter(dateTimeIn)); + // return this.dateTime.isAfter(dateTimeIn); + // } + fun isAfter(atechDateTime: Long): Boolean { + if (this.atechDateTime == null) { + Log.e("PumpHistoryEntry", "Date is null. Show object: " + toString()) + return false // FIXME shouldn't happen + } + return atechDateTime < this.atechDateTime!! + } + + class Comparator : java.util.Comparator { + override fun compare(o1: PumpHistoryEntry, o2: PumpHistoryEntry): Int { + val data = (o2.atechDateTime!! - o1.atechDateTime!!).toInt() + return if (data != 0) data else o2.entryType!!.code - o1.entryType!!.code + } + } + + override var pumpId: Long? = null + get() { + setPumpId() + return field + } + set(pumpId) { + super.pumpId = pumpId + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java deleted file mode 100644 index becfcfbcd2..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.java +++ /dev/null @@ -1,378 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup; -import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType; - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public enum PumpHistoryEntryType // implements CodeEnum -{ - // all commented out are probably not the real items - None(0, "None", PumpHistoryEntryGroup.Unknown, 1, 0, 0), - Bolus(0x01, "Bolus", PumpHistoryEntryGroup.Bolus, 4, 5, 0), // 523+[H=8] 9/13 - Prime(0x03, "Prime", PumpHistoryEntryGroup.Prime, 5, 5, 0), // - // /**/EventUnknown_MM522_0x05((byte) 0x05, "Unknown Event 0x05", PumpHistoryEntryGroup.Unknown, 2, 5, 28), // - NoDeliveryAlarm(0x06, "No Delivery", PumpHistoryEntryGroup.Alarm, 4, 5, 0), // - EndResultTotals(0x07, "End Result Totals", PumpHistoryEntryGroup.Statistic, 5, 2, 0), - ChangeBasalProfile_OldProfile(0x08, "Change Basal Profile (Old)", PumpHistoryEntryGroup.Basal, 2, 5, 145), - ChangeBasalProfile_NewProfile(0x09, "Change Basal Profile (New)", PumpHistoryEntryGroup.Basal, 2, 5, 145), // - // /**/EventUnknown_MM512_0x10(0x10, "Unknown Event 0x10", PumpHistoryEntryGroup.Unknown), // 29, 5, 0 - CalBGForPH(0x0a, "BG Capture", PumpHistoryEntryGroup.Glucose), // - SensorAlert(0x0b, "Sensor Alert", PumpHistoryEntryGroup.Alarm, 3, 5, 0), // Ian08 - ClearAlarm(0x0c, "Clear Alarm", PumpHistoryEntryGroup.Alarm, 2, 5, 0), // 2,5,4 - ChangeBasalPattern(0x14, "Change Basal Pattern", PumpHistoryEntryGroup.Basal), // - TempBasalDuration(0x16, "TBR Duration", PumpHistoryEntryGroup.Basal), // - ChangeTime(0x17, "Change Time", PumpHistoryEntryGroup.Configuration), // - NewTimeSet(0x18, "New Time Set", PumpHistoryEntryGroup.Notification), // - LowBattery(0x19, "LowBattery", PumpHistoryEntryGroup.Notification), // - BatteryChange(0x1a, "Battery Change", PumpHistoryEntryGroup.Notification), // - SetAutoOff(0x1b, "Set Auto Off", PumpHistoryEntryGroup.Configuration), // - SuspendPump(0x1e, "Suspend", PumpHistoryEntryGroup.Basal), // - ResumePump(0x1f, "Resume", PumpHistoryEntryGroup.Basal), // - SelfTest(0x20, "Self Test", PumpHistoryEntryGroup.Statistic), // - Rewind(0x21, "Rewind", PumpHistoryEntryGroup.Prime), // - ClearSettings(0x22, "Clear Settings", PumpHistoryEntryGroup.Configuration), // - ChangeChildBlockEnable(0x23, "Change Child Block Enable", PumpHistoryEntryGroup.Configuration), // - ChangeMaxBolus(0x24, "Change Max Bolus", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM522_0x25(0x25, "Unknown Event 0x25", PumpHistoryEntryGroup.Unknown), // 8? - EnableDisableRemote(0x26, "Enable/Disable Remote", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // 2, 5, 14 V6:2,5,14 - ChangeRemoteId(0x27, "Change Remote ID", PumpHistoryEntryGroup.Configuration), // ?? - ChangeMaxBasal(0x2c, "Change Max Basal", PumpHistoryEntryGroup.Configuration), // - BolusWizardEnabled(0x2d, "Bolus Wizard Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? - /* TODO */EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // - BolusWizard512(0x2f, "Bolus Wizard (512)", PumpHistoryEntryGroup.Bolus, 2, 5, 12), // - UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // FIXME - ChangeBGReminderOffset(0x31, "Change BG Reminder Offset", PumpHistoryEntryGroup.Configuration), // - ChangeAlarmClockTime(0x32, "Change Alarm Clock Time", PumpHistoryEntryGroup.Configuration), // - TempBasalRate(0x33, "TBR Rate", PumpHistoryEntryGroup.Basal, 2, 5, 1), // - LowReservoir(0x34, "Low Reservoir", PumpHistoryEntryGroup.Notification), // - ChangeAlarmClock(0x35, "Change Alarm Clock", PumpHistoryEntryGroup.Configuration), // - ChangeMeterId(0x36, "Change Meter ID", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM512_0x37(0x37, "Unknown Event 0x37", PumpHistoryEntryGroup.Unknown), // V:MM512 -// /**/EventUnknown_MM512_0x38(0x38, "Unknown Event 0x38", PumpHistoryEntryGroup.Unknown), // - BGReceived512(0x39, "BG Received (512)", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // - /* TODO */ConfirmInsulinChange(0x3a, "Confirm Insulin Change", PumpHistoryEntryGroup.Unknown), // - SensorStatus(0x3b, "Sensor Status", PumpHistoryEntryGroup.Glucose), // - ChangeParadigmID(0x3c, "Change Paradigm ID", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // V3 ? V6: 2,5,14 ?? is it this length or just 7 - // EventUnknown_MM512_0x3D(0x3d, "Unknown Event 0x3D", PumpHistoryEntryGroup.Unknown), // -// EventUnknown_MM512_0x3E(0x3e, "Unknown Event 0x3E", PumpHistoryEntryGroup.Unknown), // - BGReceived(0x3f, "BG Received", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // Ian3F - JournalEntryMealMarker(0x40, "Meal Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 2), // is size just 7??? V6 - JournalEntryExerciseMarker(0x41, "Exercise Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // ?? - JournalEntryInsulinMarker(0x42, "Insulin Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 0), // V6 = body(0)/was=1 - JournalEntryOtherMarker(0x43, "Other Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // V6 = body(1)/was=0 - EnableSensorAutoCal(0x44, "Enable Sensor AutoCal", PumpHistoryEntryGroup.Glucose), // - // /**/EventUnknown_MM522_0x45(0x45, "Unknown Event 0x45", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x46(0x46, "Unknown Event 0x46", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x47(0x47, "Unknown Event 0x47", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x48(0x48, "Unknown Event 0x48", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x49(0x49, "Unknown Event 0x49", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x4a(0x4a, "Unknown Event 0x4a", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x4b(0x4b, "Unknown Event 0x4b", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_MM522_0x4c(0x4c, "Unknown Event 0x4c", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // -// /**/EventUnknown_0x4d(0x4d, "Unknown Event 0x4d", PumpHistoryEntryGroup.Unknown), // V5: 512: 7, 522: 8 ????NS -// /**/EventUnknown_MM512_0x4e(0x4e, "Unknown Event 0x4e", PumpHistoryEntryGroup.Unknown), // /**/ - BolusWizardSetup512(0x4f, "Bolus Wizard Setup (512)", PumpHistoryEntryGroup.Configuration, 2, 5, 32), // - ChangeSensorSetup2(0x50, "Sensor Setup2", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // Ian50 - /* TODO */Sensor_0x51(0x51, "Unknown Event 0x51", PumpHistoryEntryGroup.Unknown), // - /* TODO */Sensor_0x52(0x52, "Unknown Event 0x52", PumpHistoryEntryGroup.Unknown), // - ChangeSensorAlarmSilenceConfig(0x53, "Sensor Alarm Silence Config", PumpHistoryEntryGroup.Configuration, 2, 5, 1), // 8 - /* TODO */Sensor_0x54(0x54, "Unknown Event 0x54", PumpHistoryEntryGroup.Unknown), // Ian54 - /* TODO */Sensor_0x55(0x55, "Unknown Event 0x55", PumpHistoryEntryGroup.Unknown), // - ChangeSensorRateOfChangeAlertSetup(0x56, "Sensor Rate Of Change Alert Setup", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 - ChangeBolusScrollStepSize(0x57, "Change Bolus Scroll Step Size", PumpHistoryEntryGroup.Configuration), // - BolusWizardSetup(0x5a, "Bolus Wizard Setup (522)", PumpHistoryEntryGroup.Configuration, 2, 5, 117), - // V2: 522+[B=143]; V6: 124, v6: 137, v7: 117/137 [523] - BolusWizard(0x5b, "Bolus Wizard Estimate", PumpHistoryEntryGroup.Configuration, 2, 5, 13), // 15 // - UnabsorbedInsulin(0x5c, "Unabsorbed Insulin", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // head[1] -> body - SaveSettings(0x5d, "Save Settings", PumpHistoryEntryGroup.Configuration), // - ChangeVariableBolus(0x5e, "Change Variable Bolus", PumpHistoryEntryGroup.Configuration), // - ChangeAudioBolus(0x5f, "Easy Bolus Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? - ChangeBGReminderEnable(0x60, "BG Reminder Enable", PumpHistoryEntryGroup.Configuration), // questionable60 - ChangeAlarmClockEnable(0x61, "Alarm Clock Enable", PumpHistoryEntryGroup.Configuration), // - ChangeTempBasalType((byte) 0x62, "Change Basal Type", PumpHistoryEntryGroup.Configuration), // ChangeTempBasalTypePumpEvent - ChangeAlarmNotifyMode(0x63, "Change Alarm Notify Mode", PumpHistoryEntryGroup.Configuration), // - ChangeTimeFormat(0x64, "Change Time Format", PumpHistoryEntryGroup.Configuration), // - ChangeReservoirWarningTime((byte) 0x65, "Change Reservoir Warning Time", PumpHistoryEntryGroup.Configuration), // - ChangeBolusReminderEnable(0x66, "Change Bolus Reminder Enable", PumpHistoryEntryGroup.Configuration), // 9 - SetBolusReminderTime((byte) 0x67, "Change Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 - DeleteBolusReminderTime((byte) 0x68, "Delete Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 - BolusReminder(0x69, "Bolus Reminder", PumpHistoryEntryGroup.Configuration, 2, 5, 0), // Ian69 - DeleteAlarmClockTime(0x6a, "Delete Alarm Clock Time", PumpHistoryEntryGroup.Configuration, 2, 5, 7), // 14 - DailyTotals515(0x6c, "Daily Totals (515)", PumpHistoryEntryGroup.Statistic, 1, 2, 35), // v4: 0,0,36. v5: 1,2,33 - DailyTotals522(0x6d, "Daily Totals (522)", PumpHistoryEntryGroup.Statistic, 1, 2, 41), // - DailyTotals523(0x6e, "Daily Totals (523)", PumpHistoryEntryGroup.Statistic, 1, 2, 49), // 1102014-03-17T00:00:00 - ChangeCarbUnits((byte) 0x6f, "Change Carb Units", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM522_0x70((byte) 0x70, "Unknown Event 0x70", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // - BasalProfileStart(0x7b, "Basal Profile Start", PumpHistoryEntryGroup.Basal, 2, 5, 3), // // 722 - ChangeWatchdogEnable((byte) 0x7c, "Change Watchdog Enable", PumpHistoryEntryGroup.Configuration), // - ChangeOtherDeviceID((byte) 0x7d, "Change Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // - ChangeWatchdogMarriageProfile(0x81, "Change Watchdog Marriage Profile", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 - DeleteOtherDeviceID(0x82, "Delete Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // - ChangeCaptureEventEnable(0x83, "Change Capture Event Enable", PumpHistoryEntryGroup.Configuration), // - // /**/EventUnknown_MM512_0x88(0x88, "Unknown Event 0x88", PumpHistoryEntryGroup.Unknown), // -// /**/EventUnknown_MM512_0x94(0x94, "Unknown Event 0x94", PumpHistoryEntryGroup.Unknown), // - /**/ IanA8(0xA8, "Ian A8 (Unknown)", PumpHistoryEntryGroup.Unknown, 10, 5, 0), // - // /**/EventUnknown_MM522_0xE8(0xe8, "Unknown Event 0xE8", PumpHistoryEntryGroup.Unknown, 2, 5, 25), // - // F0 - F3 are not in go code, but they are in GGC one and thet are used - ReadOtherDevicesIDs(0xf0, "Read Other Devices IDs", PumpHistoryEntryGroup.Configuration), // ? - ReadCaptureEventEnabled(0xf1, "Read Capture Event Enabled", PumpHistoryEntryGroup.Configuration), // ? - ChangeCaptureEventEnable2(0xf2, "Change Capture Event Enable2", PumpHistoryEntryGroup.Configuration), // ? - ReadOtherDevicesStatus(0xf3, "Read Other Devices Status", PumpHistoryEntryGroup.Configuration), // ? - - TempBasalCombined(0xfe, "TBR", PumpHistoryEntryGroup.Basal), // - UnknownBasePacket(0xff, "Unknown Base Packet", PumpHistoryEntryGroup.Unknown); - - private static final Map opCodeMap = new HashMap<>(); - - static { - for (PumpHistoryEntryType type : values()) { - opCodeMap.put(type.opCode, type); - } - - setSpecialRulesForEntryTypes(); - } - - private final int opCode; - private final String description; - private final int headLength; - private final int dateLength; - // private MinimedDeviceType deviceType; - private final int bodyLength; - private final int totalLength; - // special rules need to be put in list from highest to lowest (e.g.: - // 523andHigher=12, 515andHigher=10 and default (set in cnstr) would be 8) - private List specialRulesHead; - private List specialRulesBody; - private boolean hasSpecialRules = false; - private final PumpHistoryEntryGroup group; - - - PumpHistoryEntryType(int opCode, String name, PumpHistoryEntryGroup group) { - this(opCode, name, group, 2, 5, 0); - } - - - PumpHistoryEntryType(int opCode, PumpHistoryEntryGroup group) { - this(opCode, null, group, 2, 5, 0); - } - - - PumpHistoryEntryType(int opCode, PumpHistoryEntryGroup group, int head, int date, int body) { - this(opCode, null, group, head, date, body); - } - - - PumpHistoryEntryType(int opCode, String name, PumpHistoryEntryGroup group, int head, int date, int body) { - this.opCode = (byte) opCode; - this.description = name; - this.headLength = head; - this.dateLength = date; - this.bodyLength = body; - this.totalLength = (head + date + body); - this.group = group; - } - - - static void setSpecialRulesForEntryTypes() { - EndResultTotals.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3)); - Bolus.addSpecialRuleHead(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 8)); - BolusWizardSetup.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 137)); - BolusWizard.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 15)); - BolusReminder.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 2)); - ChangeSensorSetup2.addSpecialRuleBody(new SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 34)); - } - - - public static PumpHistoryEntryType getByCode(int opCode) { - if (opCodeMap.containsKey(opCode)) { - return opCodeMap.get(opCode); - } else { - return PumpHistoryEntryType.UnknownBasePacket; - } - } - - - // - // private PumpHistoryEntryType(int opCode, String name, int head, int date, - // int body) - // { - // this.opCode = (byte) opCode; - // this.description = name; - // this.headLength = head; - // this.dateLength = date; - // this.bodyLength = body; - // this.totalLength = (head + date + body); - // } - // - - public static boolean isAAPSRelevantEntry(PumpHistoryEntryType entryType) { - return (entryType == PumpHistoryEntryType.Bolus || // Treatments - entryType == PumpHistoryEntryType.TempBasalRate || // - entryType == PumpHistoryEntryType.TempBasalDuration || // - - entryType == PumpHistoryEntryType.Prime || // Pump Status Change - entryType == PumpHistoryEntryType.SuspendPump || // - entryType == PumpHistoryEntryType.ResumePump || // - entryType == PumpHistoryEntryType.Rewind || // - entryType == PumpHistoryEntryType.NoDeliveryAlarm || // no delivery - entryType == PumpHistoryEntryType.BasalProfileStart || // - - entryType == PumpHistoryEntryType.ChangeTime || // Time Change - entryType == PumpHistoryEntryType.NewTimeSet || // - - entryType == PumpHistoryEntryType.ChangeBasalPattern || // Configuration - entryType == PumpHistoryEntryType.ClearSettings || // - entryType == PumpHistoryEntryType.SaveSettings || // - entryType == PumpHistoryEntryType.ChangeMaxBolus || // - entryType == PumpHistoryEntryType.ChangeMaxBasal || // - entryType == PumpHistoryEntryType.ChangeTempBasalType || // - - entryType == PumpHistoryEntryType.ChangeBasalProfile_NewProfile || // Basal profile - - entryType == PumpHistoryEntryType.DailyTotals515 || // Daily Totals - entryType == PumpHistoryEntryType.DailyTotals522 || // - entryType == PumpHistoryEntryType.DailyTotals523 || // - entryType == PumpHistoryEntryType.EndResultTotals); - } - - - public static boolean isRelevantEntry() { - return true; - } - - - public int getCode() { - return this.opCode; - } - - - public int getTotalLength(MedtronicDeviceType medtronicDeviceType) { - if (hasSpecialRules()) { - return getHeadLength(medtronicDeviceType) + getBodyLength(medtronicDeviceType) + getDateLength(); - } else { - return totalLength; - } - } - - - private boolean hasSpecialRules() { - return hasSpecialRules; - } - - - void addSpecialRuleHead(SpecialRule rule) { - if (isEmpty(specialRulesHead)) { - specialRulesHead = new ArrayList<>(); - } - - specialRulesHead.add(rule); - hasSpecialRules = true; - } - - - void addSpecialRuleBody(SpecialRule rule) { - if (isEmpty(specialRulesBody)) { - specialRulesBody = new ArrayList<>(); - } - - specialRulesBody.add(rule); - hasSpecialRules = true; - } - - - public int getOpCode() { - return opCode; - } - - - public String getDescription() { - return this.description == null ? name() : this.description; - } - - - public int getHeadLength(MedtronicDeviceType medtronicDeviceType) { - if (hasSpecialRules) { - if (isNotEmpty(specialRulesHead)) { - return determineSizeByRule(medtronicDeviceType, headLength, specialRulesHead); - } else { - return headLength; - } - } else { - return headLength; - } - } - - - public int getDateLength() { - return dateLength; - } - - - public int getBodyLength(MedtronicDeviceType medtronicDeviceType) { - if (hasSpecialRules) { - if (isNotEmpty(specialRulesBody)) { - return determineSizeByRule(medtronicDeviceType, bodyLength, specialRulesBody); - } else { - return bodyLength; - } - } else { - return bodyLength; - } - } - - - private boolean isNotEmpty(List list) { - return list != null && !list.isEmpty(); - } - - - private boolean isEmpty(List list) { - return list == null || list.isEmpty(); - } - - - // byte[] dh = { 2, 3 }; - - private int determineSizeByRule(MedtronicDeviceType medtronicDeviceType, int defaultValue, List rules) { - int size = defaultValue; - - for (SpecialRule rule : rules) { - if (MedtronicDeviceType.isSameDevice(medtronicDeviceType, rule.deviceType)) { - size = rule.size; - break; - } - } - - return size; - } - - - public PumpHistoryEntryGroup getGroup() { - - return group; - } - - public static class SpecialRule { - - MedtronicDeviceType deviceType; - int size; - - - SpecialRule(MedtronicDeviceType deviceType, int size) { - this.deviceType = deviceType; - this.size = size; - } - } - -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt new file mode 100644 index 0000000000..3f2a4a0c40 --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryEntryType.kt @@ -0,0 +1,323 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import info.nightscout.androidaps.plugins.pump.common.defs.PumpHistoryEntryGroup +import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class PumpHistoryEntryType // implements CodeEnum +@JvmOverloads constructor(opCode: Byte, name: String?, group: PumpHistoryEntryGroup, head: Int = 2, date: Int = 5, body: Int = 0) { + + // all commented out are probably not the real items + None(0, "None", PumpHistoryEntryGroup.Unknown, 1, 0, 0), Bolus(0x01, "Bolus", PumpHistoryEntryGroup.Bolus, 4, 5, 0), // 523+[H=8] 9/13 + Prime(0x03, "Prime", PumpHistoryEntryGroup.Prime, 5, 5, 0), // + + // /**/EventUnknown_MM522_0x05((byte) 0x05, "Unknown Event 0x05", PumpHistoryEntryGroup.Unknown, 2, 5, 28), // + NoDeliveryAlarm(0x06, "No Delivery", PumpHistoryEntryGroup.Alarm, 4, 5, 0), // + EndResultTotals(0x07, "End Result Totals", PumpHistoryEntryGroup.Statistic, 5, 2, 0), ChangeBasalProfile_OldProfile(0x08, "Change Basal Profile (Old)", PumpHistoryEntryGroup.Basal, 2, 5, 145), ChangeBasalProfile_NewProfile(0x09, "Change Basal Profile (New)", PumpHistoryEntryGroup.Basal, 2, 5, 145), // + + // /**/EventUnknown_MM512_0x10(0x10, "Unknown Event 0x10", PumpHistoryEntryGroup.Unknown), // 29, 5, 0 + CalBGForPH(0x0a, "BG Capture", PumpHistoryEntryGroup.Glucose), // + SensorAlert(0x0b, "Sensor Alert", PumpHistoryEntryGroup.Alarm, 3, 5, 0), // Ian08 + ClearAlarm(0x0c, "Clear Alarm", PumpHistoryEntryGroup.Alarm, 2, 5, 0), // 2,5,4 + ChangeBasalPattern(0x14, "Change Basal Pattern", PumpHistoryEntryGroup.Basal), // + TempBasalDuration(0x16, "TBR Duration", PumpHistoryEntryGroup.Basal), // + ChangeTime(0x17, "Change Time", PumpHistoryEntryGroup.Configuration), // + NewTimeSet(0x18, "New Time Set", PumpHistoryEntryGroup.Notification), // + LowBattery(0x19, "LowBattery", PumpHistoryEntryGroup.Notification), // + BatteryChange(0x1a, "Battery Change", PumpHistoryEntryGroup.Notification), // + SetAutoOff(0x1b, "Set Auto Off", PumpHistoryEntryGroup.Configuration), // + SuspendPump(0x1e, "Suspend", PumpHistoryEntryGroup.Basal), // + ResumePump(0x1f, "Resume", PumpHistoryEntryGroup.Basal), // + SelfTest(0x20, "Self Test", PumpHistoryEntryGroup.Statistic), // + Rewind(0x21, "Rewind", PumpHistoryEntryGroup.Prime), // + ClearSettings(0x22, "Clear Settings", PumpHistoryEntryGroup.Configuration), // + ChangeChildBlockEnable(0x23, "Change Child Block Enable", PumpHistoryEntryGroup.Configuration), // + ChangeMaxBolus(0x24, "Change Max Bolus", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM522_0x25(0x25, "Unknown Event 0x25", PumpHistoryEntryGroup.Unknown), // 8? + EnableDisableRemote(0x26, "Enable/Disable Remote", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // 2, 5, 14 V6:2,5,14 + ChangeRemoteId(0x27, "Change Remote ID", PumpHistoryEntryGroup.Configuration), // ?? + ChangeMaxBasal(0x2c, "Change Max Basal", PumpHistoryEntryGroup.Configuration), // + BolusWizardEnabled(0x2d, "Bolus Wizard Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? + + /* TODO */ + EventUnknown_MM512_0x2e(0x2e, "Unknown Event 0x2e", PumpHistoryEntryGroup.Unknown, 2, 5, 100), // + BolusWizard512(0x2f, "Bolus Wizard (512)", PumpHistoryEntryGroup.Bolus, 2, 5, 12), // + UnabsorbedInsulin512(0x30, "Unabsorbed Insulin (512)", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // FIXME + ChangeBGReminderOffset(0x31, "Change BG Reminder Offset", PumpHistoryEntryGroup.Configuration), // + ChangeAlarmClockTime(0x32, "Change Alarm Clock Time", PumpHistoryEntryGroup.Configuration), // + TempBasalRate(0x33, "TBR Rate", PumpHistoryEntryGroup.Basal, 2, 5, 1), // + LowReservoir(0x34, "Low Reservoir", PumpHistoryEntryGroup.Notification), // + ChangeAlarmClock(0x35, "Change Alarm Clock", PumpHistoryEntryGroup.Configuration), // + ChangeMeterId(0x36, "Change Meter ID", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM512_0x37(0x37, "Unknown Event 0x37", PumpHistoryEntryGroup.Unknown), // V:MM512 + // /**/EventUnknown_MM512_0x38(0x38, "Unknown Event 0x38", PumpHistoryEntryGroup.Unknown), // + BGReceived512(0x39, "BG Received (512)", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // + + /* TODO */ + ConfirmInsulinChange(0x3a, "Confirm Insulin Change", PumpHistoryEntryGroup.Unknown), // + SensorStatus(0x3b, "Sensor Status", PumpHistoryEntryGroup.Glucose), // + ChangeParadigmID(0x3c, "Change Paradigm ID", PumpHistoryEntryGroup.Configuration, 2, 5, 14), // V3 ? V6: 2,5,14 ?? is it this length or just 7 + + // EventUnknown_MM512_0x3D(0x3d, "Unknown Event 0x3D", PumpHistoryEntryGroup.Unknown), // + // EventUnknown_MM512_0x3E(0x3e, "Unknown Event 0x3E", PumpHistoryEntryGroup.Unknown), // + BGReceived(0x3f, "BG Received", PumpHistoryEntryGroup.Glucose, 2, 5, 3), // Ian3F + JournalEntryMealMarker(0x40, "Meal Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 2), // is size just 7??? V6 + JournalEntryExerciseMarker(0x41, "Exercise Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // ?? + JournalEntryInsulinMarker(0x42, "Insulin Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 0), // V6 = body(0)/was=1 + JournalEntryOtherMarker(0x43, "Other Marker", PumpHistoryEntryGroup.Bolus, 2, 5, 1), // V6 = body(1)/was=0 + EnableSensorAutoCal(0x44, "Enable Sensor AutoCal", PumpHistoryEntryGroup.Glucose), // + + // /**/EventUnknown_MM522_0x45(0x45, "Unknown Event 0x45", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x46(0x46, "Unknown Event 0x46", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x47(0x47, "Unknown Event 0x47", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x48(0x48, "Unknown Event 0x48", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x49(0x49, "Unknown Event 0x49", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x4a(0x4a, "Unknown Event 0x4a", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x4b(0x4b, "Unknown Event 0x4b", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_MM522_0x4c(0x4c, "Unknown Event 0x4c", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + // /**/EventUnknown_0x4d(0x4d, "Unknown Event 0x4d", PumpHistoryEntryGroup.Unknown), // V5: 512: 7, 522: 8 ????NS + // /**/EventUnknown_MM512_0x4e(0x4e, "Unknown Event 0x4e", PumpHistoryEntryGroup.Unknown), // /**/ + BolusWizardSetup512(0x4f, "Bolus Wizard Setup (512)", PumpHistoryEntryGroup.Configuration, 2, 5, 32), // + ChangeSensorSetup2(0x50, "Sensor Setup2", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // Ian50 + + /* TODO */ + Sensor_0x51(0x51, "Unknown Event 0x51", PumpHistoryEntryGroup.Unknown), // + + /* TODO */ + Sensor_0x52(0x52, "Unknown Event 0x52", PumpHistoryEntryGroup.Unknown), // + ChangeSensorAlarmSilenceConfig(0x53, "Sensor Alarm Silence Config", PumpHistoryEntryGroup.Configuration, 2, 5, 1), // 8 + + /* TODO */ + Sensor_0x54(0x54, "Unknown Event 0x54", PumpHistoryEntryGroup.Unknown), // Ian54 + + /* TODO */ + Sensor_0x55(0x55, "Unknown Event 0x55", PumpHistoryEntryGroup.Unknown), // + ChangeSensorRateOfChangeAlertSetup(0x56, "Sensor Rate Of Change Alert Setup", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 + ChangeBolusScrollStepSize(0x57, "Change Bolus Scroll Step Size", PumpHistoryEntryGroup.Configuration), // + BolusWizardSetup(0x5a, "Bolus Wizard Setup (522)", PumpHistoryEntryGroup.Configuration, 2, 5, 117), // V2: 522+[B=143]; V6: 124, v6: 137, v7: 117/137 [523] + BolusWizard(0x5b, "Bolus Wizard Estimate", PumpHistoryEntryGroup.Configuration, 2, 5, 13), // 15 // + UnabsorbedInsulin(0x5c, "Unabsorbed Insulin", PumpHistoryEntryGroup.Statistic, 5, 0, 0), // head[1] -> body + SaveSettings(0x5d, "Save Settings", PumpHistoryEntryGroup.Configuration), // + ChangeVariableBolus(0x5e, "Change Variable Bolus", PumpHistoryEntryGroup.Configuration), // + ChangeAudioBolus(0x5f, "Easy Bolus Enabled", PumpHistoryEntryGroup.Configuration), // V3 ? + ChangeBGReminderEnable(0x60, "BG Reminder Enable", PumpHistoryEntryGroup.Configuration), // questionable60 + ChangeAlarmClockEnable(0x61, "Alarm Clock Enable", PumpHistoryEntryGroup.Configuration), // + ChangeTempBasalType(0x62.toByte(), "Change Basal Type", PumpHistoryEntryGroup.Configuration), // ChangeTempBasalTypePumpEvent + ChangeAlarmNotifyMode(0x63, "Change Alarm Notify Mode", PumpHistoryEntryGroup.Configuration), // + ChangeTimeFormat(0x64, "Change Time Format", PumpHistoryEntryGroup.Configuration), // + ChangeReservoirWarningTime(0x65.toByte(), "Change Reservoir Warning Time", PumpHistoryEntryGroup.Configuration), // + ChangeBolusReminderEnable(0x66, "Change Bolus Reminder Enable", PumpHistoryEntryGroup.Configuration), // 9 + SetBolusReminderTime(0x67.toByte(), "Change Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 + DeleteBolusReminderTime(0x68.toByte(), "Delete Bolus Reminder Time", PumpHistoryEntryGroup.Configuration, 2, 5, 2), // 9 + BolusReminder(0x69, "Bolus Reminder", PumpHistoryEntryGroup.Configuration, 2, 5, 0), // Ian69 + DeleteAlarmClockTime(0x6a, "Delete Alarm Clock Time", PumpHistoryEntryGroup.Configuration, 2, 5, 7), // 14 + DailyTotals515(0x6c, "Daily Totals (515)", PumpHistoryEntryGroup.Statistic, 1, 2, 35), // v4: 0,0,36. v5: 1,2,33 + DailyTotals522(0x6d, "Daily Totals (522)", PumpHistoryEntryGroup.Statistic, 1, 2, 41), // + DailyTotals523(0x6e, "Daily Totals (523)", PumpHistoryEntryGroup.Statistic, 1, 2, 49), // 1102014-03-17T00:00:00 + ChangeCarbUnits(0x6f.toByte(), "Change Carb Units", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM522_0x70((byte) 0x70, "Unknown Event 0x70", PumpHistoryEntryGroup.Unknown, 2, 5, 1), // + BasalProfileStart(0x7b, "Basal Profile Start", PumpHistoryEntryGroup.Basal, 2, 5, 3), // // 722 + ChangeWatchdogEnable(0x7c, "Change Watchdog Enable", PumpHistoryEntryGroup.Configuration), // + ChangeOtherDeviceID(0x7d, "Change Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 30), // + ChangeWatchdogMarriageProfile(0x81.toByte(), "Change Watchdog Marriage Profile", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // 12 + DeleteOtherDeviceID(0x82.toByte(), "Delete Other Device ID", PumpHistoryEntryGroup.Configuration, 2, 5, 5), // + ChangeCaptureEventEnable(0x83.toByte(), "Change Capture Event Enable", PumpHistoryEntryGroup.Configuration), // + + // /**/EventUnknown_MM512_0x88(0x88, "Unknown Event 0x88", PumpHistoryEntryGroup.Unknown), // + // /**/EventUnknown_MM512_0x94(0x94, "Unknown Event 0x94", PumpHistoryEntryGroup.Unknown), // + /**/ + IanA8(0xA8.toByte(), "Ian A8 (Unknown)", PumpHistoryEntryGroup.Unknown, 10, 5, 0), // + + // /**/EventUnknown_MM522_0xE8(0xe8, "Unknown Event 0xE8", PumpHistoryEntryGroup.Unknown, 2, 5, 25), // + // F0 - F3 are not in go code, but they are in GGC one and thet are used + ReadOtherDevicesIDs(0xf0.toByte(), "Read Other Devices IDs", PumpHistoryEntryGroup.Configuration), // ? + ReadCaptureEventEnabled(0xf1.toByte(), "Read Capture Event Enabled", PumpHistoryEntryGroup.Configuration), // ? + ChangeCaptureEventEnable2(0xf2.toByte(), "Change Capture Event Enable2", PumpHistoryEntryGroup.Configuration), // ? + ReadOtherDevicesStatus(0xf3.toByte(), "Read Other Devices Status", PumpHistoryEntryGroup.Configuration), // ? + TempBasalCombined(0xfe.toByte(), "TBR", PumpHistoryEntryGroup.Basal), // + UnknownBasePacket(0xff.toByte(), "Unknown Base Packet", PumpHistoryEntryGroup.Unknown); + + companion object { + private val opCodeMap: MutableMap = HashMap() + fun setSpecialRulesForEntryTypes() { + EndResultTotals.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 3)) + Bolus.addSpecialRuleHead(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 8)) + BolusWizardSetup.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 137)) + BolusWizard.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 15)) + BolusReminder.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 2)) + ChangeSensorSetup2.addSpecialRuleBody(SpecialRule(MedtronicDeviceType.Medtronic_523andHigher, 34)) + } + + @JvmStatic fun getByCode(opCode: Byte): PumpHistoryEntryType? { + return if (opCodeMap.containsKey(opCode)) { + opCodeMap[opCode] + } else { + UnknownBasePacket + } + } + + // + // private PumpHistoryEntryType(int opCode, String name, int head, int date, + // int body) + // { + // this.opCode = (byte) opCode; + // this.description = name; + // this.headLength = head; + // this.dateLength = date; + // this.bodyLength = body; + // this.totalLength = (head + date + body); + // } + // + fun isAAPSRelevantEntry(entryType: PumpHistoryEntryType): Boolean { + return entryType == Bolus || // Treatments + entryType == TempBasalRate || // + entryType == TempBasalDuration || // + entryType == Prime || // Pump Status Change + entryType == SuspendPump || // + entryType == ResumePump || // + entryType == Rewind || // + entryType == NoDeliveryAlarm || // no delivery + entryType == BasalProfileStart || // + entryType == ChangeTime || // Time Change + entryType == NewTimeSet || // + entryType == ChangeBasalPattern || // Configuration + entryType == ClearSettings || // + entryType == SaveSettings || // + entryType == ChangeMaxBolus || // + entryType == ChangeMaxBasal || // + entryType == ChangeTempBasalType || // + entryType == ChangeBasalProfile_NewProfile || // Basal profile + entryType == DailyTotals515 || // Daily Totals + entryType == DailyTotals522 || // + entryType == DailyTotals523 || // + entryType == EndResultTotals + } + + val isRelevantEntry: Boolean + get() = true + + init { + for (type in values()) { + opCodeMap[type.code] = type + } + setSpecialRulesForEntryTypes() + } + } + + val code: Byte + private val description: String? + private val headLength: Int + val dateLength: Int + + // private MinimedDeviceType deviceType; + private val bodyLength: Int + private val totalLength: Int + + // special rules need to be put in list from highest to lowest (e.g.: + // 523andHigher=12, 515andHigher=10 and default (set in cnstr) would be 8) + private var specialRulesHead: MutableList? = null + private var specialRulesBody: MutableList? = null + private var hasSpecialRules = false + val group: PumpHistoryEntryGroup + + private constructor(opCode: Byte, group: PumpHistoryEntryGroup) : this(opCode, null, group, 2, 5, 0) {} + private constructor(opCode: Byte, group: PumpHistoryEntryGroup, head: Int, date: Int, body: Int) : this(opCode, null, group, head, date, body) {} + + fun getTotalLength(medtronicDeviceType: MedtronicDeviceType?): Int { + return if (hasSpecialRules()) { + getHeadLength(medtronicDeviceType) + getBodyLength(medtronicDeviceType) + dateLength + } else { + totalLength + } + } + + private fun hasSpecialRules(): Boolean { + return hasSpecialRules + } + + fun addSpecialRuleHead(rule: SpecialRule) { + if (isEmpty(specialRulesHead)) { + specialRulesHead = ArrayList() + } + specialRulesHead!!.add(rule) + hasSpecialRules = true + } + + fun addSpecialRuleBody(rule: SpecialRule) { + if (isEmpty(specialRulesBody)) { + specialRulesBody = ArrayList() + } + specialRulesBody!!.add(rule) + hasSpecialRules = true + } + + fun getDescription(): String { + return description ?: name + } + + fun getHeadLength(medtronicDeviceType: MedtronicDeviceType?): Int { + return if (hasSpecialRules) { + if (isNotEmpty(specialRulesHead)) { + determineSizeByRule(medtronicDeviceType, headLength, specialRulesHead) + } else { + headLength + } + } else { + headLength + } + } + + fun getBodyLength(medtronicDeviceType: MedtronicDeviceType?): Int { + return if (hasSpecialRules) { + if (isNotEmpty(specialRulesBody)) { + determineSizeByRule(medtronicDeviceType, bodyLength, specialRulesBody) + } else { + bodyLength + } + } else { + bodyLength + } + } + + private fun isNotEmpty(list: List<*>?): Boolean { + return list != null && !list.isEmpty() + } + + private fun isEmpty(list: List<*>?): Boolean { + return list == null || list.isEmpty() + } + + // byte[] dh = { 2, 3 }; + private fun determineSizeByRule(medtronicDeviceType: MedtronicDeviceType?, defaultValue: Int, rules: List?): Int { + var size = defaultValue + for (rule in rules!!) { + if (MedtronicDeviceType.isSameDevice(medtronicDeviceType, rule.deviceType)) { + size = rule.size + break + } + } + return size + } + + class SpecialRule internal constructor(var deviceType: MedtronicDeviceType, var size: Int) + + init { + this.code = opCode //as Byte.toInt() + description = name + headLength = head + dateLength = date + bodyLength = body + totalLength = head + date + body + this.group = group + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java deleted file mode 100644 index 4bb67cfb3e..0000000000 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.java +++ /dev/null @@ -1,177 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import info.nightscout.androidaps.logging.AAPSLogger; -import info.nightscout.androidaps.logging.LTag; -import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil; - -/** - * History page contains data, sorted from newest to oldest (0=newest..n=oldest) - *

- * Created by andy on 9/23/18. - */ -public class PumpHistoryResult { - - private final AAPSLogger aapsLogger; - - private boolean searchFinished = false; - private final PumpHistoryEntry searchEntry = null; - private Long searchDate = null; - private SearchType searchType = SearchType.None; - public List unprocessedEntries; - public List validEntries; - - - public PumpHistoryResult(AAPSLogger aapsLogger, PumpHistoryEntry searchEntry, Long targetDate) { - this.aapsLogger = aapsLogger; - if (searchEntry != null) { - /* - * this.searchEntry = searchEntry; - * this.searchType = SearchType.LastEntry; - * aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Search parameters: Last Entry: " + searchEntry.atechDateTime + " type=" - * + searchEntry.getEntryType().name()); - */ - this.searchDate = searchEntry.atechDateTime; - this.searchType = SearchType.Date; - aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date(with searchEntry): " + targetDate); - } else if (targetDate != null) { - this.searchDate = targetDate; - this.searchType = SearchType.Date; - aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date: " + targetDate); - } - - // this.unprocessedEntries = new ArrayList<>(); - this.validEntries = new ArrayList<>(); - } - - - public void addHistoryEntries(List entries, int page) { - this.unprocessedEntries = entries; - //aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Unprocessed entries: {}", MedtronicUtil.getGsonInstance().toJson(entries)); - processEntries(); - } - - // TODO Bug #145 need to check if we had timeChange that went -1, that situation needs to be evaluated separately - public void processEntries() { - int olderEntries = 0; - - Collections.reverse(this.unprocessedEntries); - - switch (searchType) { - case None: - //aapsLogger.debug(LTag.PUMPCOMM,"PE. None search"); - this.validEntries.addAll(this.unprocessedEntries); - break; - - case LastEntry: { - aapsLogger.debug(LTag.PUMPCOMM, "PE. Last entry search"); - - //Collections.sort(this.unprocessedEntries, new PumpHistoryEntry.Comparator()); - - aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: " + searchEntry.atechDateTime); - - Long date = searchEntry.atechDateTime; - - for (PumpHistoryEntry unprocessedEntry : unprocessedEntries) { - - if (unprocessedEntry.equals(searchEntry)) { - //aapsLogger.debug(LTag.PUMPCOMM,"PE. Item found {}.", unprocessedEntry); - searchFinished = true; - break; - } - - //aapsLogger.debug(LTag.PUMPCOMM,"PE. Entry {} added.", unprocessedEntry); - this.validEntries.add(unprocessedEntry); - } - } - break; - case Date: { - aapsLogger.debug(LTag.PUMPCOMM, "PE. Date search: Search date: " + this.searchDate); - - - for (PumpHistoryEntry unprocessedEntry : unprocessedEntries) { - - if (unprocessedEntry.atechDateTime == null || unprocessedEntry.atechDateTime == 0) { - aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: Entry with no date: " + unprocessedEntry); - continue; - } - - if (unprocessedEntry.isAfter(this.searchDate)) { - this.validEntries.add(unprocessedEntry); - } else { -// aapsLogger.debug(LTag.PUMPCOMM,"PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", -// DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); - if (DateTimeUtil.getYear(unprocessedEntry.atechDateTime) > 2015) - olderEntries++; - } - } - - if (olderEntries > 0) { - //Collections.sort(this.validEntries, new PumpHistoryEntry.Comparator()); - - searchFinished = true; - } - } - break; - - } // switch - - //aapsLogger.debug(LTag.PUMPCOMM,"PE. Valid Entries: {}", validEntries); - } - - - public String toString() { - return "PumpHistoryResult [unprocessed=" + (unprocessedEntries != null ? "" + unprocessedEntries.size() : "0") + // - ", valid=" + (validEntries != null ? "" + validEntries.size() : "0") + // - ", searchEntry=" + searchEntry + // - ", searchDate=" + searchDate + // - ", searchType=" + searchType + // - ", searchFinished=" + searchFinished + // - "]"; - - } - - - /** - * Return latest entry (entry with highest date time) - * - * @return - */ - public PumpHistoryEntry getLatestEntry() { - if (this.validEntries == null || this.validEntries.size() == 0) - return null; - else { - return this.validEntries.get(0); - // PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); - // - // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) - // return pumpHistoryEntry; - // else - // return this.validEntries.get(1); - } - } - - - public boolean isSearchRequired() { - return searchType != SearchType.None; - } - - - public boolean isSearchFinished() { - return searchFinished; - } - - - public List getValidEntries() { - return validEntries; - } - - enum SearchType { - None, // - LastEntry, // - Date - } -} diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt new file mode 100644 index 0000000000..0ab0e7e05e --- /dev/null +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/comm/history/pump/PumpHistoryResult.kt @@ -0,0 +1,144 @@ +package info.nightscout.androidaps.plugins.pump.medtronic.comm.history.pump + +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil +import java.util.* + +/** + * History page contains data, sorted from newest to oldest (0=newest..n=oldest) + * + * + * Created by andy on 9/23/18. + */ +class PumpHistoryResult(private val aapsLogger: AAPSLogger, searchEntry: PumpHistoryEntry?, targetDate: Long?) { + + var isSearchFinished = false + private set + private val searchEntry: PumpHistoryEntry? = null + private var searchDate: Long? = null + private var searchType = SearchType.None + @JvmField var unprocessedEntries: List? = null + @JvmField var validEntries: MutableList? + fun addHistoryEntries(entries: List?, page: Int) { + unprocessedEntries = entries + //aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Unprocessed entries: {}", MedtronicUtil.getGsonInstance().toJson(entries)); + processEntries() + } + + // TODO Bug #145 need to check if we had timeChange that went -1, that situation needs to be evaluated separately + fun processEntries() { + var olderEntries = 0 + Collections.reverse(unprocessedEntries) + when (searchType) { + SearchType.None -> //aapsLogger.debug(LTag.PUMPCOMM,"PE. None search"); + validEntries!!.addAll(unprocessedEntries!!) + + SearchType.LastEntry -> { + aapsLogger.debug(LTag.PUMPCOMM, "PE. Last entry search") + + //Collections.sort(this.unprocessedEntries, new PumpHistoryEntry.Comparator()); + aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: " + searchEntry!!.atechDateTime) + val date = searchEntry.atechDateTime + for (unprocessedEntry in unprocessedEntries!!) { + if (unprocessedEntry!!.equals(searchEntry)) { + //aapsLogger.debug(LTag.PUMPCOMM,"PE. Item found {}.", unprocessedEntry); + isSearchFinished = true + break + } + + //aapsLogger.debug(LTag.PUMPCOMM,"PE. Entry {} added.", unprocessedEntry); + validEntries!!.add(unprocessedEntry) + } + } + + SearchType.Date -> { + aapsLogger.debug(LTag.PUMPCOMM, "PE. Date search: Search date: " + searchDate) + for (unprocessedEntry in unprocessedEntries!!) { + if (unprocessedEntry!!.atechDateTime == null || unprocessedEntry.atechDateTime == 0L) { + aapsLogger.debug(LTag.PUMPCOMM, "PE. PumpHistoryResult. Search entry date: Entry with no date: $unprocessedEntry") + continue + } + if (unprocessedEntry.isAfter(searchDate!!)) { + validEntries!!.add(unprocessedEntry) + } else { +// aapsLogger.debug(LTag.PUMPCOMM,"PE. PumpHistoryResult. Not after.. Unprocessed Entry [year={},entry={}]", +// DateTimeUtil.getYear(unprocessedEntry.atechDateTime), unprocessedEntry); + if (DateTimeUtil.getYear(unprocessedEntry.atechDateTime) > 2015) olderEntries++ + } + } + if (olderEntries > 0) { + //Collections.sort(this.validEntries, new PumpHistoryEntry.Comparator()); + isSearchFinished = true + } + } + } + + //aapsLogger.debug(LTag.PUMPCOMM,"PE. Valid Entries: {}", validEntries); + } + + override fun toString(): String { + return "PumpHistoryResult [unprocessed=" + (if (unprocessedEntries != null) "" + unprocessedEntries!!.size else "0") + // + ", valid=" + (if (validEntries != null) "" + validEntries!!.size else "0") + // + ", searchEntry=" + searchEntry + // + ", searchDate=" + searchDate + // + ", searchType=" + searchType + // + ", searchFinished=" + isSearchFinished + // + "]" + }// PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); + // + // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) + // return pumpHistoryEntry; + // else + // return this.validEntries.get(1); + + /** + * Return latest entry (entry with highest date time) + * + * @return + */ + val latestEntry: PumpHistoryEntry? + get() = if (validEntries == null || validEntries!!.size == 0) null else { + validEntries!![0] + // PumpHistoryEntry pumpHistoryEntry = this.validEntries.get(0); + // + // if (pumpHistoryEntry.getEntryType() == PumpHistoryEntryType.EndResultTotals) + // return pumpHistoryEntry; + // else + // return this.validEntries.get(1); + } + + val isSearchRequired: Boolean + get() = searchType != SearchType.None + + fun getValidEntries(): List? { + return validEntries + } + + internal enum class SearchType { + None, // + LastEntry, // + Date + } + + init { + if (searchEntry != null) { + /* + * this.searchEntry = searchEntry; + * this.searchType = SearchType.LastEntry; + * aapsLogger.debug(LTag.PUMPCOMM,"PumpHistoryResult. Search parameters: Last Entry: " + searchEntry.atechDateTime + " type=" + * + searchEntry.getEntryType().name()); + */ + searchDate = searchEntry.atechDateTime + searchType = SearchType.Date + aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date(with searchEntry): $targetDate") + } else if (targetDate != null) { + searchDate = targetDate + searchType = SearchType.Date + aapsLogger.debug(LTag.PUMPCOMM, "PumpHistoryResult. Search parameters: Date: $targetDate") + } + + // this.unprocessedEntries = new ArrayList<>(); + validEntries = ArrayList() + } +} \ No newline at end of file diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java index 697b74aa74..ae15a51c07 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/dto/DailyTotalsDTO.java @@ -74,15 +74,15 @@ public class DailyTotalsDTO { break; case DailyTotals515: - decodeDailyTotals515(entry.getBody()); + decodeDailyTotals515(entry.body); break; case DailyTotals522: - decodeDailyTotals522(entry.getBody()); + decodeDailyTotals522(entry.body); break; case DailyTotals523: - decodeDailyTotals523(entry.getBody()); + decodeDailyTotals523(entry.body); break; default: @@ -96,18 +96,18 @@ public class DailyTotalsDTO { private void setDisplayable() { if (this.insulinBasal == null) { - this.entry.setDisplayableValue("Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); + this.entry.displayableValue = "Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2); } else { - this.entry.setDisplayableValue("Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) - + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2)); + this.entry.displayableValue = "Basal Insulin: " + StringUtil.getFormatedValueUS(this.insulinBasal, 2) + + ", Total Insulin: " + StringUtil.getFormatedValueUS(this.insulinTotal, 2); } } private void decodeEndResultsTotals(PumpHistoryEntry entry) { - double totals = ByteUtil.toInt((int) entry.getHead()[0], (int) entry.getHead()[1], (int) entry.getHead()[2], - (int) entry.getHead()[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; + double totals = ByteUtil.toInt((int) entry.head[0], (int) entry.head[1], (int) entry.head[2], + (int) entry.head[3], ByteUtil.BitConversion.BIG_ENDIAN) * 0.025d; this.insulinTotal = totals; diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java index fc986f4f83..a2ce6c00e7 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/dialog/MedtronicHistoryActivity.java @@ -59,7 +59,7 @@ public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { this.filteredHistoryList.addAll(list); } else { for (PumpHistoryEntry pumpHistoryEntry : list) { - if (pumpHistoryEntry.getEntryType().getGroup() == group) { + if (pumpHistoryEntry.getEntryType().group == group) { this.filteredHistoryList.add(pumpHistoryEntry); } } @@ -214,7 +214,7 @@ public class MedtronicHistoryActivity extends NoSplashAppCompatActivity { if (record != null) { holder.timeView.setText(record.getDateTimeString()); holder.typeView.setText(record.getEntryType().getDescription()); - holder.valueView.setText(record.getDisplayableValue()); + holder.valueView.setText(record.displayableValue); } } diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java deleted file mode 100644 index 70a484d5d6..0000000000 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.java +++ /dev/null @@ -1,66 +0,0 @@ -package info.nightscout.androidaps.plugins.pump.common.defs; - -import java.util.ArrayList; -import java.util.List; - - -import info.nightscout.androidaps.core.R; -import info.nightscout.androidaps.utils.resources.ResourceHelper; - - -/** - * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes - * management and modified/extended for AAPS. - *

- * Author: Andy {andy.rozman@gmail.com} - */ - -public enum PumpHistoryEntryGroup { - - All(R.string.history_group_all), - Bolus(R.string.history_group_bolus), - Basal(R.string.history_group_basal), - Prime(R.string.history_group_prime), - Configuration(R.string.history_group_configuration), - Alarm(R.string.history_group_alarm), - Glucose(R.string.history_group_glucose), - Notification(R.string.history_group_notification), - Statistic(R.string.history_group_statistic), - Unknown(R.string.history_group_unknown), - ; - - private final int resourceId; - private String translated; - - private static List translatedList; - - PumpHistoryEntryGroup(int resourceId) { - this.resourceId = resourceId; - } - - private static void doTranslation(ResourceHelper resourceHelper) { - translatedList = new ArrayList<>(); - - for (PumpHistoryEntryGroup pumpHistoryEntryGroup : values()) { - pumpHistoryEntryGroup.translated = resourceHelper.gs(pumpHistoryEntryGroup.resourceId); - translatedList.add(pumpHistoryEntryGroup); - } - } - - public static List getTranslatedList(ResourceHelper resourceHelper) { - if (translatedList == null) doTranslation(resourceHelper); - return translatedList; - } - - public int getResourceId() { - return resourceId; - } - - public String getTranslated() { - return translated; - } - - public String toString() { - return this.translated; - } -} diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt new file mode 100644 index 0000000000..8b856d7036 --- /dev/null +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/defs/PumpHistoryEntryGroup.kt @@ -0,0 +1,50 @@ +package info.nightscout.androidaps.plugins.pump.common.defs + +import info.nightscout.androidaps.core.R +import info.nightscout.androidaps.utils.resources.ResourceHelper +import java.util.* + +/** + * This file was taken from GGC - GNU Gluco Control (ggc.sourceforge.net), application for diabetes + * management and modified/extended for AAPS. + * + * + * Author: Andy {andy.rozman@gmail.com} + */ +enum class PumpHistoryEntryGroup(val resourceId: Int) { + + All(R.string.history_group_all), + Bolus(R.string.history_group_bolus), + Basal(R.string.history_group_basal), + Prime(R.string.history_group_prime), + Configuration(R.string.history_group_configuration), + Alarm(R.string.history_group_alarm), + Glucose(R.string.history_group_glucose), + Notification(R.string.history_group_notification), + Statistic(R.string.history_group_statistic), + Unknown(R.string.history_group_unknown); + + var translated: String? = null + private set + + override fun toString(): String { + return translated!! + } + + companion object { + private var translatedList: MutableList? = null + private fun doTranslation(resourceHelper: ResourceHelper) { + translatedList = ArrayList() + for (pumpHistoryEntryGroup in values()) { + pumpHistoryEntryGroup.translated = resourceHelper.gs(pumpHistoryEntryGroup.resourceId) + (translatedList as ArrayList).add(pumpHistoryEntryGroup) + } + } + + @JvmStatic fun getTranslatedList(resourceHelper: ResourceHelper): List? { + if (translatedList == null) doTranslation(resourceHelper) + return translatedList + } + } + +} \ No newline at end of file diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java index 6273ff5203..da5e99596c 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/utils/ByteUtil.java @@ -29,9 +29,13 @@ public class ByteUtil { return (b < 0) ? b + 256 : b; } + public static int asUINT8(Integer b) { + return (b < 0) ? b + 256 : b; + } + public static byte[] getBytesFromInt16(int value) { byte[] array = getBytesFromInt(value); - return new byte[] {array[2], array[3]}; + return new byte[]{array[2], array[3]}; } public static byte[] getBytesFromInt(int value) { @@ -283,10 +287,54 @@ public class ByteUtil { } + /** + * Converts 4 (or less) ints into int. (Shorts are objects, so you can send null if you have less parameters) + * + * @param b1 short 1 + * @param b2 short 2 + * @param b3 short 3 + * @param b4 short 4 + * @param flag Conversion Flag (Big Endian, Little endian) + * @return int value + */ + public static int toInt(Byte b1, Byte b2, Byte b3, Byte b4, BitConversion flag) { + switch (flag) { + case LITTLE_ENDIAN: { + if (b4 != null) { + return (b4 & 0xff) << 24 | (b3 & 0xff) << 16 | (b2 & 0xff) << 8 | b1 & 0xff; + } else if (b3 != null) { + return (b3 & 0xff) << 16 | (b2 & 0xff) << 8 | b1 & 0xff; + } else if (b2 != null) { + return (b2 & 0xff) << 8 | b1 & 0xff; + } else { + return b1 & 0xff; + } + } + + default: + case BIG_ENDIAN: { + if (b4 != null) { + return (b1 & 0xff) << 24 | (b2 & 0xff) << 16 | (b3 & 0xff) << 8 | b4 & 0xff; + } else if (b3 != null) { + return (b1 & 0xff) << 16 | (b2 & 0xff) << 8 | b3 & 0xff; + } else if (b2 != null) { + return (b1 & 0xff) << 8 | b2 & 0xff; + } else { + return b1 & 0xff; + } + } + } + } + + public static int toInt(int b1, int b2) { return toInt(b1, b2, null, null, BitConversion.BIG_ENDIAN); } + public static int toInt(Byte b1, Byte b2) { + return toInt(b1, b2, null, null, BitConversion.BIG_ENDIAN); + } + public static int toInt(int b1, int b2, int b3) { return toInt(b1, b2, b3, null, BitConversion.BIG_ENDIAN); @@ -329,6 +377,25 @@ public class ByteUtil { } + public static String getCorrectHexValue(byte inp) { + String hx = Integer.toHexString((char) inp); + + if (hx.length() == 0) + return "00"; + else if (hx.length() == 1) + return "0" + hx; + else if (hx.length() == 2) + return hx; + else if (hx.length() == 4) + return hx.substring(2); + else { + System.out.println("Hex Error: " + inp); + } + + return null; + } + + public static String getHex(byte[] abyte0) { return abyte0 != null ? getHex(abyte0, abyte0.length) : null; }