RS v3 encryption
This commit is contained in:
parent
d1d49a8db2
commit
5ce8b998d9
18 changed files with 549 additions and 108 deletions
|
@ -84,6 +84,8 @@
|
||||||
<activity
|
<activity
|
||||||
android:name=".plugins.pump.danaRS.activities.PairingHelperActivity"
|
android:name=".plugins.pump.danaRS.activities.PairingHelperActivity"
|
||||||
android:launchMode="singleTask" />
|
android:launchMode="singleTask" />
|
||||||
|
<activity android:name=".plugins.pump.danaRS.activities.EnterPinActivity"
|
||||||
|
android:launchMode="singleTask" />
|
||||||
<activity android:name=".historyBrowser.HistoryBrowseActivity" />
|
<activity android:name=".historyBrowser.HistoryBrowseActivity" />
|
||||||
<activity android:name=".activities.SurveyActivity" />
|
<activity android:name=".activities.SurveyActivity" />
|
||||||
<activity android:name=".activities.StatsActivity" />
|
<activity android:name=".activities.StatsActivity" />
|
||||||
|
|
|
@ -13,6 +13,7 @@ import info.nightscout.androidaps.plugins.pump.common.hw.rileylink.dialog.RileyL
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRHistoryActivity
|
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRHistoryActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRUserOptionsActivity
|
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRUserOptionsActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.BLEScanActivity
|
import info.nightscout.androidaps.plugins.pump.danaRS.activities.BLEScanActivity
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRS.activities.EnterPinActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.PairingHelperActivity
|
import info.nightscout.androidaps.plugins.pump.danaRS.activities.PairingHelperActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightAlertActivity
|
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightAlertActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingActivity
|
import info.nightscout.androidaps.plugins.pump.insight.activities.InsightPairingActivity
|
||||||
|
@ -28,6 +29,7 @@ abstract class ActivitiesModule {
|
||||||
@ContributesAndroidInjector abstract fun contributeBolusProgressHelperActivity(): BolusProgressHelperActivity
|
@ContributesAndroidInjector abstract fun contributeBolusProgressHelperActivity(): BolusProgressHelperActivity
|
||||||
@ContributesAndroidInjector abstract fun contributeDanaRHistoryActivity(): DanaRHistoryActivity
|
@ContributesAndroidInjector abstract fun contributeDanaRHistoryActivity(): DanaRHistoryActivity
|
||||||
@ContributesAndroidInjector abstract fun contributeDanaRUserOptionsActivity(): DanaRUserOptionsActivity
|
@ContributesAndroidInjector abstract fun contributeDanaRUserOptionsActivity(): DanaRUserOptionsActivity
|
||||||
|
@ContributesAndroidInjector abstract fun contributeEnterPinActivity(): EnterPinActivity
|
||||||
@ContributesAndroidInjector abstract fun contributeErrorHelperActivity(): ErrorHelperActivity
|
@ContributesAndroidInjector abstract fun contributeErrorHelperActivity(): ErrorHelperActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
|
@ContributesAndroidInjector abstract fun contributesHistoryBrowseActivity(): HistoryBrowseActivity
|
||||||
@ContributesAndroidInjector abstract fun contributesInsightAlertActivity(): InsightAlertActivity
|
@ContributesAndroidInjector abstract fun contributesInsightAlertActivity(): InsightAlertActivity
|
||||||
|
|
|
@ -15,6 +15,8 @@ import info.nightscout.androidaps.data.Profile;
|
||||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||||
|
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
||||||
|
import info.nightscout.androidaps.events.EventPreferenceChange;
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||||
import info.nightscout.androidaps.interfaces.Constraint;
|
import info.nightscout.androidaps.interfaces.Constraint;
|
||||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
||||||
|
@ -42,6 +44,8 @@ import info.nightscout.androidaps.utils.DecimalFormatter;
|
||||||
import info.nightscout.androidaps.utils.Round;
|
import info.nightscout.androidaps.utils.Round;
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
import info.nightscout.androidaps.utils.resources.ResourceHelper;
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mike on 28.01.2018.
|
* Created by mike on 28.01.2018.
|
||||||
|
@ -50,6 +54,8 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP;
|
||||||
public abstract class AbstractDanaRPlugin extends PumpPluginBase implements PumpInterface, DanaRInterface, ConstraintsInterface {
|
public abstract class AbstractDanaRPlugin extends PumpPluginBase implements PumpInterface, DanaRInterface, ConstraintsInterface {
|
||||||
protected AbstractDanaRExecutionService sExecutionService;
|
protected AbstractDanaRExecutionService sExecutionService;
|
||||||
|
|
||||||
|
protected CompositeDisposable disposable = new CompositeDisposable();
|
||||||
|
|
||||||
protected boolean useExtendedBoluses = false;
|
protected boolean useExtendedBoluses = false;
|
||||||
|
|
||||||
protected PumpDescription pumpDescription = new PumpDescription();
|
protected PumpDescription pumpDescription = new PumpDescription();
|
||||||
|
@ -86,6 +92,28 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
|
||||||
this.sp = sp;
|
this.sp = sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventConfigBuilderChange.class)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(event -> danaRPump.setLastConnection(0))
|
||||||
|
);
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventPreferenceChange.class)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(event -> {
|
||||||
|
if (event.isChanged(getResourceHelper(), R.string.key_danar_bt_name))
|
||||||
|
danaRPump.setLastConnection(0);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
disposable.clear();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSuspended() {
|
public boolean isSuspended() {
|
||||||
return danaRPump.getPumpSuspended();
|
return danaRPump.getPumpSuspended();
|
||||||
|
@ -488,6 +516,4 @@ public abstract class AbstractDanaRPlugin extends PumpPluginBase implements Pump
|
||||||
public void timeDateOrTimeZoneChanged() {
|
public void timeDateOrTimeZoneChanged() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.activities.TDDStatsActivity
|
import info.nightscout.androidaps.activities.TDDStatsActivity
|
||||||
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
||||||
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
import info.nightscout.androidaps.events.EventExtendedBolusChange
|
||||||
|
import info.nightscout.androidaps.events.EventInitializationChanged
|
||||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||||
import info.nightscout.androidaps.events.EventTempBasalChange
|
import info.nightscout.androidaps.events.EventTempBasalChange
|
||||||
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
import info.nightscout.androidaps.interfaces.ActivePluginProvider
|
||||||
|
@ -24,13 +25,16 @@ import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRHistoryActi
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRUserOptionsActivity
|
import info.nightscout.androidaps.plugins.pump.danaR.activities.DanaRUserOptionsActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.events.EventDanaRNewStatus
|
import info.nightscout.androidaps.plugins.pump.danaR.events.EventDanaRNewStatus
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin
|
import info.nightscout.androidaps.plugins.pump.danaRKorean.DanaRKoreanPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||||
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
import info.nightscout.androidaps.queue.events.EventQueueChanged
|
||||||
import info.nightscout.androidaps.utils.DateUtil
|
import info.nightscout.androidaps.utils.DateUtil
|
||||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog
|
||||||
import info.nightscout.androidaps.utils.SetWarnColor
|
import info.nightscout.androidaps.utils.SetWarnColor
|
||||||
import info.nightscout.androidaps.utils.T
|
import info.nightscout.androidaps.utils.T
|
||||||
import info.nightscout.androidaps.utils.extensions.plusAssign
|
import info.nightscout.androidaps.utils.extensions.plusAssign
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import kotlinx.android.synthetic.main.danar_fragment.*
|
import kotlinx.android.synthetic.main.danar_fragment.*
|
||||||
|
@ -43,8 +47,10 @@ class DanaRFragment : DaggerFragment() {
|
||||||
@Inject lateinit var commandQueue: CommandQueueProvider
|
@Inject lateinit var commandQueue: CommandQueueProvider
|
||||||
@Inject lateinit var activePlugin: ActivePluginProvider
|
@Inject lateinit var activePlugin: ActivePluginProvider
|
||||||
@Inject lateinit var danaRKoreanPlugin: DanaRKoreanPlugin
|
@Inject lateinit var danaRKoreanPlugin: DanaRKoreanPlugin
|
||||||
|
@Inject lateinit var danaRSPlugin: DanaRSPlugin
|
||||||
@Inject lateinit var danaRPump: DanaRPump
|
@Inject lateinit var danaRPump: DanaRPump
|
||||||
@Inject lateinit var resourceHelper: ResourceHelper
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
|
||||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
|
@ -93,12 +99,28 @@ class DanaRFragment : DaggerFragment() {
|
||||||
danaRPump.lastConnection = 0
|
danaRPump.lastConnection = 0
|
||||||
commandQueue.readStatus("Clicked connect to pump", null)
|
commandQueue.readStatus("Clicked connect to pump", null)
|
||||||
}
|
}
|
||||||
|
if (danaRSPlugin.isEnabled())
|
||||||
|
danar_btconnection.setOnLongClickListener {
|
||||||
|
activity?.let {
|
||||||
|
OKDialog.showConfirmation(it, resourceHelper.gs(R.string.resetpairing), Runnable {
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName)
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName)
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName)
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randomsynckey) + danaRSPlugin.mDeviceName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
override fun onResume() {
|
override fun onResume() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
||||||
|
disposable += rxBus
|
||||||
|
.toObservable(EventInitializationChanged::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ updateGUI() }, { fabricPrivacy.logException(it) })
|
||||||
disposable += rxBus
|
disposable += rxBus
|
||||||
.toObservable(EventDanaRNewStatus::class.java)
|
.toObservable(EventDanaRNewStatus::class.java)
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
|
|
@ -27,6 +27,7 @@ import info.nightscout.androidaps.data.PumpEnactResult;
|
||||||
import info.nightscout.androidaps.db.ExtendedBolus;
|
import info.nightscout.androidaps.db.ExtendedBolus;
|
||||||
import info.nightscout.androidaps.db.TemporaryBasal;
|
import info.nightscout.androidaps.db.TemporaryBasal;
|
||||||
import info.nightscout.androidaps.events.EventAppExit;
|
import info.nightscout.androidaps.events.EventAppExit;
|
||||||
|
import info.nightscout.androidaps.events.EventConfigBuilderChange;
|
||||||
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
import info.nightscout.androidaps.interfaces.CommandQueueProvider;
|
||||||
import info.nightscout.androidaps.interfaces.Constraint;
|
import info.nightscout.androidaps.interfaces.Constraint;
|
||||||
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
import info.nightscout.androidaps.interfaces.ConstraintsInterface;
|
||||||
|
@ -157,6 +158,11 @@ public class DanaRSPlugin extends PumpPluginBase implements PumpInterface, DanaR
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
.subscribe(event -> context.unbindService(mConnection), fabricPrivacy::logException)
|
.subscribe(event -> context.unbindService(mConnection), fabricPrivacy::logException)
|
||||||
);
|
);
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventConfigBuilderChange.class)
|
||||||
|
.observeOn(Schedulers.io())
|
||||||
|
.subscribe(event -> danaRPump.setLastConnection(0))
|
||||||
|
);
|
||||||
disposable.add(rxBus
|
disposable.add(rxBus
|
||||||
.toObservable(EventDanaRSDeviceChange.class)
|
.toObservable(EventDanaRSDeviceChange.class)
|
||||||
.observeOn(Schedulers.io())
|
.observeOn(Schedulers.io())
|
||||||
|
@ -191,6 +197,7 @@ public class DanaRSPlugin extends PumpPluginBase implements PumpInterface, DanaR
|
||||||
private void loadAddress() {
|
private void loadAddress() {
|
||||||
mDeviceAddress = sp.getString(R.string.key_danars_address, "");
|
mDeviceAddress = sp.getString(R.string.key_danars_address, "");
|
||||||
mDeviceName = sp.getString(R.string.key_danars_name, "");
|
mDeviceName = sp.getString(R.string.key_danars_name, "");
|
||||||
|
danaRPump.setLastConnection(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package info.nightscout.androidaps.plugins.pump.danaRS.activities
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.util.Base64
|
||||||
|
import info.nightscout.androidaps.R
|
||||||
|
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
||||||
|
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRS.services.BLEComm
|
||||||
|
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||||
|
import info.nightscout.androidaps.utils.OKDialog
|
||||||
|
import info.nightscout.androidaps.utils.extensions.hexStringToByteArray
|
||||||
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
|
import info.nightscout.androidaps.utils.textValidator.DefaultEditTextValidator
|
||||||
|
import info.nightscout.androidaps.utils.textValidator.EditTextValidator
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
|
import kotlinx.android.synthetic.main.danars_enter_pin_activity.*
|
||||||
|
import kotlinx.android.synthetic.main.okcancel.*
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.experimental.xor
|
||||||
|
|
||||||
|
class EnterPinActivity : NoSplashAppCompatActivity() {
|
||||||
|
|
||||||
|
@Inject lateinit var rxBus: RxBusWrapper
|
||||||
|
@Inject lateinit var fabricPrivacy: FabricPrivacy
|
||||||
|
@Inject lateinit var resourceHelper: ResourceHelper
|
||||||
|
@Inject lateinit var danaRSPlugin: DanaRSPlugin
|
||||||
|
@Inject lateinit var sp: SP
|
||||||
|
@Inject lateinit var bleComm: BLEComm
|
||||||
|
|
||||||
|
private val disposable = CompositeDisposable()
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
setContentView(R.layout.danars_enter_pin_activity)
|
||||||
|
|
||||||
|
val p1 = DefaultEditTextValidator(rs_v3_pin1, this)
|
||||||
|
.setTestErrorString(resourceHelper.gs(R.string.error_mustbe12hexadidits), this)
|
||||||
|
.setCustomRegexp(resourceHelper.gs(R.string.twelvehexanumber), this)
|
||||||
|
.setTestType(EditTextValidator.TEST_REGEXP, this)
|
||||||
|
val p2 = DefaultEditTextValidator(rs_v3_pin2, this)
|
||||||
|
.setTestErrorString(resourceHelper.gs(R.string.error_mustbe8hexadidits), this)
|
||||||
|
.setCustomRegexp(resourceHelper.gs(R.string.eighthexanumber), this)
|
||||||
|
.setTestType(EditTextValidator.TEST_REGEXP, this)
|
||||||
|
|
||||||
|
ok.setOnClickListener {
|
||||||
|
if (p1.testValidity(false) && p2.testValidity(false)) {
|
||||||
|
val result = checkPairingCheckSum(
|
||||||
|
rs_v3_pin1.text.toString().hexStringToByteArray(),
|
||||||
|
rs_v3_pin2.text.toString().substring(0..5).hexStringToByteArray(),
|
||||||
|
rs_v3_pin2.text.toString().substring(6..7).hexStringToByteArray())
|
||||||
|
if (result) {
|
||||||
|
bleComm.finishV3Pairing()
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
else OKDialog.show(this, resourceHelper.gs(R.string.error), resourceHelper.gs(R.string.danar_invalidinput))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cancel.setOnClickListener { finish() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
disposable.add(rxBus
|
||||||
|
.toObservable(EventPumpStatusChanged::class.java)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribe({ if (it.status == EventPumpStatusChanged.Status.DISCONNECTED) finish() }) { fabricPrivacy.logException(it) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPause() {
|
||||||
|
super.onPause()
|
||||||
|
disposable.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkPairingCheckSum(pairingKey: ByteArray, randomPairingKey: ByteArray, checksum: ByteArray): Boolean {
|
||||||
|
|
||||||
|
// pairingKey ByteArray(6)
|
||||||
|
// randomPairingKey ByteArray(3)
|
||||||
|
// checksum ByteArray(1)
|
||||||
|
|
||||||
|
var pairingKeyCheckSum: Byte = 0
|
||||||
|
for (i in pairingKey.indices)
|
||||||
|
pairingKeyCheckSum = pairingKeyCheckSum xor pairingKey[i]
|
||||||
|
|
||||||
|
sp.putString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, Base64.encodeToString(pairingKey, Base64.DEFAULT))
|
||||||
|
|
||||||
|
for (i in randomPairingKey.indices)
|
||||||
|
pairingKeyCheckSum = pairingKeyCheckSum xor randomPairingKey[i]
|
||||||
|
|
||||||
|
sp.putString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, Base64.encodeToString(randomPairingKey, Base64.DEFAULT))
|
||||||
|
|
||||||
|
return checksum[0] == pairingKeyCheckSum
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -69,7 +69,7 @@ class DanaRSMessageHashTable @Inject constructor(
|
||||||
put(DanaRS_Packet_General_Delivery_Status(aapsLogger))
|
put(DanaRS_Packet_General_Delivery_Status(aapsLogger))
|
||||||
put(DanaRS_Packet_General_Get_Password(aapsLogger, danaRPump))
|
put(DanaRS_Packet_General_Get_Password(aapsLogger, danaRPump))
|
||||||
put(DanaRS_Packet_General_Initial_Screen_Information(aapsLogger, danaRPump))
|
put(DanaRS_Packet_General_Initial_Screen_Information(aapsLogger, danaRPump))
|
||||||
put(DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper))
|
put(DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper, rxBus))
|
||||||
put(DanaRS_Packet_Notify_Delivery_Complete(aapsLogger, rxBus, resourceHelper, danaRSPlugin))
|
put(DanaRS_Packet_Notify_Delivery_Complete(aapsLogger, rxBus, resourceHelper, danaRSPlugin))
|
||||||
put(DanaRS_Packet_Notify_Delivery_Rate_Display(aapsLogger, rxBus, resourceHelper, danaRSPlugin))
|
put(DanaRS_Packet_Notify_Delivery_Rate_Display(aapsLogger, rxBus, resourceHelper, danaRSPlugin))
|
||||||
put(DanaRS_Packet_Notify_Missed_Bolus_Alarm(aapsLogger))
|
put(DanaRS_Packet_Notify_Missed_Bolus_Alarm(aapsLogger))
|
||||||
|
|
|
@ -11,7 +11,6 @@ class DanaRS_Packet_General_Initial_Screen_Information(
|
||||||
) : DanaRS_Packet() {
|
) : DanaRS_Packet() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
type = BleEncryption.DANAR_PACKET__TYPE_RESPONSE
|
|
||||||
opCode = BleEncryption.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION
|
opCode = BleEncryption.DANAR_PACKET__OPCODE_REVIEW__INITIAL_SCREEN_INFORMATION
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "New message")
|
aapsLogger.debug(LTag.PUMPCOMM, "New message")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,16 @@ import info.nightscout.androidaps.plugins.pump.danaRS.encryption.BleEncryption
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
import info.nightscout.androidaps.logging.LTag
|
import info.nightscout.androidaps.logging.LTag
|
||||||
|
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
|
||||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification
|
||||||
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
|
|
||||||
class DanaRS_Packet_Notify_Alarm(
|
class DanaRS_Packet_Notify_Alarm(
|
||||||
private val aapsLogger: AAPSLogger,
|
private val aapsLogger: AAPSLogger,
|
||||||
private val resourceHelper: ResourceHelper
|
private val resourceHelper: ResourceHelper,
|
||||||
|
private val rxBus: RxBusWrapper
|
||||||
) : DanaRS_Packet() {
|
) : DanaRS_Packet() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -29,11 +33,11 @@ class DanaRS_Packet_Notify_Alarm(
|
||||||
0x03 -> // Occlusion
|
0x03 -> // Occlusion
|
||||||
errorString = resourceHelper.gs(R.string.occlusion)
|
errorString = resourceHelper.gs(R.string.occlusion)
|
||||||
0x04 -> // LOW BATTERY
|
0x04 -> // LOW BATTERY
|
||||||
errorString = resourceHelper.gs(R.string.lowbattery)
|
errorString = resourceHelper.gs(R.string.pumpshutdown)
|
||||||
0x05 -> // Shutdown
|
0x05 -> // Shutdown
|
||||||
errorString = resourceHelper.gs(R.string.lowbattery)
|
errorString = resourceHelper.gs(R.string.lowbattery)
|
||||||
0x06 -> // Basal Compare
|
0x06 -> // Basal Compare
|
||||||
errorString = "BasalCompare ????"
|
errorString = resourceHelper.gs(R.string.basalcompare)
|
||||||
0x09 -> // Empty Reservoir
|
0x09 -> // Empty Reservoir
|
||||||
errorString = resourceHelper.gs(R.string.emptyreservoir)
|
errorString = resourceHelper.gs(R.string.emptyreservoir)
|
||||||
0x07, 0xFF -> // Blood sugar measurement alert
|
0x07, 0xFF -> // Blood sugar measurement alert
|
||||||
|
@ -41,7 +45,7 @@ class DanaRS_Packet_Notify_Alarm(
|
||||||
0x08, 0xFE -> // Remaining insulin level
|
0x08, 0xFE -> // Remaining insulin level
|
||||||
errorString = resourceHelper.gs(R.string.remaininsulinalert)
|
errorString = resourceHelper.gs(R.string.remaininsulinalert)
|
||||||
0xFD -> // Blood sugar check miss alarm
|
0xFD -> // Blood sugar check miss alarm
|
||||||
errorString = "Blood sugar check miss alarm ???"
|
errorString = resourceHelper.gs(R.string.missedbolus)
|
||||||
}
|
}
|
||||||
// No error no need to upload anything
|
// No error no need to upload anything
|
||||||
if (errorString == "") {
|
if (errorString == "") {
|
||||||
|
@ -49,6 +53,8 @@ class DanaRS_Packet_Notify_Alarm(
|
||||||
aapsLogger.debug(LTag.PUMPCOMM, "Error detected: $errorString")
|
aapsLogger.debug(LTag.PUMPCOMM, "Error detected: $errorString")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val notification = Notification(Notification.USERMESSAGE, errorString, Notification.URGENT)
|
||||||
|
rxBus.send(EventNewNotification(notification))
|
||||||
NSUpload.uploadError(errorString)
|
NSUpload.uploadError(errorString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,7 @@ public class BleEncryption {
|
||||||
return encryptSecondLevelPacketJni(context, bytes);
|
return encryptSecondLevelPacketJni(context, bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] ecryptSecondLevelPacket(byte[] bytes) {
|
public byte[] decryptSecondLevelPacket(byte[] bytes) {
|
||||||
return decryptSecondLevelPacketJni(context, bytes);
|
return decryptSecondLevelPacketJni(context, bytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.bluetooth.*
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
|
import android.util.Base64
|
||||||
import info.nightscout.androidaps.R
|
import info.nightscout.androidaps.R
|
||||||
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
import info.nightscout.androidaps.events.EventPumpStatusChanged
|
||||||
import info.nightscout.androidaps.logging.AAPSLogger
|
import info.nightscout.androidaps.logging.AAPSLogger
|
||||||
|
@ -14,11 +15,13 @@ import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotifi
|
||||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification
|
||||||
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPump
|
import info.nightscout.androidaps.plugins.pump.danaR.DanaRPump
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
import info.nightscout.androidaps.plugins.pump.danaRS.DanaRSPlugin
|
||||||
|
import info.nightscout.androidaps.plugins.pump.danaRS.activities.EnterPinActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.activities.PairingHelperActivity
|
import info.nightscout.androidaps.plugins.pump.danaRS.activities.PairingHelperActivity
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.comm.DanaRSMessageHashTable
|
import info.nightscout.androidaps.plugins.pump.danaRS.comm.DanaRSMessageHashTable
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.comm.DanaRS_Packet
|
import info.nightscout.androidaps.plugins.pump.danaRS.comm.DanaRS_Packet
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.encryption.BleEncryption
|
import info.nightscout.androidaps.plugins.pump.danaRS.encryption.BleEncryption
|
||||||
import info.nightscout.androidaps.plugins.pump.danaRS.events.EventDanaRSPairingSuccess
|
import info.nightscout.androidaps.plugins.pump.danaRS.events.EventDanaRSPairingSuccess
|
||||||
|
import info.nightscout.androidaps.utils.ToastUtils
|
||||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||||
import okhttp3.internal.notify
|
import okhttp3.internal.notify
|
||||||
|
@ -58,8 +61,17 @@ class BLEComm @Inject internal constructor(
|
||||||
private var connectDeviceName: String? = null
|
private var connectDeviceName: String? = null
|
||||||
private var bluetoothGatt: BluetoothGatt? = null
|
private var bluetoothGatt: BluetoothGatt? = null
|
||||||
|
|
||||||
|
private var v3Encryption: Boolean = false
|
||||||
|
set(newValue) {
|
||||||
|
bleEncryption.setEnhancedEncryption(newValue)
|
||||||
|
field = newValue
|
||||||
|
}
|
||||||
|
private var isEasyMode: Boolean = false
|
||||||
|
private var isUnitUD: Boolean = false
|
||||||
|
|
||||||
var isConnected = false
|
var isConnected = false
|
||||||
var isConnecting = false
|
var isConnecting = false
|
||||||
|
private var encryptedDataRead = false
|
||||||
private var uartRead: BluetoothGattCharacteristic? = null
|
private var uartRead: BluetoothGattCharacteristic? = null
|
||||||
private var uartWrite: BluetoothGattCharacteristic? = null
|
private var uartWrite: BluetoothGattCharacteristic? = null
|
||||||
|
|
||||||
|
@ -106,6 +118,14 @@ class BLEComm @Inject internal constructor(
|
||||||
fun disconnect(from: String) {
|
fun disconnect(from: String) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "disconnect from: $from")
|
||||||
|
|
||||||
|
if (!encryptedDataRead) {
|
||||||
|
// there was no response from pump after started encryption
|
||||||
|
// assume pairing keys are invalid
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName)
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName)
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_v3_randomsynckey) + danaRSPlugin.mDeviceName)
|
||||||
|
ToastUtils.showToastInUiThread(context, R.string.invalidpairing)
|
||||||
|
}
|
||||||
// cancel previous scheduled disconnection to prevent closing upcoming connection
|
// cancel previous scheduled disconnection to prevent closing upcoming connection
|
||||||
scheduledDisconnection?.cancel(false)
|
scheduledDisconnection?.cancel(false)
|
||||||
scheduledDisconnection = null
|
scheduledDisconnection = null
|
||||||
|
@ -118,6 +138,7 @@ class BLEComm @Inject internal constructor(
|
||||||
setCharacteristicNotification(uartReadBTGattChar, false)
|
setCharacteristicNotification(uartReadBTGattChar, false)
|
||||||
bluetoothGatt?.disconnect()
|
bluetoothGatt?.disconnect()
|
||||||
isConnected = false
|
isConnected = false
|
||||||
|
encryptedDataRead = false
|
||||||
SystemClock.sleep(2000)
|
SystemClock.sleep(2000)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,19 +163,20 @@ class BLEComm @Inject internal constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
override fun onCharacteristicRead(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicRead: " + DanaRS_Packet.toHexString(characteristic.value))
|
// for v3 after initial handshake it's encrypted - useless
|
||||||
addToReadBuffer(characteristic.value)
|
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicRead: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||||
readDataParsing()
|
readDataParsing(characteristic.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
|
override fun onCharacteristicChanged(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged: " + DanaRS_Packet.toHexString(characteristic.value))
|
// for v3 after initial handshake it's encrypted - useless
|
||||||
addToReadBuffer(characteristic.value)
|
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicChanged: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||||
Thread(Runnable { readDataParsing() }).start()
|
readDataParsing(characteristic.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
override fun onCharacteristicWrite(gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic, status: Int) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
|
// for v3 after initial handshake it's encrypted - useless
|
||||||
|
// aapsLogger.debug(LTag.PUMPBTCOMM, "onCharacteristicWrite: " + DanaRS_Packet.toHexString(characteristic.value))
|
||||||
Thread(Runnable {
|
Thread(Runnable {
|
||||||
synchronized(mSendQueue) {
|
synchronized(mSendQueue) {
|
||||||
// after message sent, check if there is the rest of the message waiting and send it
|
// after message sent, check if there is the rest of the message waiting and send it
|
||||||
|
@ -175,9 +197,10 @@ class BLEComm @Inject internal constructor(
|
||||||
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
||||||
isConnecting = false
|
isConnecting = false
|
||||||
isConnected = false
|
isConnected = false
|
||||||
|
encryptedDataRead = false
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
bluetoothGatt!!.setCharacteristicNotification(characteristic, enabled)
|
bluetoothGatt?.setCharacteristicNotification(characteristic, enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Synchronized
|
@Synchronized
|
||||||
|
@ -188,13 +211,15 @@ class BLEComm @Inject internal constructor(
|
||||||
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
||||||
isConnecting = false
|
isConnecting = false
|
||||||
isConnected = false
|
isConnected = false
|
||||||
|
encryptedDataRead = false
|
||||||
return@Runnable
|
return@Runnable
|
||||||
}
|
}
|
||||||
characteristic.value = data
|
characteristic.value = data
|
||||||
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
characteristic.writeType = BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE
|
||||||
aapsLogger.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data))
|
//aapsLogger.debug("writeCharacteristic:" + DanaRS_Packet.toHexString(data))
|
||||||
bluetoothGatt!!.writeCharacteristic(characteristic)
|
bluetoothGatt?.writeCharacteristic(characteristic)
|
||||||
}).start()
|
}).start()
|
||||||
|
waitMillis(50)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val uartReadBTGattChar: BluetoothGattCharacteristic
|
private val uartReadBTGattChar: BluetoothGattCharacteristic
|
||||||
|
@ -211,6 +236,7 @@ class BLEComm @Inject internal constructor(
|
||||||
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
aapsLogger.error("BluetoothAdapter not initialized_ERROR")
|
||||||
isConnecting = false
|
isConnecting = false
|
||||||
isConnected = false
|
isConnected = false
|
||||||
|
encryptedDataRead = false
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return bluetoothGatt?.services
|
return bluetoothGatt?.services
|
||||||
|
@ -243,6 +269,8 @@ class BLEComm @Inject internal constructor(
|
||||||
close()
|
close()
|
||||||
isConnected = false
|
isConnected = false
|
||||||
isConnecting = false
|
isConnecting = false
|
||||||
|
v3Encryption = false
|
||||||
|
encryptedDataRead = false
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED))
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Device was disconnected " + gatt.device.name) //Device was disconnected
|
||||||
}
|
}
|
||||||
|
@ -263,13 +291,20 @@ class BLEComm @Inject internal constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readDataParsing() {
|
private fun readDataParsing(receviedData: ByteArray) {
|
||||||
|
//aapsLogger.debug(LTag.PUMPBTCOMM, "readDataParsing")
|
||||||
var startSignatureFound = false
|
var startSignatureFound = false
|
||||||
var packetIsValid = false
|
var packetIsValid = false
|
||||||
var isProcessing: Boolean
|
var isProcessing: Boolean
|
||||||
isProcessing = true
|
isProcessing = true
|
||||||
var inputBuffer: ByteArray? = null
|
var inputBuffer: ByteArray? = null
|
||||||
|
|
||||||
|
// decrypt 2nd level after successful connection
|
||||||
|
val incomingBuffer = if (v3Encryption && isConnected)
|
||||||
|
bleEncryption.decryptSecondLevelPacket(receviedData).also { encryptedDataRead = true }
|
||||||
|
else receviedData
|
||||||
|
addToReadBuffer(incomingBuffer)
|
||||||
|
|
||||||
while (isProcessing) {
|
while (isProcessing) {
|
||||||
var length = 0
|
var length = 0
|
||||||
synchronized(readBuffer) {
|
synchronized(readBuffer) {
|
||||||
|
@ -321,85 +356,163 @@ class BLEComm @Inject internal constructor(
|
||||||
// decrypt the packet
|
// decrypt the packet
|
||||||
bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer ->
|
bleEncryption.getDecryptedPacket(inputBuffer)?.let { decryptedBuffer ->
|
||||||
when (decryptedBuffer[0]) {
|
when (decryptedBuffer[0]) {
|
||||||
BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte() -> when (decryptedBuffer[1]) {
|
BleEncryption.DANAR_PACKET__TYPE_ENCRYPTION_RESPONSE.toByte() ->
|
||||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK.toByte() -> if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
when (decryptedBuffer[1]) {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PUMP_CHECK.toByte() ->
|
||||||
// Grab pairing key from preferences if exists
|
if (decryptedBuffer.size == 4 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||||
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, "")
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Using stored pairing key: $pairingKey")
|
v3Encryption = false
|
||||||
if (pairingKey.isNotEmpty()) {
|
// Grab pairing key from preferences if exists
|
||||||
val encodedPairingKey = DanaRS_Packet.hexToBytes(pairingKey)
|
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
val bytes = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY, encodedPairingKey, null)
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Using stored pairing key: $pairingKey")
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(bytes))
|
if (pairingKey.isNotEmpty()) {
|
||||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
val encodedPairingKey = DanaRS_Packet.hexToBytes(pairingKey)
|
||||||
} else {
|
val bytes = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY, encodedPairingKey, null)
|
||||||
// Stored pairing key does not exists, request pairing
|
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(bytes))
|
||||||
sendPairingRequest()
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
}
|
} else {
|
||||||
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'P'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'M'.toByte() && decryptedBuffer[5] == 'P'.toByte()) {
|
// Stored pairing key does not exists, request pairing
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
sendPairingRequest()
|
||||||
mSendQueue.clear()
|
}
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.pumperror)))
|
} else if (decryptedBuffer.size == 9 && decryptedBuffer[2] == 'O'.toByte() && decryptedBuffer[3] == 'K'.toByte()) {
|
||||||
NSUpload.uploadError(resourceHelper.gs(R.string.pumperror))
|
// v3 2nd layer encryption
|
||||||
val n = Notification(Notification.PUMPERROR, resourceHelper.gs(R.string.pumperror), Notification.URGENT)
|
v3Encryption = true
|
||||||
rxBus.send(EventNewNotification(n))
|
val model = decryptedBuffer[5]
|
||||||
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'B'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'S'.toByte() && decryptedBuffer[5] == 'Y'.toByte()) {
|
// val protocol = decryptedBuffer[7]
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (BUSY)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
if (model == 0x05.toByte()) {
|
||||||
mSendQueue.clear()
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK V3 (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.pumpbusy)))
|
// Dana RS Pump
|
||||||
} else {
|
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
// ERROR in response, wrong serial number
|
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
if (randomPairingKey.isNotEmpty() && pairingKey.isNotEmpty()) {
|
||||||
mSendQueue.clear()
|
val randomSyncKey = String.format("%02x", decryptedBuffer[decryptedBuffer.size - 1])
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.connectionerror)))
|
sp.putString(resourceHelper.gs(R.string.key_danars_v3_randomsynckey) + danaRSPlugin.mDeviceName, randomSyncKey)
|
||||||
sp.remove(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName)
|
val tPairingKey = Base64.decode(pairingKey, Base64.DEFAULT)
|
||||||
val n = Notification(Notification.WRONGSERIALNUMBER, resourceHelper.gs(R.string.wrongpassword), Notification.URGENT)
|
val tRandomPairingKey = Base64.decode(randomPairingKey, Base64.DEFAULT)
|
||||||
rxBus.send(EventNewNotification(n))
|
var tRandomSyncKey: Byte = 0
|
||||||
}
|
if (randomSyncKey.isNotEmpty()) {
|
||||||
|
tRandomSyncKey = randomSyncKey.toInt(16).toByte()
|
||||||
|
}
|
||||||
|
bleEncryption.setPairingKeys(tPairingKey, tRandomPairingKey, tRandomSyncKey)
|
||||||
|
sendV3PairingInformation(0)
|
||||||
|
} else {
|
||||||
|
sendV3PairingInformation(1)
|
||||||
|
}
|
||||||
|
} else if (model == 0x06.toByte()) {
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK V3 EASY (OK)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
// Dana RS Easy
|
||||||
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_EASYMENU_CHECK, null, null)
|
||||||
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
}
|
||||||
|
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'P'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'M'.toByte() && decryptedBuffer[5] == 'P'.toByte()) {
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (PUMP)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
mSendQueue.clear()
|
||||||
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.pumperror)))
|
||||||
|
NSUpload.uploadError(resourceHelper.gs(R.string.pumperror))
|
||||||
|
val n = Notification(Notification.PUMPERROR, resourceHelper.gs(R.string.pumperror), Notification.URGENT)
|
||||||
|
rxBus.send(EventNewNotification(n))
|
||||||
|
} else if (decryptedBuffer.size == 6 && decryptedBuffer[2] == 'B'.toByte() && decryptedBuffer[3] == 'U'.toByte() && decryptedBuffer[4] == 'S'.toByte() && decryptedBuffer[5] == 'Y'.toByte()) {
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (BUSY)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
mSendQueue.clear()
|
||||||
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.pumpbusy)))
|
||||||
|
} else {
|
||||||
|
// ERROR in response, wrong serial number
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PUMP_CHECK (ERROR)" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
mSendQueue.clear()
|
||||||
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.DISCONNECTED, resourceHelper.gs(R.string.connectionerror)))
|
||||||
|
sp.remove(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName)
|
||||||
|
val n = Notification(Notification.WRONGSERIALNUMBER, resourceHelper.gs(R.string.wrongpassword), Notification.URGENT)
|
||||||
|
rxBus.send(EventNewNotification(n))
|
||||||
|
}
|
||||||
|
|
||||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY.toByte() -> {
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION.toByte() -> {
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
if (decryptedBuffer[2] == 0x00.toByte()) {
|
if (v3Encryption) {
|
||||||
// Paring is not requested, sending time info
|
// decryptedBuffer[2] : 0x00 OK 0x01 Error, No pairing
|
||||||
|
if (decryptedBuffer[2] == 0x00.toByte()) {
|
||||||
|
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
|
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
|
if (randomPairingKey.isNotEmpty() && pairingKey.isNotEmpty()) {
|
||||||
|
// expecting successful connect
|
||||||
|
isConnected = true
|
||||||
|
isConnecting = false
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Connect !!")
|
||||||
|
} else {
|
||||||
|
context.startActivity(Intent(context, EnterPinActivity::class.java).also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Request pairing keys !!")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sendV3PairingInformation(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
val size = decryptedBuffer.size
|
||||||
|
var pass: Int = (decryptedBuffer[size - 1].toInt() and 0x000000FF shl 8) + (decryptedBuffer[size - 2].toInt() and 0x000000FF)
|
||||||
|
pass = pass xor 3463
|
||||||
|
danaRPump.rsPassword = Integer.toHexString(pass)
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Pump user password: " + Integer.toHexString(pass))
|
||||||
|
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
|
||||||
|
isConnected = true
|
||||||
|
isConnecting = false
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "RS connected and status read")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__CHECK_PASSKEY.toByte() -> {
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__CHECK_PASSKEY" + " " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
if (decryptedBuffer[2] == 0x00.toByte()) {
|
||||||
|
// Paring is not requested, sending time info
|
||||||
|
sendTimeInfo()
|
||||||
|
} else {
|
||||||
|
// Pairing on pump is requested
|
||||||
|
sendPairingRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST.toByte() -> {
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PASSKEY_REQUEST " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
if (decryptedBuffer[2] != 0x00.toByte()) {
|
||||||
|
disconnect("passkey request failed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_RETURN.toByte() -> {
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PASSKEY_RETURN " + DanaRS_Packet.toHexString(decryptedBuffer))
|
||||||
|
// Paring is successful, sending time info
|
||||||
|
rxBus.send(EventDanaRSPairingSuccess())
|
||||||
sendTimeInfo()
|
sendTimeInfo()
|
||||||
} else {
|
val pairingKey = byteArrayOf(decryptedBuffer[2], decryptedBuffer[3])
|
||||||
// Pairing on pump is requested
|
// store pairing key to preferences
|
||||||
sendPairingRequest()
|
sp.putString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, DanaRS_Packet.bytesToHex(pairingKey))
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, "Got pairing key: " + DanaRS_Packet.bytesToHex(pairingKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_PUMP_CHECK.toByte() -> {
|
||||||
|
if (decryptedBuffer[2] == 0x05.toByte()) {
|
||||||
|
// not easy mode, request time info
|
||||||
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, null, null)
|
||||||
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
} else {
|
||||||
|
// easy mode
|
||||||
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_EASYMENU_CHECK, null, null)
|
||||||
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__GET_EASYMENU_CHECK.toByte() -> {
|
||||||
|
isEasyMode = decryptedBuffer[2] == 0x01.toByte()
|
||||||
|
isUnitUD = decryptedBuffer[3] == 0x01.toByte()
|
||||||
|
|
||||||
|
// request time information
|
||||||
|
if (v3Encryption) {
|
||||||
|
sendV3PairingInformation(1)
|
||||||
|
} else {
|
||||||
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, null, null)
|
||||||
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST.toByte() -> {
|
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PASSKEY_REQUEST " + DanaRS_Packet.toHexString(decryptedBuffer))
|
|
||||||
if (decryptedBuffer[2] != 0x00.toByte()) {
|
|
||||||
disconnect("passkey request failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_RETURN.toByte() -> {
|
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__PASSKEY_RETURN " + DanaRS_Packet.toHexString(decryptedBuffer))
|
|
||||||
// Paring is successful, sending time info
|
|
||||||
rxBus.send(EventDanaRSPairingSuccess())
|
|
||||||
sendTimeInfo()
|
|
||||||
val pairingKey = byteArrayOf(decryptedBuffer[2], decryptedBuffer[3])
|
|
||||||
// store pairing key to preferences
|
|
||||||
sp.putString(resourceHelper.gs(R.string.key_danars_pairingkey) + danaRSPlugin.mDeviceName, DanaRS_Packet.bytesToHex(pairingKey))
|
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Got pairing key: " + DanaRS_Packet.bytesToHex(pairingKey))
|
|
||||||
}
|
|
||||||
|
|
||||||
BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION.toByte() -> {
|
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "<<<<< " + "ENCRYPTION__TIME_INFORMATION " + /*message.getMessageName() + " " + */DanaRS_Packet.toHexString(decryptedBuffer))
|
|
||||||
val size = decryptedBuffer.size
|
|
||||||
var pass: Int = (decryptedBuffer[size - 1].toInt() and 0x000000FF shl 8) + (decryptedBuffer[size - 2].toInt() and 0x000000FF)
|
|
||||||
pass = pass xor 3463
|
|
||||||
danaRPump.rsPassword = Integer.toHexString(pass)
|
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "Pump user password: " + Integer.toHexString(pass))
|
|
||||||
rxBus.send(EventPumpStatusChanged(EventPumpStatusChanged.Status.CONNECTED))
|
|
||||||
isConnected = true
|
|
||||||
isConnecting = false
|
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, "RS connected and status read")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
// Retrieve message code from received buffer and last message sent
|
// Retrieve message code from received buffer and last message sent
|
||||||
val originalCommand = processedMessage?.command ?: 0xFFFF
|
val originalCommand = processedMessage?.command ?: 0xFFFF
|
||||||
|
@ -449,6 +562,8 @@ class BLEComm @Inject internal constructor(
|
||||||
val params = message.requestParams
|
val params = message.requestParams
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + message.friendlyName + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params))
|
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + message.friendlyName + " " + DanaRS_Packet.toHexString(command) + " " + DanaRS_Packet.toHexString(params))
|
||||||
var bytes = bleEncryption.getEncryptedPacket(message.opCode, params, null)
|
var bytes = bleEncryption.getEncryptedPacket(message.opCode, params, null)
|
||||||
|
if (v3Encryption)
|
||||||
|
bytes = bleEncryption.encryptSecondLevelPacket(bytes)
|
||||||
// If there is another message not completely sent, add to queue only
|
// If there is another message not completely sent, add to queue only
|
||||||
if (mSendQueue.size > 0) {
|
if (mSendQueue.size > 0) {
|
||||||
// Split to parts per 20 bytes max
|
// Split to parts per 20 bytes max
|
||||||
|
@ -509,13 +624,30 @@ class BLEComm @Inject internal constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun finishV3Pairing() {
|
||||||
|
val randomPairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_randompairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
|
val pairingKey = sp.getString(resourceHelper.gs(R.string.key_danars_v3_pairingkey) + danaRSPlugin.mDeviceName, "")
|
||||||
|
if (randomPairingKey.isNotEmpty() && pairingKey.isNotEmpty()) {
|
||||||
|
val tPairingKey = Base64.decode(pairingKey, Base64.DEFAULT)
|
||||||
|
val tRandomPairingKey = Base64.decode(randomPairingKey, Base64.DEFAULT)
|
||||||
|
val tRandomSyncKey: Byte = 0
|
||||||
|
bleEncryption.setPairingKeys(tPairingKey, tRandomPairingKey, tRandomSyncKey)
|
||||||
|
sendV3PairingInformation(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0x00 Start encryption, 0x01 Request pairing
|
||||||
|
private fun sendV3PairingInformation(requestNewPairing: Int) {
|
||||||
|
val params = byteArrayOf(requestNewPairing.toByte())
|
||||||
|
val bytes: ByteArray = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__TIME_INFORMATION, params, null)
|
||||||
|
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__TIME_INFORMATION" + " " + DanaRS_Packet.toHexString(bytes))
|
||||||
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
}
|
||||||
|
|
||||||
private fun sendPairingRequest() {
|
private fun sendPairingRequest() {
|
||||||
// Start activity which is waiting 20sec
|
// Start activity which is waiting 20sec
|
||||||
// On pump pairing request is displayed and is waiting for conformation
|
// On pump pairing request is displayed and is waiting for conformation
|
||||||
val i = Intent()
|
context.startActivity(Intent(context, PairingHelperActivity::class.java).also { it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) })
|
||||||
i.setClass(context, PairingHelperActivity::class.java)
|
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
||||||
context.startActivity(i)
|
|
||||||
val bytes = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST, null, null)
|
val bytes = bleEncryption.getEncryptedPacket(BleEncryption.DANAR_PACKET__OPCODE_ENCRYPTION__PASSKEY_REQUEST, null, null)
|
||||||
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__PASSKEY_REQUEST" + " " + DanaRS_Packet.toHexString(bytes))
|
aapsLogger.debug(LTag.PUMPBTCOMM, ">>>>> " + "ENCRYPTION__PASSKEY_REQUEST" + " " + DanaRS_Packet.toHexString(bytes))
|
||||||
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
writeCharacteristicNoResponse(uartWriteBTGattChar, bytes)
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
package info.nightscout.androidaps.utils.extensions
|
||||||
|
|
||||||
|
private val HEX_CHARS = "0123456789ABCDEF".toCharArray()
|
||||||
|
|
||||||
|
fun ByteArray.toHex() : String{
|
||||||
|
val result = StringBuffer()
|
||||||
|
|
||||||
|
forEach {
|
||||||
|
val octet = it.toInt()
|
||||||
|
val firstIndex = (octet and 0xF0).ushr(4)
|
||||||
|
val secondIndex = octet and 0x0F
|
||||||
|
result.append(HEX_CHARS[firstIndex])
|
||||||
|
result.append(HEX_CHARS[secondIndex])
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun String.hexStringToByteArray() : ByteArray {
|
||||||
|
|
||||||
|
val result = ByteArray(length / 2)
|
||||||
|
|
||||||
|
for (i in 0 until length step 2) {
|
||||||
|
val firstIndex = HEX_CHARS.indexOf(this[i]);
|
||||||
|
val secondIndex = HEX_CHARS.indexOf(this[i + 1]);
|
||||||
|
|
||||||
|
val octet = firstIndex.shl(4).or(secondIndex)
|
||||||
|
result.set(i.shr(1), octet.toByte())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
|
@ -15,6 +15,9 @@ class DefaultEditTextValidator : EditTextValidator {
|
||||||
protected var testErrorString: String? = null
|
protected var testErrorString: String? = null
|
||||||
protected var emptyAllowed = false
|
protected var emptyAllowed = false
|
||||||
protected lateinit var editTextView: EditText
|
protected lateinit var editTextView: EditText
|
||||||
|
private var tw: TextWatcher? = null
|
||||||
|
private var defaultEmptyErrorString: String? = null
|
||||||
|
|
||||||
protected var testType: Int
|
protected var testType: Int
|
||||||
protected var classType: String? = null
|
protected var classType: String? = null
|
||||||
protected var customRegexp: String? = null
|
protected var customRegexp: String? = null
|
||||||
|
@ -26,8 +29,6 @@ class DefaultEditTextValidator : EditTextValidator {
|
||||||
protected var maxNumber = 0
|
protected var maxNumber = 0
|
||||||
protected var floatminNumber = 0f
|
protected var floatminNumber = 0f
|
||||||
protected var floatmaxNumber = 0f
|
protected var floatmaxNumber = 0f
|
||||||
private var tw: TextWatcher? = null
|
|
||||||
private var defaultEmptyErrorString: String? = null
|
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
constructor(editTextView: EditText, context: Context) {
|
constructor(editTextView: EditText, context: Context) {
|
||||||
|
@ -167,44 +168,50 @@ class DefaultEditTextValidator : EditTextValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun setClassType(classType: String?, testErrorString: String?, context: Context) {
|
fun setClassType(classType: String?, testErrorString: String?, context: Context) : DefaultEditTextValidator{
|
||||||
testType = EditTextValidator.TEST_CUSTOM
|
testType = EditTextValidator.TEST_CUSTOM
|
||||||
this.classType = classType
|
this.classType = classType
|
||||||
this.testErrorString = testErrorString
|
this.testErrorString = testErrorString
|
||||||
resetValidators(context)
|
resetValidators(context)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun setCustomRegexp(customRegexp: String?, context: Context) {
|
fun setCustomRegexp(customRegexp: String?, context: Context) : DefaultEditTextValidator {
|
||||||
testType = EditTextValidator.TEST_REGEXP
|
testType = EditTextValidator.TEST_REGEXP
|
||||||
this.customRegexp = customRegexp
|
this.customRegexp = customRegexp
|
||||||
resetValidators(context)
|
resetValidators(context)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun setEmptyAllowed(emptyAllowed: Boolean, context: Context) {
|
fun setEmptyAllowed(emptyAllowed: Boolean, context: Context) : DefaultEditTextValidator {
|
||||||
this.emptyAllowed = emptyAllowed
|
this.emptyAllowed = emptyAllowed
|
||||||
resetValidators(context)
|
resetValidators(context)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setEmptyErrorString(emptyErrorString: String?) {
|
fun setEmptyErrorString(emptyErrorString: String?) : DefaultEditTextValidator {
|
||||||
emptyErrorStringActual = if (!TextUtils.isEmpty(emptyErrorString)) {
|
emptyErrorStringActual = if (!TextUtils.isEmpty(emptyErrorString)) {
|
||||||
emptyErrorString
|
emptyErrorString
|
||||||
} else {
|
} else {
|
||||||
defaultEmptyErrorString
|
defaultEmptyErrorString
|
||||||
}
|
}
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun setTestErrorString(testErrorString: String?, context: Context) {
|
fun setTestErrorString(testErrorString: String?, context: Context) : DefaultEditTextValidator {
|
||||||
this.testErrorString = testErrorString
|
this.testErrorString = testErrorString
|
||||||
resetValidators(context)
|
resetValidators(context)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
fun setTestType(testType: Int, context: Context) {
|
fun setTestType(testType: Int, context: Context) : DefaultEditTextValidator {
|
||||||
this.testType = testType
|
this.testType = testType
|
||||||
resetValidators(context)
|
resetValidators(context)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun testValidity(): Boolean {
|
override fun testValidity(): Boolean {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package info.nightscout.androidaps.utils.textValidator
|
package info.nightscout.androidaps.utils.textValidator
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import androidx.core.content.res.TypedArrayUtils
|
import androidx.core.content.res.TypedArrayUtils
|
||||||
|
@ -22,7 +23,7 @@ class ValidatingEditTextPreference(ctx: Context, attrs: AttributeSet, defStyleAt
|
||||||
constructor(ctx: Context, attrs: AttributeSet, defStyle: Int)
|
constructor(ctx: Context, attrs: AttributeSet, defStyle: Int)
|
||||||
: this(ctx, attrs, defStyle, 0)
|
: this(ctx, attrs, defStyle, 0)
|
||||||
|
|
||||||
constructor(ctx: Context, attrs: AttributeSet)
|
@SuppressLint("RestrictedApi") constructor(ctx: Context, attrs: AttributeSet)
|
||||||
: this(ctx, attrs, TypedArrayUtils.getAttr(ctx, R.attr.editTextPreferenceStyle,
|
: this(ctx, attrs, TypedArrayUtils.getAttr(ctx, R.attr.editTextPreferenceStyle,
|
||||||
R.attr.editTextPreferenceStyle))
|
R.attr.editTextPreferenceStyle))
|
||||||
|
|
||||||
|
|
90
app/src/main/res/layout/danars_enter_pin_activity.xml
Normal file
90
app/src/main/res/layout/danars_enter_pin_activity.xml
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
tools:context=".plugins.pump.danaRS.activities.EnterPinActivity">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="@color/activity_title_background"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="5dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:contentDescription="@string/pairing"
|
||||||
|
android:src="@drawable/ic_bluetooth_white_48dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerInParent="true"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginLeft="10dp"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:text="@string/pairing"
|
||||||
|
android:textAlignment="center"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:labelFor="@+id/rs_v3_pin1"
|
||||||
|
android:text="@string/num1pin"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/rs_v3_pin1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autofillHints="@string/pin1"
|
||||||
|
android:digits="0123456789ABCDEF"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:inputType="textCapCharacters"
|
||||||
|
android:text=""
|
||||||
|
android:textSize="25sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="10dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:labelFor="@+id/rs_v3_pin2"
|
||||||
|
android:text="@string/num2pin"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||||
|
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/rs_v3_pin2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:autofillHints="@string/pin2"
|
||||||
|
android:digits="0123456789ABCDEF"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:inputType="textCapCharacters"
|
||||||
|
android:text=""
|
||||||
|
android:textSize="25sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="10dp"
|
||||||
|
android:layout_marginBottom="20dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:text="@string/press_ok_on_the_pump"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
|
||||||
|
|
||||||
|
<include layout="@layout/okcancel" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -417,6 +417,7 @@
|
||||||
<string name="open_settings_on_wear">Open Settings on Wear</string>
|
<string name="open_settings_on_wear">Open Settings on Wear</string>
|
||||||
<string name="pumperror">Pump Error</string>
|
<string name="pumperror">Pump Error</string>
|
||||||
<string name="lowbattery">Low Battery</string>
|
<string name="lowbattery">Low Battery</string>
|
||||||
|
<string name="basalcompare">Delivering less than preset basal rate</string>
|
||||||
<string name="pumpshutdown">Pump Shutdown</string>
|
<string name="pumpshutdown">Pump Shutdown</string>
|
||||||
<string name="batterydischarged">Pump Battery Discharged</string>
|
<string name="batterydischarged">Pump Battery Discharged</string>
|
||||||
<string name="danarkoreanpump">DanaR Korean</string>
|
<string name="danarkoreanpump">DanaR Korean</string>
|
||||||
|
@ -731,12 +732,16 @@
|
||||||
<string name="pairingtimedout">Pairing timed out</string>
|
<string name="pairingtimedout">Pairing timed out</string>
|
||||||
<string name="pairing">Pairing</string>
|
<string name="pairing">Pairing</string>
|
||||||
<string name="key_danars_pairingkey" translatable="false">danars_pairing_key_</string>
|
<string name="key_danars_pairingkey" translatable="false">danars_pairing_key_</string>
|
||||||
|
<string name="key_danars_v3_randompairingkey" translatable="false">danars_v3_randompairing_key_</string>
|
||||||
|
<string name="key_danars_v3_pairingkey" translatable="false">danars_v3_pairing_key_</string>
|
||||||
|
<string name="key_danars_v3_randomsynckey" translatable="false">danars_v3_randomsync_key_</string>
|
||||||
<string name="key_danars_address" translatable="false">danars_address</string>
|
<string name="key_danars_address" translatable="false">danars_address</string>
|
||||||
<string name="key_danars_name" translatable="false">danars_name</string>
|
<string name="key_danars_name" translatable="false">danars_name</string>
|
||||||
<string name="danars_nodeviceavailable">No device found so far</string>
|
<string name="danars_nodeviceavailable">No device found so far</string>
|
||||||
<string name="emptyreservoir">Empty reservoir</string>
|
<string name="emptyreservoir">Empty reservoir</string>
|
||||||
<string name="bloodsugarmeasurementalert">Blood sugar measurement alert</string>
|
<string name="bloodsugarmeasurementalert">Blood sugar measurement alert</string>
|
||||||
<string name="remaininsulinalert">Remaining insulin level</string>
|
<string name="remaininsulinalert">Remaining insulin level</string>
|
||||||
|
<string name="missedbolus">Missed bolus</string>
|
||||||
<string name="danarspump">DanaRS</string>
|
<string name="danarspump">DanaRS</string>
|
||||||
<string name="danarspump_shortname">Dana</string>
|
<string name="danarspump_shortname">Dana</string>
|
||||||
<string name="selectedpump">Selected pump</string>
|
<string name="selectedpump">Selected pump</string>
|
||||||
|
@ -1736,4 +1741,11 @@
|
||||||
<string name="smscommunicator_otp_install_info">On each follower phone install Authenticator app that support RFC 6238 TOTP tokens. Popular free apps are:\n • Authy\n • Google Authenticator\n • LastPass Authenticator\n • FreeOTP Authenticator</string>
|
<string name="smscommunicator_otp_install_info">On each follower phone install Authenticator app that support RFC 6238 TOTP tokens. Popular free apps are:\n • Authy\n • Google Authenticator\n • LastPass Authenticator\n • FreeOTP Authenticator</string>
|
||||||
<string name="smscommunicator_otp_provisioning_warning">DO NOT SHARE this code online!\nUse it only to setup Authenticator App on follower phones.</string>
|
<string name="smscommunicator_otp_provisioning_warning">DO NOT SHARE this code online!\nUse it only to setup Authenticator App on follower phones.</string>
|
||||||
<string name="smscommunicator_otp_reset_warning">By reseting authenticator you make all already provisioned authenticators invalid. You will need to set up them again!</string>
|
<string name="smscommunicator_otp_reset_warning">By reseting authenticator you make all already provisioned authenticators invalid. You will need to set up them again!</string>
|
||||||
|
<string name="pin1">PIN1</string>
|
||||||
|
<string name="pin2">PIN2</string>
|
||||||
|
<string name="press_ok_on_the_pump">Press OK on the pump\nand enter 2 displayed numbers\nKeep display on pump ON by pressing minus button until you finish entering code.</string>
|
||||||
|
<string name="num1pin">1: (12 digits)</string>
|
||||||
|
<string name="num2pin">2: (8 digits)</string>
|
||||||
|
<string name="resetpairing">Reset pairing information?</string>
|
||||||
|
<string name="invalidpairing">Invalid pairing information. Requesting new pairing</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -16,9 +16,13 @@
|
||||||
<string name="error_date_not_valid">Format not valid</string>
|
<string name="error_date_not_valid">Format not valid</string>
|
||||||
<string name="error_mustbe4digitnumber">Must be 4 digit number</string>
|
<string name="error_mustbe4digitnumber">Must be 4 digit number</string>
|
||||||
<string name="error_mustbe6digitnumber">Must be 6 digit number</string>
|
<string name="error_mustbe6digitnumber">Must be 6 digit number</string>
|
||||||
|
<string name="error_mustbe12hexadidits">Must be 12 characters of ABCDEF0123456789</string>
|
||||||
|
<string name="error_mustbe8hexadidits">Must be 8 characters of ABCDEF0123456789</string>
|
||||||
<string name="error_not_a_minimum_length">Not a minimum length</string>
|
<string name="error_not_a_minimum_length">Not a minimum length</string>
|
||||||
<string name="error_pin_not_valid">Pin should be 3 to 6 digits, not same or in series</string>
|
<string name="error_pin_not_valid">Pin should be 3 to 6 digits, not same or in series</string>
|
||||||
|
|
||||||
<string name="fourdigitnumber" translatable="false">^\\d{4}</string>
|
<string name="fourdigitnumber" translatable="false">^\\d{4}</string>
|
||||||
|
<string name="twelvehexanumber" translatable="false">^[A-F0-9]{12}$</string>
|
||||||
|
<string name="eighthexanumber" translatable="false">^[A-F0-9]{8}$</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -14,7 +14,7 @@ import org.powermock.modules.junit4.PowerMockRunner
|
||||||
class DanaRS_Packet_Notify_AlarmTest : DanaRSTestBase() {
|
class DanaRS_Packet_Notify_AlarmTest : DanaRSTestBase() {
|
||||||
|
|
||||||
@Test fun runTest() {
|
@Test fun runTest() {
|
||||||
val packet = DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper)
|
val packet = DanaRS_Packet_Notify_Alarm(aapsLogger, resourceHelper, rxBus)
|
||||||
// test params
|
// test params
|
||||||
Assert.assertEquals(null, packet.requestParams)
|
Assert.assertEquals(null, packet.requestParams)
|
||||||
// test message decoding
|
// test message decoding
|
||||||
|
|
Loading…
Reference in a new issue