diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt index b1a930cc6a..665b5c8f34 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/MedtronicPumpPlugin.kt @@ -1006,24 +1006,23 @@ class MedtronicPumpPlugin @Inject constructor( if (medtronicHistoryData.isTBRActive(runningTBR)) { val differenceTime = System.currentTimeMillis() - runningTBR.date - val tbrData = runningTBR.tbrData!! + //val tbrData = runningTBR val result = pumpSync.syncTemporaryBasalWithPumpId( runningTBR.date, - tbrData.rate, + runningTBR.rate, differenceTime, - tbrData.isAbsolute, - tbrData.tbrType, + runningTBR.isAbsolute, + runningTBR.tbrType, runningTBR.pumpId!!, runningTBR.pumpType, runningTBR.serialNumber) val differenceTimeMin = Math.floor(differenceTime / (60.0 * 1000.0)) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "canceling running TBR - syncTemporaryBasalWithPumpId [date=%d, pumpId=%d, rate=%.2f U, duration=%d, pumpSerial=%s] - Result: %b", - runningTBR.date, runningTBR.pumpId, - tbrData.rate, differenceTimeMin.toInt(), - medtronicPumpStatus.serialNumber, result)) + aapsLogger.debug(LTag.PUMP, "canceling running TBR - syncTemporaryBasalWithPumpId [date=${runningTBR.date}, " + + "pumpId=${runningTBR.pumpId}, rate=${runningTBR.rate} U, duration=${differenceTimeMin.toInt()}, " + + "pumpSerial=${medtronicPumpStatus.serialNumber}] - Result: $result") } } diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt index e558a22f88..e618b77037 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/data/MedtronicHistoryData.kt @@ -10,6 +10,7 @@ import info.nightscout.androidaps.logging.AAPSLogger import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.plugins.pump.common.defs.PumpType import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntry +import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryBolus import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR import info.nightscout.androidaps.plugins.pump.common.utils.DateTimeUtil import info.nightscout.androidaps.plugins.pump.common.utils.StringUtil @@ -490,17 +491,17 @@ class MedtronicHistoryData @Inject constructor( var temporaryId: Long? = null if (!multiwave) { - val entryWithTempId = findDbEntry(bolus, boluses) + val entryWithTempId = findDbEntry(bolus, boluses as MutableList) as PumpDbEntryBolus? aapsLogger.debug(LTag.PUMP, "DD: entryWithTempId=$entryWithTempId") if (entryWithTempId != null) { - aapsLogger.debug(LTag.PUMP, String.format("DD: entryWithTempId.bolusData=%s", if (entryWithTempId.bolusData == null) "null" else entryWithTempId.bolusData)) + //aapsLogger.debug(LTag.PUMP, String.format("DD: entryWithTempId.bolusData=%s", if (entryWithTempId.bolusData == null) "null" else entryWithTempId.bolusData)) temporaryId = entryWithTempId.temporaryId pumpSyncStorage.removeBolusWithTemporaryId(temporaryId) boluses.remove(entryWithTempId) - type = entryWithTempId.bolusData!!.bolusType + type = entryWithTempId.bolusType } } @@ -619,7 +620,7 @@ class MedtronicHistoryData @Inject constructor( aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemOne: " + gson.toJson(tempBasalProcessDTO.itemOne)) aapsLogger.debug(LTag.PUMP, "DD: tempBasalProcessDTO.itemTwo: " + (if (tempBasalProcessDTO.itemTwo == null) "null" else gson.toJson(tempBasalProcessDTO.itemTwo!!))) - val entryWithTempId = findDbEntry(tempBasalProcessDTO.itemOne, tbrRecords) + val entryWithTempId = findDbEntry(tempBasalProcessDTO.itemOne, tbrRecords as MutableList) as PumpDbEntryTBR? aapsLogger.debug(LTag.PUMP, "DD: entryWithTempId: " + (if (entryWithTempId == null) "null" else entryWithTempId.toString())) @@ -697,16 +698,16 @@ class MedtronicHistoryData @Inject constructor( if (isTBRActive(startTimestamp = tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime), durationSeconds = tempBasalProcessDTO.durationAsSeconds)) { if (medtronicPumpStatus.runningTBR == null) { - medtronicPumpStatus.runningTBR = info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntry(0L, - tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime), - medtronicPumpStatus.pumpType, - medtronicPumpStatus.serialNumber, - null, - PumpDbEntryTBR(rate = tbrEntry.insulinRate, + medtronicPumpStatus.runningTBR = PumpDbEntryTBR( + temporaryId = 0L, + date = tryToGetByLocalTime(tempBasalProcessDTO.atechDateTime), + pumpType = medtronicPumpStatus.pumpType, + serialNumber = medtronicPumpStatus.serialNumber, + entry = PumpDbEntryTBR(rate = tbrEntry.insulinRate, isAbsolute = !tbrEntry.isPercent, durationInSeconds = tempBasalProcessDTO.durationAsSeconds, tbrType = PumpSync.TemporaryBasalType.NORMAL), - tempBasalProcessDTO.pumpId) + pumpId = tempBasalProcessDTO.pumpId) } } } else { @@ -717,10 +718,12 @@ class MedtronicHistoryData @Inject constructor( } // collection } - fun isTBRActive(dbEntry: PumpDbEntry): Boolean { + + + fun isTBRActive(dbEntry: PumpDbEntryTBR): Boolean { return isTBRActive( startTimestamp = dbEntry.date, - durationSeconds = dbEntry.tbrData!!.durationInSeconds) + durationSeconds = dbEntry.durationInSeconds) } fun isTBRActive(startTimestamp: Long, durationSeconds: Int): Boolean { diff --git a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt index 7372363ff1..c417a22a1d 100644 --- a/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt +++ b/medtronic/src/main/java/info/nightscout/androidaps/plugins/pump/medtronic/driver/MedtronicPumpStatus.kt @@ -7,6 +7,7 @@ import info.nightscout.androidaps.plugins.pump.common.events.EventRileyLinkDevic import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.data.RLHistoryItem import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.defs.RileyLinkTargetDevice +import info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntryTBR import info.nightscout.androidaps.plugins.pump.medtronic.defs.BasalProfileStatus import info.nightscout.androidaps.plugins.pump.medtronic.defs.BatteryType import info.nightscout.androidaps.plugins.pump.medtronic.defs.MedtronicDeviceType @@ -32,7 +33,7 @@ class MedtronicPumpStatus @Inject constructor(private val resourceHelper: Resour var pumpFrequency: String? = null var maxBolus: Double? = null var maxBasal: Double? = null - var runningTBR: info.nightscout.androidaps.plugins.pump.common.sync.PumpDbEntry? = null + var runningTBR: PumpDbEntryTBR? = null // statuses var pumpDeviceState = PumpDeviceState.NeverContacted diff --git a/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt b/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt index 918fc9d3ee..3061e9566a 100644 --- a/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt +++ b/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpDbEntry.kt @@ -4,45 +4,75 @@ import info.nightscout.androidaps.data.DetailedBolusInfo import info.nightscout.androidaps.interfaces.PumpSync import info.nightscout.androidaps.plugins.pump.common.defs.PumpType -data class PumpDbEntry constructor(var temporaryId: Long, - var date: Long, - var pumpType: PumpType, - var serialNumber: String, - var bolusData: PumpDbEntryBolus? = null, - var tbrData: PumpDbEntryTBR? = null, - var pumpId: Long? = null) { +// data class PumpDbEntry constructor(var temporaryId: Long, +// var date: Long, +// var pumpType: PumpType, +// var serialNumber: String, +// var bolusData: PumpDbEntryBolus? = null, +// var tbrData: PumpDbEntryTBR? = null, +// var pumpId: Long? = null) { +// +// constructor(temporaryId: Long, +// date: Long, +// pumpType: PumpType, +// serialNumber: String, +// detailedBolusInfo: DetailedBolusInfo) : this(temporaryId, date, pumpType, serialNumber) { +// this.bolusData = PumpDbEntryBolus( +// detailedBolusInfo.insulin, +// detailedBolusInfo.carbs, +// detailedBolusInfo.bolusType) +// } +// +// constructor(temporaryId: Long, +// date: Long, +// pumpType: PumpType, +// serialNumber: String, +// rate: Double, +// isAbsolute: Boolean, +// durationInMinutes: Int, +// tbrType: PumpSync.TemporaryBasalType) : this(temporaryId, date, pumpType, serialNumber) { +// this.tbrData = PumpDbEntryTBR( +// rate, +// isAbsolute, +// durationInMinutes, +// tbrType) +// } +// +// } - constructor(temporaryId: Long, - date: Long, - pumpType: PumpType, - serialNumber: String, - detailedBolusInfo: DetailedBolusInfo) : this(temporaryId, date, pumpType, serialNumber) { - this.bolusData = PumpDbEntryBolus( - detailedBolusInfo.insulin, - detailedBolusInfo.carbs, - detailedBolusInfo.bolusType) - } - - constructor(temporaryId: Long, - date: Long, - pumpType: PumpType, - serialNumber: String, - rate: Double, - isAbsolute: Boolean, - durationInMinutes: Int, - tbrType: PumpSync.TemporaryBasalType) : this(temporaryId, date, pumpType, serialNumber) { - this.tbrData = PumpDbEntryTBR( - rate, - isAbsolute, - durationInMinutes, - tbrType) - } +interface PumpDbEntry { + var temporaryId: Long + var date: Long + var pumpType: PumpType + var serialNumber: String + var pumpId: Long? } -data class PumpDbEntryBolus(var insulin: Double, + + +data class PumpDbEntryBolus(override var temporaryId: Long, + override var date: Long, + override var pumpType: PumpType, + override var serialNumber: String, + override var pumpId: Long? = null, + var insulin: Double, var carbs: Double, - var bolusType: DetailedBolusInfo.BolusType) + var bolusType: DetailedBolusInfo.BolusType) : PumpDbEntry { + + constructor(temporaryId: Long, + date: Long, + pumpType: PumpType, + serialNumber: String, + detailedBolusInfo: DetailedBolusInfo) : this(temporaryId, date, pumpType, serialNumber, null, + detailedBolusInfo.insulin, + detailedBolusInfo.carbs, + detailedBolusInfo.bolusType) { + + } + + +} data class PumpDbEntryCarbs(var date: Long, var carbs: Double, @@ -57,7 +87,29 @@ data class PumpDbEntryCarbs(var date: Long, creator.serialNumber()) } -data class PumpDbEntryTBR(var rate: Double, +data class PumpDbEntryTBR(override var temporaryId: Long, + override var date: Long, + override var pumpType: PumpType, + override var serialNumber: String, + override var pumpId: Long? = null, + var rate: Double, var isAbsolute: Boolean, var durationInSeconds: Int, - var tbrType: PumpSync.TemporaryBasalType) \ No newline at end of file + var tbrType: PumpSync.TemporaryBasalType) : PumpDbEntry { + + constructor(rate: Double, + isAbsolute: Boolean, + durationInSeconds: Int, + tbrType: PumpSync.TemporaryBasalType) : this(0, 0, PumpType.GENERIC_AAPS, "", null, + rate, isAbsolute, durationInSeconds, tbrType) + + constructor(temporaryId: Long, + date: Long, + pumpType: PumpType, + serialNumber: String, + entry: PumpDbEntryTBR, + pumpId: Long? + ) : this(temporaryId, date, pumpType, serialNumber, pumpId, + entry.rate, entry.isAbsolute, entry.durationInSeconds, entry.tbrType) + +} \ No newline at end of file diff --git a/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt b/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt index ef8866d040..a4b244dae3 100644 --- a/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt +++ b/pump-common/src/main/java/info/nightscout/androidaps/plugins/pump/common/sync/PumpSyncStorage.kt @@ -22,13 +22,13 @@ class PumpSyncStorage @Inject constructor( ) { companion object { - - const val pumpSyncStorageKey: String = "pump_sync_storage_xstream_v2" - const val TBR: String = "TBR" - const val BOLUS: String = "BOLUS" + const val pumpSyncStorageBolusKey: String = "pump_sync_storage_bolus" + const val pumpSyncStorageTBRKey: String = "pump_sync_storage_tbr" } - var pumpSyncStorage: MutableMap> = mutableMapOf() + var pumpSyncStorageBolus: MutableList = mutableListOf() + var pumpSyncStorageTBR: MutableList = mutableListOf() + private var storageInitialized: Boolean = false private var xstream: XStream = XStream() @@ -41,38 +41,58 @@ class PumpSyncStorage @Inject constructor( if (storageInitialized) return - var loaded = false + xstream.addPermission(AnyTypePermission.ANY) - if (sp.contains(pumpSyncStorageKey)) { - val jsonData: String = sp.getString(pumpSyncStorageKey, "") + if (sp.contains(pumpSyncStorageBolusKey)) { + val jsonData: String = sp.getString(pumpSyncStorageBolusKey, "") if (jsonData.isNotBlank()) { - xstream.addPermission(AnyTypePermission.ANY) @Suppress("UNCHECKED_CAST") - pumpSyncStorage = xstream.fromXML(jsonData, MutableMap::class.java) as MutableMap> + pumpSyncStorageBolus = xstream.fromXML(jsonData, MutableList::class.java) as + MutableList - aapsLogger.debug(LTag.PUMP, String.format("Loading Pump Sync Storage: boluses=%d, tbrs=%d.", pumpSyncStorage[BOLUS]!!.size, pumpSyncStorage[TBR]!!.size)) - aapsLogger.debug(LTag.PUMP, "DD: PumpSyncStorage=$pumpSyncStorage") - - loaded = true + aapsLogger.debug(LTag.PUMP, "Loading Pump Sync Storage Bolus: boluses=${pumpSyncStorageBolus.size}") + aapsLogger.debug(LTag.PUMP, "DD: PumpSyncStorageBolus=$pumpSyncStorageBolus") } } - if (!loaded) { - pumpSyncStorage[BOLUS] = mutableListOf() - pumpSyncStorage[TBR] = mutableListOf() + if (sp.contains(pumpSyncStorageTBRKey)) { + val jsonData: String = sp.getString(pumpSyncStorageTBRKey, "") + + if (jsonData.isNotBlank()) { + @Suppress("UNCHECKED_CAST") + pumpSyncStorageTBR = xstream.fromXML(jsonData, MutableList::class.java) as + MutableList + + aapsLogger.debug(LTag.PUMP, "Loading Pump Sync Storage: tbrs=${pumpSyncStorageTBR.size}.") + aapsLogger.debug(LTag.PUMP, "DD: PumpSyncStorageTBR=$pumpSyncStorageTBR") + } + } + storageInitialized = true + } + + fun saveStorageBolus() { + if (!pumpSyncStorageBolus.isEmpty()) { + sp.putString(pumpSyncStorageBolusKey, xstream.toXML(pumpSyncStorageBolus)) + aapsLogger.debug(LTag.PUMP,"Saving Pump Sync Storage: boluses=${pumpSyncStorageBolus.size}") + } else { + if (sp.contains(pumpSyncStorageBolusKey)) + sp.remove(pumpSyncStorageBolusKey) } } - fun saveStorage() { - if (!isStorageEmpty()) { - sp.putString(pumpSyncStorageKey, xstream.toXML(pumpSyncStorage)) - aapsLogger.debug(String.format("Saving Pump Sync Storage: boluses=%d, tbrs=%d.", pumpSyncStorage[BOLUS]!!.size, pumpSyncStorage[TBR]!!.size)) + fun saveStorageTBR() { + if (!pumpSyncStorageTBR.isEmpty()) { + sp.putString(pumpSyncStorageTBRKey, xstream.toXML(pumpSyncStorageTBR)) + aapsLogger.debug(LTag.PUMP, "Saving Pump Sync Storage: tbr=${pumpSyncStorageTBR.size}") + } else { + if (sp.contains(pumpSyncStorageTBRKey)) + sp.remove(pumpSyncStorageTBRKey) } } private fun cleanOldStorage() { - val oldSpKeys = setOf("pump_sync_storage", "pump_sync_storage_xstream") + val oldSpKeys = setOf("pump_sync_storage", "pump_sync_storage_xstream", "pump_sync_storage_xstream_v2") for (oldSpKey in oldSpKeys) { if (sp.contains(oldSpKey)) @@ -80,16 +100,12 @@ class PumpSyncStorage @Inject constructor( } } - private fun isStorageEmpty(): Boolean { - return pumpSyncStorage[BOLUS]!!.isEmpty() && pumpSyncStorage[TBR]!!.isEmpty() + fun getBoluses(): MutableList { + return pumpSyncStorageBolus } - fun getBoluses(): MutableList { - return pumpSyncStorage[BOLUS]!! - } - - fun getTBRs(): MutableList { - return pumpSyncStorage[TBR]!! + fun getTBRs(): MutableList { + return pumpSyncStorageTBR } fun addBolusWithTempId(detailedBolusInfo: DetailedBolusInfo, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator): Boolean { @@ -102,24 +118,25 @@ class PumpSyncStorage @Inject constructor( creator.model(), creator.serialNumber()) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "addBolusWithTempId [date=%d, temporaryId=%d, insulin=%.2f, type=%s, pumpSerial=%s] - Result: %b", - detailedBolusInfo.timestamp, temporaryId, detailedBolusInfo.insulin, detailedBolusInfo.bolusType, - creator.serialNumber(), result)) + aapsLogger.debug(LTag.PUMP, "addBolusWithTempId [date=${detailedBolusInfo.timestamp}, temporaryId=$temporaryId, " + + "insulin=${detailedBolusInfo.insulin}, type=${detailedBolusInfo.bolusType}, pumpSerial=${creator.serialNumber()}] - " + + "Result: $result") if (detailedBolusInfo.carbs > 0.0) { addCarbs(PumpDbEntryCarbs(detailedBolusInfo, creator)) } if (result && writeToInternalHistory) { - val innerList: MutableList = pumpSyncStorage[BOLUS]!! + val dbEntry = PumpDbEntryBolus(temporaryId = temporaryId, + date = detailedBolusInfo.timestamp, + pumpType = creator.model(), + serialNumber = creator.serialNumber(), + detailedBolusInfo = detailedBolusInfo) - val dbEntry = PumpDbEntry(temporaryId, detailedBolusInfo.timestamp, creator.model(), creator.serialNumber(), detailedBolusInfo) + aapsLogger.debug("PumpDbEntryBolus: $dbEntry") - aapsLogger.debug("PumpDbEntry: $dbEntry") - - innerList.add(dbEntry) - pumpSyncStorage[BOLUS] = innerList - saveStorage() + pumpSyncStorageBolus.add(dbEntry) + saveStorageBolus() } return result } @@ -132,8 +149,8 @@ class PumpSyncStorage @Inject constructor( carbsDto.pumpType, carbsDto.serialNumber) - aapsLogger.debug(LTag.PUMP, String.format(Locale.ENGLISH, "syncCarbsWithTimestamp [date=%d, carbs=%.2f, pumpSerial=%s] - Result: %b", - carbsDto.date, carbsDto.carbs, carbsDto.serialNumber, result)) + aapsLogger.debug(LTag.PUMP, "syncCarbsWithTimestamp [date=${carbsDto.date}, " + + "carbs=${carbsDto.carbs}, pumpSerial=${carbsDto.serialNumber}] - Result: $result") } fun addTemporaryBasalRateWithTempId(temporaryBasal: PumpDbEntryTBR, writeToInternalHistory: Boolean, creator: PumpSyncEntriesCreator): Boolean { @@ -151,42 +168,52 @@ class PumpSyncStorage @Inject constructor( creator.serialNumber()) if (response && writeToInternalHistory) { - val innerList: MutableList = pumpSyncStorage[TBR]!! + val dbEntry = PumpDbEntryTBR(temporaryId = temporaryId, + date = timeNow, + pumpType = creator.model(), + serialNumber = creator.serialNumber(), + entry = temporaryBasal, + pumpId=null) - innerList.add(PumpDbEntry(temporaryId, timeNow, creator.model(), creator.serialNumber(), null, temporaryBasal)) - pumpSyncStorage[BOLUS] = innerList - saveStorage() + aapsLogger.debug("PumpDbEntryTBR: $dbEntry") + + pumpSyncStorageTBR.add(dbEntry) + saveStorageTBR() } return response } fun removeBolusWithTemporaryId(temporaryId: Long) { - val bolusList = removeTemporaryId(temporaryId, pumpSyncStorage[BOLUS]!!) - pumpSyncStorage[BOLUS] = bolusList - saveStorage() - } + var dbEntry: PumpDbEntryBolus? = null - fun removeTemporaryBasalWithTemporaryId(temporaryId: Long) { - val tbrList = removeTemporaryId(temporaryId, pumpSyncStorage[TBR]!!) - pumpSyncStorage[TBR] = tbrList - saveStorage() - } - - private fun removeTemporaryId(temporaryId: Long, list: MutableList): MutableList { - var dbEntry: PumpDbEntry? = null - - for (pumpDbEntry in list) { + for (pumpDbEntry in pumpSyncStorageBolus) { if (pumpDbEntry.temporaryId == temporaryId) { dbEntry = pumpDbEntry } } if (dbEntry != null) { - list.remove(dbEntry) + pumpSyncStorageBolus.remove(dbEntry) } - return list + saveStorageBolus() + } + + fun removeTemporaryBasalWithTemporaryId(temporaryId: Long) { + var dbEntry: PumpDbEntryTBR? = null + + for (pumpDbEntry in pumpSyncStorageTBR) { + if (pumpDbEntry.temporaryId == temporaryId) { + dbEntry = pumpDbEntry + } + } + + if (dbEntry != null) { + pumpSyncStorageTBR.remove(dbEntry) + } + + saveStorageTBR() } } \ No newline at end of file diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/di/RileyLinkModule.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/di/RileyLinkModule.kt index ac6f4747ce..ffd25e97ea 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/di/RileyLinkModule.kt +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/di/RileyLinkModule.kt @@ -9,6 +9,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.command.S import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.command.SetPreamble import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioPacket import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.RadioResponse +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.device.OrangeLinkImpl import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusActivity import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusGeneralFragment import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyLinkStatusHistoryFragment @@ -30,6 +31,7 @@ abstract class RileyLinkModule { @ContributesAndroidInjector abstract fun sendAndListenProvider(): SendAndListen @ContributesAndroidInjector abstract fun setPreambleProvider(): SetPreamble @ContributesAndroidInjector abstract fun radioPacketProvider(): RadioPacket + @ContributesAndroidInjector abstract fun orangeLinkDeviceProvider(): OrangeLinkImpl @ContributesAndroidInjector abstract fun contributesRileyLinkStatusGeneral(): RileyLinkStatusGeneralFragment @ContributesAndroidInjector abstract fun contributesRileyLinkStatusHistoryFragment(): RileyLinkStatusHistoryFragment diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java index 61ffe6408e..9d832f7469 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RFSpy.java @@ -68,7 +68,7 @@ public class RFSpy { private final UUID radioDataUUID = UUID.fromString(GattAttributes.CHARA_RADIO_DATA); private final UUID radioVersionUUID = UUID.fromString(GattAttributes.CHARA_RADIO_VERSION); private final UUID batteryServiceUUID = UUID.fromString(GattAttributes.SERVICE_BATTERY); - private final UUID batteryLevelUUID = UUID.fromString(GattAttributes.CHARA_BATTERY_UNK); + private final UUID batteryLevelUUID = UUID.fromString(GattAttributes.CHARA_BATTERY_LEVEL); private String bleVersion; // We don't use it so no need of sofisticated logic private Double currentFrequencyMHz; private long nextBatteryCheck = 0; @@ -103,6 +103,10 @@ public class RFSpy { String cc1110Version = getCC1110Version(); rileyLinkServiceData.versionCC110 = cc1110Version; rileyLinkServiceData.firmwareVersion = getFirmwareVersion(aapsLogger, bleVersion, cc1110Version); + + aapsLogger.debug(LTag.PUMPBTCOMM, + String.format("RileyLink - BLE Version: %s, CC1110 Version: %s, Firmware Version: %s", + bleVersion, cc1110Version, rileyLinkServiceData.firmwareVersion)); } // Call this from the "response count" notification handler. diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java index 086f8aab9e..c365e2e3da 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/RileyLinkBLE.java @@ -8,19 +8,11 @@ import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattDescriptor; import android.bluetooth.BluetoothGattService; import android.bluetooth.BluetoothProfile; -import android.bluetooth.le.BluetoothLeScanner; -import android.bluetooth.le.ScanCallback; -import android.bluetooth.le.ScanFilter; -import android.bluetooth.le.ScanResult; -import android.bluetooth.le.ScanSettings; import android.content.Context; -import android.os.Handler; -import android.os.Message; import android.os.SystemClock; import org.apache.commons.lang3.StringUtils; -import java.util.ArrayList; import java.util.List; import java.util.Locale; import java.util.UUID; @@ -34,6 +26,7 @@ import info.nightscout.androidaps.logging.LTag; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkConst; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.GattAttributes; +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.device.OrangeLinkImpl; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperation; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperationResult; import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.CharacteristicReadOperation; @@ -57,6 +50,7 @@ public class RileyLinkBLE { @Inject RileyLinkServiceData rileyLinkServiceData; @Inject RileyLinkUtil rileyLinkUtil; @Inject SP sp; + @Inject OrangeLinkImpl orangeLink; private final Context context; private final boolean gattDebugEnabled = true; @@ -75,6 +69,8 @@ public class RileyLinkBLE { this.context = context; this.bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + //orangeLink.rileyLinkBLE = this; + bluetoothGattCallback = new BluetoothGattCallback() { @Override @@ -93,16 +89,7 @@ public class RileyLinkBLE { radioResponseCountNotified.run(); } - if (characteristic.getUuid().toString().equals(GattAttributes.UUID_NOTIF_CHARACTER.toString())) { - final byte[] data = characteristic.getValue(); - int first = 0xff & data[0]; - aapsLogger.info(LTag.PUMPBTCOMM, - "onCharacteristicChanged " + ByteUtil.shortHexString(characteristic.getValue()) + "=====" + first); - String fv = data[3] + "." + data[4]; - String hv = data[5] + "." + data[6]; - rileyLinkServiceData.versionOrangeFV = fv; - rileyLinkServiceData.versionOrangeHV = hv; - } + orangeLink.onCharacteristicChanged(characteristic); } @@ -242,6 +229,9 @@ public class RileyLinkBLE { final List services = gatt.getServices(); boolean rileyLinkFound = false; + orangeLink.resetOrangeLinkData(); + + StringBuilder stringBuilder = new StringBuilder("RileyLink Device Debug\n"); for (BluetoothGattService service : services) { final UUID uuidService = service.getUuid(); @@ -251,14 +241,14 @@ public class RileyLinkBLE { } if (gattDebugEnabled) { - debugService(service, 0); - } - if (GattAttributes.isOrange(uuidService)) { - rileyLinkServiceData.isOrange = true; + debugService(service, 0, stringBuilder); } + + orangeLink.checkIsOrange(uuidService); } if (gattDebugEnabled) { + aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()); aapsLogger.warn(LTag.PUMPBTCOMM, "onServicesDiscovered " + getGattStatusMessage(status)); } @@ -284,6 +274,7 @@ public class RileyLinkBLE { @Inject public void onInit() { aapsLogger.debug(LTag.PUMPBTCOMM, "BT Adapter: " + this.bluetoothAdapter); + this.orangeLink.rileyLinkBLE = this; } @@ -300,6 +291,7 @@ public class RileyLinkBLE { if (isAnyRileyLinkServiceFound(serviceI)) { return true; } + orangeLink.checkIsOrange(serviceI.getUuid()); } } @@ -312,7 +304,7 @@ public class RileyLinkBLE { } - public void debugService(BluetoothGattService service, int indentCount) { + public void debugService(BluetoothGattService service, int indentCount, StringBuilder stringBuilder) { String indentString = StringUtils.repeat(' ', indentCount); @@ -321,7 +313,7 @@ public class RileyLinkBLE { if (gattDebugEnabled) { final String uuidServiceString = uuidService.toString(); - StringBuilder stringBuilder = new StringBuilder(); + //StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(indentString); stringBuilder.append(GattAttributes.lookup(uuidServiceString, "Unknown service")); @@ -338,12 +330,12 @@ public class RileyLinkBLE { stringBuilder.append("\n\n"); - aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()); + //aapsLogger.warn(LTag.PUMPBTCOMM, stringBuilder.toString()); List includedServices = service.getIncludedServices(); for (BluetoothGattService serviceI : includedServices) { - debugService(serviceI, indentCount + 4); + debugService(serviceI, indentCount + 4, stringBuilder); } } } @@ -383,53 +375,46 @@ public class RileyLinkBLE { aapsLogger.error(LTag.PUMPBTCOMM, "Error setting response count notification"); return false; } - if(rileyLinkServiceData.isOrange){ - enableNotificationsOrange(); - } - return true; - } - public boolean enableNotificationsOrange() { - aapsLogger.error(LTag.PUMPBTCOMM, "enableNotificationsORG"); - BLECommOperationResult result = setNotification_blocking(GattAttributes.UUID_NOTIF_SERVICE, // - GattAttributes.UUID_NOTIF_CHARACTER); - if (result.resultCode != BLECommOperationResult.RESULT_SUCCESS) { - aapsLogger.error(LTag.PUMPBTCOMM, "Error setting response count notification"); - return false; - } - return true; - } - String macAddress; - public void findRileyLink(String RileyLinkAddress) { - aapsLogger.debug(LTag.PUMPBTCOMM, "RileyLink address: " + RileyLinkAddress); + if (rileyLinkServiceData.isOrange) { + return orangeLink.enableNotifications(); + } + return true; + } + + + public void findRileyLink(String rileyLinkAddress) { + aapsLogger.debug(LTag.PUMPBTCOMM, "RileyLink address: " + rileyLinkAddress); // Must verify that this is a valid MAC, or crash. - macAddress = RileyLinkAddress; + //macAddress = RileyLinkAddress; boolean useScanning = sp.getBoolean(RileyLinkConst.Prefs.OrangeUseScanning, false); if (useScanning) { - startScan(); + aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan for OrangeLink device."); + orangeLink.startScan(); } else { - rileyLinkDevice = bluetoothAdapter.getRemoteDevice(RileyLinkAddress); + rileyLinkDevice = bluetoothAdapter.getRemoteDevice(rileyLinkAddress); // if this succeeds, we get a connection state change callback? if (rileyLinkDevice != null) { - connectGatt(); + connectGattInternal(); } else { - aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device not found with address: " + RileyLinkAddress); + aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device not found with address: " + rileyLinkAddress); } } } - public void connectGattCheckOrange() { + public void connectGatt() { boolean useScanning = sp.getBoolean(RileyLinkConst.Prefs.OrangeUseScanning, false); if (useScanning) { - startScan(); + aapsLogger.debug(LTag.PUMPBTCOMM, "Start scan for OrangeLink device."); + orangeLink.startScan(); } else { - connectGatt(); + connectGattInternal(); } } // This function must be run on UI thread. - public void connectGatt() { + public void connectGattInternal() { if (this.rileyLinkDevice == null) { aapsLogger.error(LTag.PUMPBTCOMM, "RileyLink device is null, can't do connectGatt."); return; @@ -478,7 +463,7 @@ public class RileyLinkBLE { } - private BLECommOperationResult setNotification_blocking(UUID serviceUUID, UUID charaUUID) { + public BLECommOperationResult setNotification_blocking(UUID serviceUUID, UUID charaUUID) { BLECommOperationResult rval = new BLECommOperationResult(); if (bluetoothConnectionGatt != null) { @@ -643,116 +628,11 @@ public class RileyLinkBLE { return statusMessage; } - private List buildScanFilters() { - ArrayList scanFilterList = new ArrayList<>(); - ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder(); - scanFilterBuilder.setDeviceAddress(macAddress); - scanFilterList.add(scanFilterBuilder.build()); - return scanFilterList; + public void setRileyLinkDevice(BluetoothDevice device) { + this.rileyLinkDevice = device; } - private ScanSettings buildScanSettings() { - ScanSettings.Builder scanSettingBuilder = new ScanSettings.Builder(); - scanSettingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY); - scanSettingBuilder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE); - scanSettingBuilder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES); - return scanSettingBuilder.build(); - } - - public void startScan() { - try { - stopScan(); - aapsLogger.debug(LTag.PUMPBTCOMM, "startScan"); - handler.sendEmptyMessageDelayed(TIME_OUT_WHAT, TIME_OUT); - BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); - if (bluetoothLeScanner == null) { - bluetoothAdapter.startLeScan(mLeScanCallback); - return; - } - bluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), scanCallback); - } catch (Exception e) { - e.printStackTrace(); - aapsLogger.error(LTag.PUMPBTCOMM, e.getMessage()); - } - - - } - - ScanCallback scanCallback = new ScanCallback() { - @Override - public void onScanResult(int callbackType, ScanResult result) { - super.onScanResult(callbackType, result); - String name = result.getDevice().getName(); - String address = result.getDevice().getAddress(); - if (macAddress.equals(address)) { - stopScan(); - rileyLinkDevice = result.getDevice(); - connectGatt(); - - } - } - - @Override - public void onBatchScanResults(List results) { - super.onBatchScanResults(results); - } - - @Override - public void onScanFailed(int errorCode) { - super.onScanFailed(errorCode); - stopScan(); - } - }; - private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { - public void onLeScan(final BluetoothDevice device, final int rssi, - final byte[] scanRecord) { - if (macAddress.equals(device.getAddress())) { - stopScan(); - rileyLinkDevice = device; - connectGatt(); - } - } - }; - public static final int TIME_OUT = 90 * 1000; - public static final int TIME_OUT_WHAT = 0x12; - Handler handler = new Handler() { - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - switch (msg.what) { - case TIME_OUT_WHAT: - stopScan(); - break; - } - } - }; - - public void stopScan() { - handler.removeMessages(TIME_OUT_WHAT); - if (bluetoothAdapter == null) { - return; - } - try { - BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner(); - if (bluetoothLeScanner == null) { - if (isBluetoothAvailable()) { - bluetoothAdapter.stopLeScan(mLeScanCallback); - } - return; - } - if (isBluetoothAvailable()) { - bluetoothLeScanner.stopScan(scanCallback); - } - } catch (Exception e) { - e.printStackTrace(); - aapsLogger.error(LTag.PUMPBTCOMM, e.getMessage()); - } - - } - - public boolean isBluetoothAvailable() { - return (bluetoothAdapter != null && - bluetoothAdapter.isEnabled() && - bluetoothAdapter.getState() == BluetoothAdapter.STATE_ON); + public BluetoothAdapter getBluetoothAdapter() { + return bluetoothAdapter; } } diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/GattAttributes.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/GattAttributes.java index c4cde5b3a7..cdcf8ab37c 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/GattAttributes.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/data/GattAttributes.java @@ -13,13 +13,20 @@ public class GattAttributes { public static String PREFIX = "0000"; public static String SUFFIX = "-0000-1000-8000-00805f9b34fb"; - public static String SERVICE_GAP = PREFIX + "1800" + SUFFIX; - public static String CHARA_GAP_NAME = PREFIX + "2a00" + SUFFIX; // RileyLink RFSpy - public static String CHARA_GAP_NUM = PREFIX + "2a01" + SUFFIX; // 0000 - public static String CHARA_GAP_UNK = PREFIX + "2a01" + SUFFIX; // a + // Generic Access + public static String SERVICE_GA = PREFIX + "1800" + SUFFIX; + public static String CHARA_GA_NAME = PREFIX + "2a00" + SUFFIX; // RileyLink RFSpy + public static String CHARA_GA_APPEARANCE = PREFIX + "2a01" + SUFFIX; // 0000 + public static String CHARA_GA_PPCP = PREFIX + "2a04" + SUFFIX; // 0000 + public static String CHARA_GA_CAR = PREFIX + "2aa6" + SUFFIX; // 0000 + + // Generic Attribute + public static String SERVICE_G_ATTR = PREFIX + "1801" + SUFFIX; + + // Battery Service public static String SERVICE_BATTERY = PREFIX + "180f" + SUFFIX; // Battery - public static String CHARA_BATTERY_UNK = PREFIX + "2a19" + SUFFIX; + public static String CHARA_BATTERY_LEVEL = PREFIX + "2a19" + SUFFIX; // RileyLink Radio Service public static String SERVICE_RADIO = "0235733b-99c5-4197-b856-69219c2a3845"; @@ -29,9 +36,20 @@ public class GattAttributes { public static String CHARA_RADIO_CUSTOM_NAME = "d93b2af0-1e28-11e4-8c21-0800200c9a66"; public static String CHARA_RADIO_VERSION = "30d99dc9-7c91-4295-a051-0a104d238cf2"; public static String CHARA_RADIO_LED_MODE = "c6d84241-f1a7-4f9c-a25f-fce16732f14e"; - //Orange Radio Service - public static UUID UUID_NOTIF_SERVICE = UUID.fromString("6e400001-b5a3-f393-e0a9-e50e24dcca9e"); - public static UUID UUID_NOTIF_CHARACTER = UUID.fromString("6e400003-b5a3-f393-e0a9-e50e24dcca9e"); + + // Secure DFU Service (Orange 1.5 - 3.2) + public static String SERVICE_DFU = "0000fe59-0000-1000-8000-00805f9b34fb"; + public static String CHARA_BUTTONLESS_DFU = "8ec90003-f315-4f60-9fb8-838830daea50"; + + // Nordic UART Service (Orange 2.1 - 3.2) + public static String SERVICE_NORDIC_UART = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"; + public static String CHARA_NORDIC_RX = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; + public static String CHARA_NORDIC_TX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; + + + // Orange Radio Service + public static String SERVICE_RADIO_ORANGE = "6e400001-b5a3-f393-e0a9-e50e24dcca9e"; + public static String CHARA_NOTIFICATION_ORANGE = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; private static final Map attributes; private static final Map attributesRileyLinkSpecific; @@ -40,13 +58,18 @@ public class GattAttributes { static { attributes = new HashMap<>(); - attributes.put(SERVICE_GAP, "Device Information Service"); - attributes.put(CHARA_GAP_NAME, "Name"); // - attributes.put(CHARA_GAP_NUM, "Number"); // + attributes.put(SERVICE_GA, "Generic Access"); + attributes.put(CHARA_GA_NAME, "Device Name"); // + attributes.put(CHARA_GA_APPEARANCE, "Appearance"); // + attributes.put(CHARA_GA_PPCP, "Peripheral Preffered Connection Parameters"); + attributes.put(CHARA_GA_CAR, "Central Address Resolution"); + + attributes.put(SERVICE_G_ATTR, "Generic Attribute"); attributes.put(SERVICE_BATTERY, "Battery Service"); + attributes.put(CHARA_BATTERY_LEVEL, "Battery Level"); - attributes.put(SERVICE_RADIO, "Radio Interface"); // a + attributes.put(SERVICE_RADIO, "Radio Interface Service"); attributes.put(CHARA_RADIO_CUSTOM_NAME, "Custom Name"); attributes.put(CHARA_RADIO_DATA, "Data"); attributes.put(CHARA_RADIO_RESPONSE_COUNT, "Response Count"); @@ -54,6 +77,13 @@ public class GattAttributes { attributes.put(CHARA_RADIO_VERSION, "Version"); // firmwareVersion attributes.put(CHARA_RADIO_LED_MODE, "Led Mode"); + attributes.put(SERVICE_DFU, "Secure DFU Service"); + attributes.put(CHARA_BUTTONLESS_DFU, "Buttonless DFU"); + + attributes.put(SERVICE_NORDIC_UART, "Nordic UART Service"); + attributes.put(CHARA_NORDIC_RX, "RX Characteristic"); + attributes.put(CHARA_NORDIC_TX, "TX Characteristic"); + attributesRileyLinkSpecific = new HashMap<>(); attributesRileyLinkSpecific.put(SERVICE_RADIO, "Radio Interface"); // a @@ -63,6 +93,9 @@ public class GattAttributes { attributesRileyLinkSpecific.put(CHARA_RADIO_TIMER_TICK, "Timer Tick"); attributesRileyLinkSpecific.put(CHARA_RADIO_VERSION, "Version"); // firmwareVersion attributesRileyLinkSpecific.put(CHARA_RADIO_LED_MODE, "Led Mode"); + + attributesRileyLinkSpecific.put(SERVICE_RADIO_ORANGE, "Orange Radio Interface"); + attributesRileyLinkSpecific.put(CHARA_NOTIFICATION_ORANGE, "Orange Notification"); } @@ -86,8 +119,10 @@ public class GattAttributes { public static boolean isRileyLink(UUID uuid) { return attributesRileyLinkSpecific.containsKey(uuid.toString()); } + + public static boolean isOrange(UUID uuid) { - return UUID_NOTIF_SERVICE.equals(uuid.toString()); + return SERVICE_RADIO_ORANGE.equals(uuid.toString()); } } diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt new file mode 100644 index 0000000000..1568503a4e --- /dev/null +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/ble/device/OrangeLinkImpl.kt @@ -0,0 +1,195 @@ +package info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.device + +import android.bluetooth.BluetoothAdapter +import android.bluetooth.BluetoothAdapter.LeScanCallback +import android.bluetooth.BluetoothGattCharacteristic +import android.bluetooth.le.BluetoothLeScanner +import android.bluetooth.le.ScanCallback +import android.bluetooth.le.ScanFilter +import android.bluetooth.le.ScanResult +import android.bluetooth.le.ScanSettings +import android.os.Handler +import android.os.Message +import info.nightscout.androidaps.logging.AAPSLogger +import info.nightscout.androidaps.logging.LTag +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.RileyLinkUtil +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.RileyLinkBLE +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.data.GattAttributes +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.ble.operations.BLECommOperationResult +import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.service.RileyLinkServiceData +import info.nightscout.androidaps.plugins.pump.common.utils.ByteUtil +import info.nightscout.androidaps.utils.sharedPreferences.SP +import java.lang.Exception +import java.util.* +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class OrangeLinkImpl @Inject constructor( + var aapsLogger: AAPSLogger, + var rileyLinkServiceData: RileyLinkServiceData, + var rileyLinkUtil: RileyLinkUtil, + var sp: SP) { + + lateinit var rileyLinkBLE: RileyLinkBLE + + fun onCharacteristicChanged(characteristic: BluetoothGattCharacteristic) { + if (characteristic.uuid.toString().equals(GattAttributes.CHARA_NOTIFICATION_ORANGE)) { + val data = characteristic.value + val first = 0xff and data[0].toInt() + aapsLogger.info(LTag.PUMPBTCOMM, + "OrangeLinkImpl: onCharacteristicChanged " + ByteUtil.shortHexString(characteristic.value) + "=====" + first) + val fv = data[3].toString() + "." + data[4] + val hv = data[5].toString() + "." + data[6] + rileyLinkServiceData.versionOrangeFirmware = fv + rileyLinkServiceData.versionOrangeHardware = hv + + aapsLogger.info(LTag.PUMPBTCOMM, "OrangeLink: Firmware: ${fv}, Hardware: ${hv}") + } + } + + + fun resetOrangeLinkData() { + rileyLinkServiceData.isOrange = false + rileyLinkServiceData.versionOrangeFirmware = null + rileyLinkServiceData.versionOrangeHardware = null + } + + /** + * We are checking if this is special Orange (with ORANGE_NOTIFICTION_SERVICE) + */ + fun checkIsOrange(uuidService: UUID) { + if (GattAttributes.isOrange(uuidService)) { + rileyLinkServiceData.isOrange = true + } + } + + + fun enableNotifications(): Boolean { + aapsLogger.info(LTag.PUMPBTCOMM, "OrangeLinkImpl::enableNotifications") + val result: BLECommOperationResult = rileyLinkBLE.setNotification_blocking( + UUID.fromString(GattAttributes.SERVICE_RADIO_ORANGE), // + UUID.fromString(GattAttributes.CHARA_NOTIFICATION_ORANGE) + ) + + if (result.resultCode != BLECommOperationResult.RESULT_SUCCESS) { + aapsLogger.error(LTag.PUMPBTCOMM, "Error setting response count notification") + return false + } + return true + } + + + private fun buildScanFilters(): List { + val scanFilterList: MutableList = mutableListOf() //ArrayList<*> = ArrayList() + val scanFilterBuilder = ScanFilter.Builder() + scanFilterBuilder.setDeviceAddress(rileyLinkServiceData.rileyLinkAddress) + scanFilterList.add(scanFilterBuilder.build()) + return scanFilterList + } + + private fun buildScanSettings(): ScanSettings? { + val scanSettingBuilder = ScanSettings.Builder() + scanSettingBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + scanSettingBuilder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE) + scanSettingBuilder.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) + return scanSettingBuilder.build() + } + + fun startScan() { + try { + stopScan() + val bluetoothAdapter = rileyLinkBLE.getBluetoothAdapter() + aapsLogger.debug(LTag.PUMPBTCOMM, "startScan") + handler.sendEmptyMessageDelayed(TIME_OUT_WHAT, TIME_OUT.toLong()) + val bluetoothLeScanner: BluetoothLeScanner = bluetoothAdapter.bluetoothLeScanner + // if (bluetoothLeScanner == null) { + // bluetoothAdapter.startLeScan(mLeScanCallback) + // return + // } + bluetoothLeScanner.startScan(buildScanFilters(), buildScanSettings(), scanCallback) + } catch (e: Exception) { + e.printStackTrace() + aapsLogger.error(LTag.PUMPBTCOMM, "Start scan: ${e.message}", e) + } + } + + var scanCallback: ScanCallback = object : ScanCallback() { + override fun onScanResult(callbackType: Int, result: ScanResult) { + super.onScanResult(callbackType, result) + //val name = result.device.name + val address = result.device.address + if (rileyLinkServiceData.rileyLinkAddress.equals(address)) { + stopScan() + rileyLinkBLE.rileyLinkDevice = result.device + rileyLinkBLE.connectGattInternal() + } + } + + override fun onBatchScanResults(results: List) { + super.onBatchScanResults(results) + } + + override fun onScanFailed(errorCode: Int) { + super.onScanFailed(errorCode) + stopScan() + } + } + + + private val mLeScanCallback = LeScanCallback { device, _, _ -> + if (rileyLinkServiceData.rileyLinkAddress.equals(device.address)) { + stopScan() + rileyLinkBLE.rileyLinkDevice = device + rileyLinkBLE.connectGattInternal() + } + } + + val TIME_OUT = 90 * 1000 + val TIME_OUT_WHAT = 0x12 + + var handler: Handler = object : Handler() { + override fun handleMessage(msg: Message) { + super.handleMessage(msg) + when (msg.what) { + TIME_OUT_WHAT -> stopScan() + } + } + } + + fun stopScan() { + handler.removeMessages(TIME_OUT_WHAT) + + val bluetoothAdapter = rileyLinkBLE.getBluetoothAdapter() ?: return + + try { + val bluetoothLeScanner: BluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner() + + if (isBluetoothAvailable()) { + bluetoothLeScanner.stopScan(scanCallback) + } + + return + + // if (bluetoothLeScanner == null) { + // if (isBluetoothAvailable()) { + // bluetoothAdapter.stopLeScan(mLeScanCallback) + // } + // return + // } + // if (isBluetoothAvailable()) { + // bluetoothLeScanner.stopScan(scanCallback) + // } + } catch (e: Exception) { + aapsLogger.error(LTag.PUMPBTCOMM, "Stop scan: ${e.message}", e) + } + } + + fun isBluetoothAvailable(): Boolean { + val bluetoothAdapter = rileyLinkBLE.getBluetoothAdapter() + return bluetoothAdapter != null && + bluetoothAdapter.isEnabled() && + bluetoothAdapter.getState() == BluetoothAdapter.STATE_ON + } + +} \ No newline at end of file diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java index ce96a5c2fa..df240c2acb 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/dialog/RileyLinkStatusGeneralFragment.java @@ -91,30 +91,29 @@ public class RileyLinkStatusGeneralFragment extends DaggerFragment implements Re this.connectionStatus.setText(resourceHelper.gs(rileyLinkServiceData.rileyLinkServiceState.getResourceId())); - // BS FIXME rileyLinkServiceData is injected so I suppose it cannot be null? - if (rileyLinkServiceData != null) { - this.configuredRileyLinkAddress.setText(Optional.ofNullable(rileyLinkServiceData.rileyLinkAddress).orElse(PLACEHOLDER)); - this.configuredRileyLinkName.setText(Optional.ofNullable(rileyLinkServiceData.rileyLinkName).orElse(PLACEHOLDER)); + this.configuredRileyLinkAddress.setText(Optional.ofNullable(rileyLinkServiceData.rileyLinkAddress).orElse(PLACEHOLDER)); + this.configuredRileyLinkName.setText(Optional.ofNullable(rileyLinkServiceData.rileyLinkName).orElse(PLACEHOLDER)); - if (sp.getBoolean(resourceHelper.gs(R.string.key_riley_link_show_battery_level), false)) { - batteryLevelRow.setVisibility(View.VISIBLE); - Integer batteryLevel = rileyLinkServiceData.batteryLevel; - this.batteryLevel.setText(batteryLevel == null ? PLACEHOLDER : resourceHelper.gs(R.string.rileylink_battery_level_value, batteryLevel)); - } else { - batteryLevelRow.setVisibility(View.GONE); - } + if (sp.getBoolean(resourceHelper.gs(R.string.key_riley_link_show_battery_level), false)) { + batteryLevelRow.setVisibility(View.VISIBLE); + Integer batteryLevel = rileyLinkServiceData.batteryLevel; + this.batteryLevel.setText(batteryLevel == null ? PLACEHOLDER : resourceHelper.gs(R.string.rileylink_battery_level_value, batteryLevel)); + } else { + batteryLevelRow.setVisibility(View.GONE); + } - RileyLinkError rileyLinkError = rileyLinkServiceData.rileyLinkError; - this.connectionError.setText(rileyLinkError == null ? PLACEHOLDER : resourceHelper.gs(rileyLinkError.getResourceId(targetDevice))); + RileyLinkError rileyLinkError = rileyLinkServiceData.rileyLinkError; + this.connectionError.setText(rileyLinkError == null ? PLACEHOLDER : resourceHelper.gs(rileyLinkError.getResourceId(targetDevice))); - if(rileyLinkServiceData.isOrange){ - this.firmwareVersion.setText("FV:"+Optional.ofNullable(rileyLinkServiceData.versionOrangeFV).orElse(PLACEHOLDER)+"\nHV:"+Optional.ofNullable(rileyLinkServiceData.versionOrangeHV).orElse(PLACEHOLDER)); - }else{ - this.firmwareVersion.setText(resourceHelper.gs(R.string.rileylink_firmware_version_value, - Optional.ofNullable(rileyLinkServiceData.versionBLE113).orElse(PLACEHOLDER), Optional.ofNullable(rileyLinkServiceData.versionCC110).orElse(PLACEHOLDER))); - - } + if (rileyLinkServiceData.isOrange && rileyLinkServiceData.versionOrangeFirmware!=null) { + this.firmwareVersion.setText(resourceHelper.gs(R.string.rileylink_firmware_version_value_orange, + rileyLinkServiceData.versionOrangeFirmware, + Optional.ofNullable(rileyLinkServiceData.versionOrangeHardware).orElse(PLACEHOLDER))); + } else { + this.firmwareVersion.setText(resourceHelper.gs(R.string.rileylink_firmware_version_value, + Optional.ofNullable(rileyLinkServiceData.versionBLE113).orElse(PLACEHOLDER), + Optional.ofNullable(rileyLinkServiceData.versionCC110).orElse(PLACEHOLDER))); } RileyLinkPumpDevice rileyLinkPumpDevice = (RileyLinkPumpDevice) activePlugin.getActivePump(); diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java index 5ab614248a..0159bd945e 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/RileyLinkServiceData.java @@ -48,9 +48,11 @@ public class RileyLinkServiceData { public String versionBLE113; // radio version public String versionCC110; + + // orangeLink public boolean isOrange; - public String versionOrangeFV; - public String versionOrangeHV; + public String versionOrangeFirmware; + public String versionOrangeHardware; public RileyLinkTargetDevice targetDevice; diff --git a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java index c24bb1d8b1..06ea7e3831 100644 --- a/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java +++ b/rileylink/src/main/java/info/nightscout/androidaps/plugins/pump/common/hw/rileylink/service/tasks/DiscoverGattServicesTask.java @@ -38,7 +38,7 @@ public class DiscoverGattServicesTask extends ServiceTask { RileyLinkPumpDevice pumpDevice = (RileyLinkPumpDevice) activePlugin.getActivePump(); if (needToConnect) { - pumpDevice.getRileyLinkService().getRileyLinkBLE().connectGattCheckOrange(); + pumpDevice.getRileyLinkService().getRileyLinkBLE().connectGatt(); } pumpDevice.getRileyLinkService().getRileyLinkBLE().discoverServices(); diff --git a/rileylink/src/main/res/values/strings.xml b/rileylink/src/main/res/values/strings.xml index 902d74153c..c8ef385aa2 100644 --- a/rileylink/src/main/res/values/strings.xml +++ b/rileylink/src/main/res/values/strings.xml @@ -45,6 +45,7 @@ Last Device Contact: Firmware Version: BLE113: %1$s\nCC110: %2$s + Fw: %1$s\nHw: %2$s Pump Serial Number: Pump Frequency: %1$.2f MHz