From 439ee1bb0b1be00d00c151660774fb488f81a339 Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Thu, 30 Aug 2018 17:29:25 -0400 Subject: [PATCH 01/11] add crc checking --- .../GlucoseFeatureCharacteristic.kt | 2 +- .../GlucoseMeasurementCharacteristic.kt | 5 +- ...GlucoseMeasurementContextCharacteristic.kt | 2 +- .../PnPIdCharacteristic.kt | 2 +- .../SystemIdCharacteristic.kt | 2 +- .../StringCharacteristicDeclarations.kt | 2 +- .../CgmFeatureCharacteristic.kt | 7 ++ .../common/BaseCharacteristic.kt | 2 +- .../characteristic => }/common/Composable.kt | 3 +- .../common/StringCharacteristic.kt | 2 +- .../{ => bgm}/bgmmeasurement/Flags.kt | 0 .../bgmmeasurement/SampleLocation.kt | 0 .../SensorStatusAnnunciation.kt | 0 .../{ => bgm}/bgmmeasurement/Type.kt | 0 .../cgm/cgmcp/CalibrationStatus.kt | 25 ++++++ .../encodedvalue/cgm/cgmcp/Opcode.kt | 39 ++++++++++ .../encodedvalue/cgm/cgmcp/ResponseCode.kt | 15 ++++ .../cgm/feature/CgmSampleLocation.kt | 22 ++++++ .../encodedvalue/cgm/feature/CgmType.kt | 22 ++++++ .../encodedvalue/cgm/feature/Flags.kt | 38 +++++++++ .../encodedvalue/cgm/measurement/Flags.kt | 26 +++++++ .../measurement/SensorStatusAnnunciation.kt | 41 ++++++++++ .../encodedvalue/cgm/racp/Filter.kt | 11 +++ .../encodedvalue/cgm/racp/Opcode.kt | 18 +++++ .../encodedvalue/cgm/racp/Operator.kt | 17 ++++ .../encodedvalue/cgm/racp/ResponseCode.kt | 20 +++++ .../{bgm => }/utility/BluetoothDateTime.kt | 5 +- .../jdrfandroidbleparser/utility/CrcHelper.kt | 78 +++++++++++++++++++ .../StringCharacteristicTest.kt | 2 +- .../GlucoseMeasurementCharacteristicTest.kt | 6 +- .../bgm}/bgmcontext/FlagsTest.kt | 2 +- .../{ => bgm}/bgmmeasurement/FlagsTest.kt | 3 +- .../SensorStatusAnnunciationTest.kt | 3 +- .../encodedvalue/cgm/feature/FlagsTest.kt | 34 ++++++++ .../encodedvalue/cgm/measurement/FlagsTest.kt | 32 ++++++++ .../SensorStatusAnnunciationTest.kt | 31 ++++++++ .../utility/CrcHelperTest.kt | 12 +++ 37 files changed, 504 insertions(+), 27 deletions(-) create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/{bgm/characteristic => }/common/BaseCharacteristic.kt (98%) rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/{bgm/characteristic => }/common/Composable.kt (85%) rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/{bgm/characteristic => }/common/StringCharacteristic.kt (90%) rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/{ => bgm}/bgmmeasurement/Flags.kt (100%) rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/{ => bgm}/bgmmeasurement/SampleLocation.kt (100%) rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/{ => bgm}/bgmmeasurement/SensorStatusAnnunciation.kt (100%) rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/{ => bgm}/bgmmeasurement/Type.kt (100%) create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt rename jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/{bgm => }/utility/BluetoothDateTime.kt (82%) create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt rename jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/{encodedvalues => encodedvalue/bgm}/bgmcontext/FlagsTest.kt (98%) rename jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/{ => bgm}/bgmmeasurement/FlagsTest.kt (95%) rename jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/{ => bgm}/bgmmeasurement/SensorStatusAnnunciationTest.kt (96%) create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseFeatureCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseFeatureCharacteristic.kt index 5bfcdb7..c995cc2 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseFeatureCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseFeatureCharacteristic.kt @@ -1,7 +1,7 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.feature.Flags import java.util.* diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt index d6c9c7a..544b968 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt @@ -1,13 +1,12 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import android.bluetooth.BluetoothGattCharacteristic -import android.util.Log -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Flags import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.SampleLocation import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.SensorStatusAnnunciation import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Type -import org.ehealthinnovation.jdrfandroidbleparser.bgm.utility.BluetoothDateTime +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.Units import java.util.* diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementContextCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementContextCharacteristic.kt index caa6208..6332153 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementContextCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementContextCharacteristic.kt @@ -1,7 +1,7 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.Units import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.contextmeasurement.* diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt index df37fe7..e8dbced 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt @@ -1,7 +1,7 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.dis.pnpid.VendorId import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.dis.pnpid.VendorId.Companion.fromVendorId diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt index aa39c43..e3c2b02 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt @@ -1,7 +1,7 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import kotlin.jvm.java diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/stringcharacteristics/StringCharacteristicDeclarations.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/stringcharacteristics/StringCharacteristicDeclarations.kt index 8cbaee0..b9f55c8 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/stringcharacteristics/StringCharacteristicDeclarations.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/stringcharacteristics/StringCharacteristicDeclarations.kt @@ -1,7 +1,7 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.stringcharacteristics import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.StringCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.StringCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic.* import kotlin.jvm.java diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt new file mode 100644 index 0000000..b8e66ed --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt @@ -0,0 +1,7 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +/** + * + */ +class CgmFeatureCharacteristic { +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/BaseCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt similarity index 98% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/BaseCharacteristic.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt index 93400f9..b9d78d3 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/BaseCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt @@ -1,4 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common +package org.ehealthinnovation.jdrfandroidbleparser.common import android.bluetooth.BluetoothGattCharacteristic import android.util.Log diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/Composable.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt similarity index 85% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/Composable.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt index a65a2f4..fed7c06 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/Composable.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt @@ -1,6 +1,5 @@ -package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common +package org.ehealthinnovation.jdrfandroidbleparser.common -import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic /** diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/StringCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/StringCharacteristic.kt similarity index 90% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/StringCharacteristic.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/StringCharacteristic.kt index cfb8c40..6ead04e 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/common/StringCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/StringCharacteristic.kt @@ -1,4 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common +package org.ehealthinnovation.jdrfandroidbleparser.common import android.bluetooth.BluetoothGattCharacteristic import kotlin.jvm.java diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/Flags.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/Flags.kt similarity index 100% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/Flags.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/Flags.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SampleLocation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SampleLocation.kt similarity index 100% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SampleLocation.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SampleLocation.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SensorStatusAnnunciation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SensorStatusAnnunciation.kt similarity index 100% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SensorStatusAnnunciation.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SensorStatusAnnunciation.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/Type.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/Type.kt similarity index 100% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/Type.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/Type.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt new file mode 100644 index 0000000..16eb1a0 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt @@ -0,0 +1,25 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.cgmcp + +import java.util.* + +enum class CalibrationStatus constructor(val bit: Int) { + CALIBRATION_DATA_REJECTED(1 shl 0), + CALIBRATION_DATA_OUT_OF_RANGE(1 shl 1), + CALIBRATION_PROCESS_PENDING(1 shl 2); + + companion object { + /** + * Takes a passed in 8bit flag value and extracts the set mask values. Returns an + * [EnumSet]<[CalibrationStatus]> of set properties + */ + fun parseFlags(calibrationStatusFlag: Int): EnumSet { + val setFlags = EnumSet.noneOf(CalibrationStatus::class.java) + CalibrationStatus.values().forEach { + val flag = it.bit + if (flag and calibrationStatusFlag == flag) setFlags.add(it) + } + return setFlags + } + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt new file mode 100644 index 0000000..b00bad5 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt @@ -0,0 +1,39 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.cgmcp + +enum class Opcode constructor(val key: Int) { + RESERVED_FOR_FUTURE_USE(0), + SET_CGM_COMMUNICATION_INTERVAL(1), + GET_CGM_COMMUNICATION_INTERVAL(2), + CGM_COMMUNICATION_INTERVAL_RESPONSE(3), + SET_GLUCOSE_CALIBRATION_VALUE(4), + GET_GLUCOSE_CALIBRATION_VALUE(5), + GLUCOSE_CALIBRATION_VALUE_RESPONSE(6), + SET_PATIENT_HIGH_ALERT_LEVEL(7), + GET_PATIENT_HIGH_ALERT_LEVEL(8), + PATIENT_HIGH_ALERT_LEVEL_RESPONSE(9), + SET_PATIENT_LOW_ALERT_LEVEL(10), + GET_PATIENT_LOW_ALERT_LEVEL(11), + PATIENT_LOW_ALERT_LEVEL_RESPONSE(12), + SET_HYPO_ALERT_LEVEL(13), + GET_HYPO_ALERT_LEVEL(14), + HYPO_ALERT_LEVEL_RESPONSE(15), + SET_HYPER_ALERT_LEVEL(16), + GET_HYPER_ALERT_LEVEL(17), + HYPER_ALERT_LEVEL_RESPONSE(18), + SET_RATE_OF_DECREASE_ALERT_LEVEL(19), + GET_RATE_OF_DECREASE_ALERT_LEVEL(20), + RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE(21), + SET_RATE_OF_INCREASE_ALERT_LEVEL(22), + GET_RATE_OF_INCREASE_ALERT_LEVEL(23), + RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE(24), + RESET_DEVICE_SPECIFIC_ALERT(25), + START_THE_SESSION(26), + STOP_THE_SESSION(27), + RESPONSE_CODE(28); + + companion object { + private val map = Opcode.values().associateBy(Opcode::key) + fun fromKey(type: Int) = map[type] + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt new file mode 100644 index 0000000..0058b40 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt @@ -0,0 +1,15 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.cgmcp + +enum class ResponseCode constructor(val key: Int) { + RESERVED_FOR_FUTURE_USE(0), + SUCCESS(1), + OP_CODE_NOT_SUPPORTED(2), + INVALID_OPERAND(3), + PROCEDURE_NOT_COMPLETED(4), + PARAMETER_OUT_OF_RANGE(5); + + companion object { + private val map = ResponseCode.values().associateBy (ResponseCode::key) + fun fromKey(key: Int) = map[key] + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt new file mode 100644 index 0000000..4865687 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt @@ -0,0 +1,22 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature + +enum class CgmSampleLocation constructor(val key: Int) { + + RESERVED_FOR_FUTURE_USE(0), + CAPILLARY_WHOLE_BLOOD(1), + CAPILLARY_PLASMA(2), + VENOUS_WHOLE_BLOOD(3), + VENOUS_PLASMA(4), + ARTERIAL_WHOLE_BLOOD(5), + ARTERIAL_PLASMA(6), + UNDETERMINED_WHOLE_BLOOD(7), + UNDETERMINED_PLASMA(8), + INTERSTITIAL_FLUID(9), + CONTROL_SOLUTION(10); + + + companion object { + private val map = CgmSampleLocation.values().associateBy(CgmSampleLocation::key) + fun fromKey(type: Int) = map[type] + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt new file mode 100644 index 0000000..79f66c3 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt @@ -0,0 +1,22 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature + +enum class CgmType constructor(val key: Int) { + + RESERVED_FOR_FUTURE_USE(0), + CAPILLARY_WHOLE_BLOOD(1), + CAPILLARY_PLASMA(2), + VENOUS_WHOLE_BLOOD(3), + VENOUS_PLASMA(4), + ARTERIAL_WHOLE_BLOOD(5), + ARTERIAL_PLASMA(6), + UNDETERMINED_WHOLE_BLOOD(7), + UNDETERMINED_PLASMA(8), + INTERSTITIAL_FLUID(9), + CONTROL_SOLUTION(10); + + + companion object { + private val map = CgmType.values().associateBy(CgmType::key) + fun fromKey(type: Int) = map[type] + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt new file mode 100644 index 0000000..831b9bf --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt @@ -0,0 +1,38 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature + +import java.util.* + +enum class Flags constructor(val bit: Int) { + CALIBRATION_SUPPORTED(1 shl 0), + PATIENT_HIGH_LOW_ALERTS_SUPPORTED(1 shl 1), + HYPO_ALERTS_SUPPORTED(1 shl 2), + HYPER_ALERTS_SUPPORTED(1 shl 3), + RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED(1 shl 4), + DEVICE_SPECIFIC_ALERT_SUPPORTED(1 shl 5), + SENSOR_MALFUNCTION_DETECTION_SUPPORTED(1 shl 6), + SENSOR_TEMPERATURE_HIGH_LOW_DETECTION_SUPPORTED(1 shl 7), + SENSOR_RESULT_HIGH_LOW_DETECTION_SUPPORTED(1 shl 8), + LOW_BATTERY_DETECTION_SUPPORTED(1 shl 9), + SENSOR_TYPE_ERROR_DETECTION_SUPPORTED(1 shl 10), + GENERAL_DEVICE_FAULT_SUPPORTED(1 shl 11), + E2E_CRC_SUPPORTED(1 shl 12), + MULTIPLE_BOND_SUPPORTED(1 shl 13), + MULTIPLE_SESSIONS_SUPPORTED(1 shl 14), + CGM_TREND_INFORMATION_SUPPORTED(1 shl 15), + CGM_QUALITY_SUPPORTED(1 shl 16); + + companion object { + /** + * Takes a passed in 8bit flag value and extracts the set mask values. Returns an + * [EnumSet]<[Flags]> of set properties + */ + fun parseFlags(characteristicFlags: Int): EnumSet { + val setFlags = EnumSet.noneOf(Flags::class.java) + Flags.values().forEach { + val flag = it.bit + if(flag and characteristicFlags == flag) setFlags.add(it) + } + return setFlags + } + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt new file mode 100644 index 0000000..9d21f85 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt @@ -0,0 +1,26 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement + +import java.util.* + +enum class Flags constructor(val bit: Int) { + CGM_TREND_INFORMATION_PRESENT(1 shl 0), + CGM_QUALITY_PRESENT(1 shl 1), + SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT(1 shl 5), + SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT(1 shl 6), + SENSOR_STATUS_ANNUNCIATION_FIELD_STATUS_OCTET_PRESENT(1 shl 7); + + companion object { + /** + * Takes a passed in 8bit flag value and extracts the set mask values. Returns an + * [EnumSet]<[Flags]> of set properties + */ + fun parseFlags(characteristicFlags: Int): EnumSet { + val setFlags = EnumSet.noneOf(Flags::class.java) + Flags.values().forEach { + val flag = it.bit + if(flag and characteristicFlags == flag) setFlags.add(it) + } + return setFlags + } + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt new file mode 100644 index 0000000..ba6f4d8 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt @@ -0,0 +1,41 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement + +import java.util.* + +enum class SensorStatusAnnunciation constructor(val bit: Int) { + SESSION_STOPPED(1 shl 0), + DEVICE_BATTERY_LOW(1 shl 1), + SENSOR_TYPE_INCORRECT_FOR_DEVICE(1 shl 2), + SENSOR_MALFUNCTION(1 shl 3), + DEVICE_SPECIFIC_ALERT(1 shl 4), + GENERAL_DEVICE_FAULT_HAS_OCCURRED_IN_THE_SENSOR(1 shl 5), + TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED(1 shl 8), + CALIBRATION_NOT_ALLOWED(1 shl 9), + CALIBRATION_RECOMMENDED(1 shl 10), + CALIBRATION_REQUIRED(1 shl 11), + SENSOR_TEMPERATURE_TOO_HIGH_FOR_VALID_RESULT_AT_TIME_OF_MEASUREMENT(1 shl 12), + SENSOR_TEMPERATURE_TOO_LOW_FOR_VALID_RESULT_AT_TIME_OF_MEASUREMENT(1 shl 13), + SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL(1 shl 16), + SENSOR_RESULT_HIGHER_THAN_THE_PATIENT_HIGH_LEVEL(1 shl 17), + SENSOR_RESULT_LOWER_THAN_THE_HYPO_LEVEL(1 shl 18), + SENSOR_RESULT_HIGHER_THAN_THE_HYPER_LEVEL(1 shl 19), + SENSOR_RATE_OF_DECREASE_EXCEEDED(1 shl 20), + SENSOR_RATE_OF_INCREASE_EXCEEDED(1 shl 21), + SENSOR_RESULT_LOWER_THAN_THE_DEVICE_CAN_PROCESS(1 shl 22), + SENSOR_RESULT_HIGHER_THAN_THE_DEVICE_CAN_PROCESS(1 shl 23); + + companion object { + /** + * Takes a passed in 8bit flag value and extracts the set mask values. Returns an + * [EnumSet]<[SensorStatusAnnunciation]> of set properties + */ + fun parseFlags(characteristicFlags: Int): EnumSet { + val setFlags = EnumSet.noneOf(SensorStatusAnnunciation::class.java) + SensorStatusAnnunciation.values().forEach { + val flag = it.bit + if(flag and characteristicFlags == flag) setFlags.add(it) + } + return setFlags + } + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt new file mode 100644 index 0000000..329f67e --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt @@ -0,0 +1,11 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp + +enum class Filter constructor(val key: Int) { + RESERVED_FOR_FUTURE_USE(0), + TIME_OFFSET(1); + + companion object { + private val map = Filter.values().associateBy(Filter::key) + fun fromKey(type: Int) = map[type] + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt new file mode 100644 index 0000000..e240297 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt @@ -0,0 +1,18 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp + +enum class Opcode constructor(val key: Int) { + + RESERVED_FOR_FUTURE_USE(0), + REPORT_STORED_RECORDS(1), + DELETE_STORED_RECORDS(2), + ABORT_OPERATION(3), + REPORT_NUMBER_OF_STORED_RECORDS(4), + NUMBER_OF_STORED_RECORDS_RESPONSE(5), + RESPONSE_CODE(6); + + companion object { + private val map = Opcode.values().associateBy(Opcode::key) + fun fromKey(type: Int) = map[type] + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt new file mode 100644 index 0000000..9da94f0 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt @@ -0,0 +1,17 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp + +enum class Operator constructor(val key: Int) { + NULL(0), + ALL_RECORDS(1), + LESS_THAN_OR_EQUAL_TO(2), + GREATER_THAN_OR_EQUAL_TO(3), + WITHIN_RANGE_OF_INCLUSIVE(4), + FIRST_RECORD(5), + LAST_RECORD(6); + + companion object { + private val map = Operator.values().associateBy(Operator::key) + fun fromKey(type: Int) = map[type] + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt new file mode 100644 index 0000000..e73b3ac --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt @@ -0,0 +1,20 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp + +enum class ResponseCode constructor(val key: Int) { + RESERVED_FOR_FUTURE_USE(0), + SUCCESS(1), + OP_CODE_NOT_SUPPORTED(2), + INVALID_OPERATOR(3), + OPERATOR_NOT_SUPPORTED(4), + INVALID_OPERAND(5), + NO_RECORDS_FOUND(6), + ABORT_UNSUCCESSFUL(7), + PROCEDURE_NOT_COMPLETED(8), + OPERAND_NOT_SUPPORTED(9); + + companion object { + private val map = ResponseCode.values().associateBy(ResponseCode::key) + fun fromKey(type: Int) = map[type] + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/utility/BluetoothDateTime.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/BluetoothDateTime.kt similarity index 82% rename from jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/utility/BluetoothDateTime.kt rename to jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/BluetoothDateTime.kt index ad44b2d..160c16c 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/utility/BluetoothDateTime.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/BluetoothDateTime.kt @@ -1,7 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.bgm.utility - -import java.time.Year -import java.util.* +package org.ehealthinnovation.jdrfandroidbleparser.utility data class BluetoothDateTime(val _year: Int = 0, val _month: Int = 0, diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt new file mode 100644 index 0000000..4bc3cee --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt @@ -0,0 +1,78 @@ +package org.ehealthinnovation.jdrfandroidbleparser.utility + +import unsigned.toUShort +import unsigned.toUshort +import kotlin.experimental.and + +object CrcHelper { + private val lookUpTable = intArrayOf( + 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, + 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, + 0x75b7, 0x643e, 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, 0x2102, + 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, + 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, + 0x453c, 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, 0x4204, 0x538d, + 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, + 0x99e1, 0xab7a, 0xbaf3, 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, + 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, 0x6306, 0x728f, 0x4014, + 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, + 0x8a78, 0x9bf1, 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, 0xffcf, + 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, 0x8408, 0x9581, 0xa71a, 0xb693, + 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, + 0x7cff, 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, 0x18c1, 0x0948, + 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, + 0xf2a7, 0xc03c, 0xd1b5, 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, + 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, 0x39c3, 0x284a, 0x1ad1, + 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, + 0xa33a, 0xb2b3, 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, 0xd68d, + 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, 0x5ac5, 0x4b4c, 0x79d7, 0x685e, + 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, + 0x93b1, 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, 0xf78f, 0xe606, + 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, + 0x2c6a, 0x1ef1, 0x0f78) + + /** + * Get the CRC check sum from a message + * @param message the byte message array + * @param length the length of the message array + * @return the CRC check sum from the message. + */ + fun calculateCcittCrc16(message: ByteArray, length: Int): Short { + var crc16 = 0xFFFF + var i: Int + i = 0 + while (i < length) { + crc16 = (crc16 shr 8 and 0xFF) xor lookUpTable[crc16 xor message[i].toInt() and 0xFF] + i++ + } + crc16 = crc16 and 0xffff + return crc16.toShort() + } + + /** + * Test a message if it passes the CRC check. + * @param message the byte message array + * @param length the length of the message array + * @return true is the message passes the test, false otherwise. + */ + fun testCcittCrc16(message: ByteArray, length: Int): Boolean { + return calculateCcittCrc16(message, length).toInt() == 0 + } + + /** + * Attach a 16 bit check sum to an input byte array + * @param message the byte message array + * @param length the length of the message array + * @return the resulting byte array with CRC code attached to the end in little endian format + */ + fun attachCcittCrc16ToPacket(message: ByteArray, length: Int): ByteArray { + val output = message.copyOf(length) + + val crc = calculateCcittCrc16(message, length) + + output[length] = crc.toByte() + output[length + 1] = (crc.toInt() and 0xFF00 shr 8).toByte() + + return output + } +} diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/StringCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/StringCharacteristicTest.kt index bd11d99..420138f 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/StringCharacteristicTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/StringCharacteristicTest.kt @@ -4,7 +4,7 @@ import android.bluetooth.BluetoothGattCharacteristic import com.nhaarman.mockito_kotlin.doReturn import com.nhaarman.mockito_kotlin.mock import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.common.StringCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.StringCharacteristic import org.junit.Assert import org.junit.Test import kotlin.jvm.java diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristicTest.kt index 526924e..75c816f 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristicTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristicTest.kt @@ -1,12 +1,9 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic -import android.bluetooth.BluetoothGattCharacteristic -import com.nhaarman.mockito_kotlin.mock import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Flags import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.SampleLocation import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Type -import org.ehealthinnovation.jdrfandroidbleparser.bgm.utility.BluetoothDateTime +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.Units import org.junit.Assert @@ -15,7 +12,6 @@ import org.junit.Test import org.junit.Assert.* import org.junit.Before import java.util.* -import kotlin.reflect.jvm.internal.impl.types.checker.TypeIntersector class GlucoseMeasurementCharacteristicTest : BaseTest() { diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalues/bgmcontext/FlagsTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmcontext/FlagsTest.kt similarity index 98% rename from jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalues/bgmcontext/FlagsTest.kt rename to jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmcontext/FlagsTest.kt index c6972ff..4cc5510 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalues/bgmcontext/FlagsTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmcontext/FlagsTest.kt @@ -1,4 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalues.bgmcontext +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalues.bgm.bgmcontext import junit.framework.Assert import org.ehealthinnovation.jdrfandroidbleparser.BaseTest diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/FlagsTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/FlagsTest.kt similarity index 95% rename from jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/FlagsTest.kt rename to jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/FlagsTest.kt index a494839..6d3e2d9 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/FlagsTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/FlagsTest.kt @@ -1,9 +1,8 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgmmeasurement +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.bgmmeasurement import junit.framework.Assert import org.ehealthinnovation.jdrfandroidbleparser.BaseTest import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Flags -import org.junit.Assert.* import org.junit.Test import java.util.* diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SensorStatusAnnunciationTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SensorStatusAnnunciationTest.kt similarity index 96% rename from jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SensorStatusAnnunciationTest.kt rename to jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SensorStatusAnnunciationTest.kt index 827b03f..28a7823 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgmmeasurement/SensorStatusAnnunciationTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/bgm/bgmmeasurement/SensorStatusAnnunciationTest.kt @@ -1,9 +1,8 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgmmeasurement +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.bgmmeasurement import junit.framework.Assert import org.ehealthinnovation.jdrfandroidbleparser.BaseTest import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.SensorStatusAnnunciation -import org.junit.Assert.* import org.junit.Test import java.util.* diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt new file mode 100644 index 0000000..722186f --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt @@ -0,0 +1,34 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test +import java.util.* + +class FlagsTest : BaseTest(){ + + @Test + fun testEach() { + enumValues().forEach { + val parseFlags = Flags.parseFlags(it.bit) + Assert.assertTrue(parseFlags.contains(it)) + } + } + + @Test + fun testCombinations() { + val setFlags: EnumSet = EnumSet.noneOf(Flags::class.java) + var currentMask = 0 + enumValues().forEach { + setFlags.add(it) + currentMask = currentMask.or(it.bit) + val parseFlags = Flags.parseFlags(currentMask) + setFlags.forEach { + Assert.assertTrue(parseFlags.contains(it)) + } + } + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt new file mode 100644 index 0000000..06f80f9 --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt @@ -0,0 +1,32 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test +import java.util.* + +class FlagsTest : BaseTest(){ + + @Test + fun testEach() { + enumValues().forEach { + val parseFlags = Flags.parseFlags(it.bit) + Assert.assertTrue(parseFlags.contains(it)) + } + } + + @Test + fun testCombinations() { + val setFlags: EnumSet = EnumSet.noneOf(Flags::class.java) + var currentMask = 0 + enumValues().forEach { + setFlags.add(it) + currentMask = currentMask.or(it.bit) + val parseFlags = Flags.parseFlags(currentMask) + setFlags.forEach { + Assert.assertTrue(parseFlags.contains(it)) + } + } + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt new file mode 100644 index 0000000..7478b0f --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt @@ -0,0 +1,31 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test +import java.util.* + +class SensorStatusAnnunciationTest : BaseTest(){ + @Test + fun testEach() { + enumValues().forEach { + val parseFlags = SensorStatusAnnunciation.parseFlags(it.bit) + Assert.assertTrue(parseFlags.contains(it)) + } + } + + @Test + fun testCombinations() { + val setFlags: EnumSet = EnumSet.noneOf(SensorStatusAnnunciation::class.java) + var currentMask = 0 + enumValues().forEach { + setFlags.add(it) + currentMask = currentMask.or(it.bit) + val parseFlags = SensorStatusAnnunciation.parseFlags(currentMask) + setFlags.forEach { + Assert.assertTrue(parseFlags.contains(it)) + } + } + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt new file mode 100644 index 0000000..70743bc --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt @@ -0,0 +1,12 @@ +package org.ehealthinnovation.jdrfandroidbleparser.utility + +import org.junit.Assert.* + +class CrcHelperTest { + /** + * Test Packet 1 + * Null package + */ + val testByteArray : ByteArray = byteArrayOf(0x00, 0x00) + val expectedCrc : Short = +} \ No newline at end of file From f80522db4dbdf47119662982058422b58b579f8e Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Tue, 4 Sep 2018 17:07:42 -0400 Subject: [PATCH 02/11] add crc and feature --- .../CgmFeatureCharacteristic.kt | 73 +++++++++- .../common/BaseCharacteristic.kt | 32 ++++- .../encodedvalue/cgm/racp/Opcode.kt | 2 +- .../encodedvalue/cgm/racp/Operator.kt | 2 +- .../encodedvalue/cgm/racp/ResponseCode.kt | 2 +- .../jdrfandroidbleparser/utility/CrcHelper.kt | 1 + .../CgmFeatureCharacteristicTest.kt | 97 ++++++++++++++ .../utility/CrcHelperTest.kt | 125 +++++++++++++++++- 8 files changed, 324 insertions(+), 10 deletions(-) create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt index b8e66ed..3dfbf83 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt @@ -1,7 +1,76 @@ package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic +import android.bluetooth.BluetoothGattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmSampleLocation +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmType +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags +import java.lang.reflect.Type +import java.util.* + /** - * + * The CGM Feature characteristic is used to describe the supported features of the Server. + * When read, the CGM Feature characteristic returns a value that is used by a Client to determine + * the supported features of the Server. Additionally, the CGM Feature contains the CGM Type-Sample + * Location field: This field is the combination of the Type field and the Sample Location field and + * is static for a CGM sensor. + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_feature.xml */ -class CgmFeatureCharacteristic { +class CgmFeatureCharacteristic(characteristic: BluetoothGattCharacteristic?) :BaseCharacteristic(characteristic, GattCharacteristic.CGM_FEATURE.assigned, false) { + + override val tag = CgmFeatureCharacteristic::class.java.canonicalName as String + + /** + * The set of feature flags contained in the binary packet. + * Use [isFeatureSupported] to query if a device supports a certain feature. + */ + private var flags: EnumSet? = null + + /** + * The location and type of the cgm sample. + */ + var cgmType : CgmType? = null + var cgmSampleLocation : CgmSampleLocation? = null + + /** + * The parsing of this characteristic consists of two passes. The pass determine if CRC is present + * The second pass verify that the CRC is right if it is present. + */ + override fun parse(c: BluetoothGattCharacteristic): Boolean { + var errorFreeParse = false + var flagValue : Int = 0 + //The feature flag consist of 24 bit, which is not a standard data field length. + flagValue = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) + flagValue += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 8 + flagValue += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 16 + Flags.parseFlags(flagValue).let { + if(it.contains(Flags.E2E_CRC_SUPPORTED)){ + if(!testCrc(rawData)){ + throw Exception("CRC Fails") + } + }else{ + flags = it + } + } + + val temporalSampleTypeHolder = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) + cgmType = CgmType.fromKey(temporalSampleTypeHolder and 0x0F) + cgmSampleLocation = CgmSampleLocation.fromKey((temporalSampleTypeHolder and 0xF0) shr 4) + + errorFreeParse = true + return errorFreeParse + } + + /** + * Query if a feature is supported as described in the packet + * @param queryFeature the glucose meter feature to be queried + * @return true if the [queryFeature] is supported, false otherwise + * This function returns false even when the packet is not parsed successfully. + * Before using this value, make sure [successfulParsing] is true. + */ + fun isFeatureSupported(queryFeature: Flags): Boolean { + return (flags?.contains(queryFeature) == true) + } + } \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt index b9d78d3..07aa4c0 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt @@ -3,6 +3,7 @@ package org.ehealthinnovation.jdrfandroidbleparser.common import android.bluetooth.BluetoothGattCharacteristic import android.util.Log import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.FormatType +import org.ehealthinnovation.jdrfandroidbleparser.utility.CrcHelper import kotlin.jvm.Throws import kotlin.jvm.java @@ -17,12 +18,16 @@ abstract class BaseCharacteristic(val uuid: Int) { * If the characteristic is null, which is possible, we just return false so the requesting * process can handle the failed parse. This is done in the super class, so we don't have to * deal with it in every other sub class characteristic. + * + * The default value for CRC check is false. There are some characteristics that requires a + * first pass of parsing to know if CRC is present, and a second pass to parse the content with + * the [hasCrc] flag set correctly. */ - constructor(characteristic: BluetoothGattCharacteristic?, uuid: Int): this(uuid) { + constructor(characteristic: BluetoothGattCharacteristic?, uuid: Int, hasCrc: Boolean = false): this(uuid) { this.characteristic = characteristic characteristic?.let { rawData = it.value ?: ByteArray(0) - this.successfulParsing = tryParse(it) + this.successfulParsing = tryParse(it, hasCrc) } } @@ -38,10 +43,19 @@ abstract class BaseCharacteristic(val uuid: Int) { * bubble up all the way immediately. * * https://github.com/markiantorno/JDRFAndroidBLEParser/issues/1 + * @param c The [BluetoothGattCharacteristic] to parse + * @param checkCrc if CRC check is needed. Default if false + * @return true if parsing is successful + * */ - fun tryParse(c: BluetoothGattCharacteristic): Boolean { + fun tryParse(c: BluetoothGattCharacteristic, checkCrc : Boolean = false): Boolean { var errorFreeParse = false try { + if(checkCrc){ + if(!testCrc(rawData)){ + throw Exception("CRC16 check failed"); + } + } errorFreeParse = parse(c) } catch (e: NullPointerException) { Log.e(tag, nullValueException) @@ -51,6 +65,7 @@ abstract class BaseCharacteristic(val uuid: Int) { return errorFreeParse } + /** * Each characteristic has it's own set of values which could be of differing types, so we leave * implementation of the parsing to the individual characteristic implementation. @@ -62,6 +77,17 @@ abstract class BaseCharacteristic(val uuid: Int) { */ protected abstract fun parse(c: BluetoothGattCharacteristic): Boolean + /** + * This function tests if the CRC attached at the packet is correct. This function + * assumes the CRC is attached at the end of the packet. If it is not the case, subclass + * needs to implements this method. + * @param data The raw data of the message byte sequence + * @return true if the CRC is passed. + */ + protected fun testCrc(data : ByteArray) : Boolean { + return CrcHelper.testCcittCrc16(data, data.size) + } + /** * Returns the stored [String] value of this characteristic. * diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt index e240297..a718f69 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt @@ -1,4 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp enum class Opcode constructor(val key: Int) { diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt index 9da94f0..ea6198d 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt @@ -1,4 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp enum class Operator constructor(val key: Int) { NULL(0), diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt index e73b3ac..00e62b4 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt @@ -1,4 +1,4 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp enum class ResponseCode constructor(val key: Int) { RESERVED_FOR_FUTURE_USE(0), diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt index 4bc3cee..1d1d151 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt @@ -5,6 +5,7 @@ import unsigned.toUshort import kotlin.experimental.and object CrcHelper { + val tag = CrcHelper::class.java.canonicalName as String private val lookUpTable = intArrayOf( 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt new file mode 100644 index 0000000..d60e071 --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt @@ -0,0 +1,97 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic.GlucoseFeatureCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags +import org.junit.After +import org.junit.Assert +import org.junit.Before + +import org.junit.Assert.* +import org.junit.Test + +class CgmFeatureCharacteristicTest : BaseTest(){ + + /** + * Test packet 1 + * A normal CGM Feature packet with no CRC + */ + private val testPacket1 = byteArrayOf(0x) + + /** + * Test Packet 2 + * A normal CGM feature packet with correct CRC + */ + + /** + * Test Packet 3 + * A normal CGM feature packet with incorrect CRC + */ + + + + @Test + fun testTag() { + val cgmFeatureCharacteristic = CgmFeatureCharacteristic(null) + Assert.assertEquals(CgmFeatureCharacteristic::class.java.canonicalName as String, cgmFeatureCharacteristic.tag) + } + + @Test + fun testAssignedNumber() { + val cgmFeatureCharacteristic = CgmFeatureCharacteristic(null) + Assert.assertEquals(GattCharacteristic.CGM_FEATURE.assigned, cgmFeatureCharacteristic.uuid) + } + + @Test + fun testPartialParseFail(){ + //This is a garbage payload, with no readable data. + val badPayload = byteArrayOf(Byte.MIN_VALUE) + val cgmFeatureCharacteristic = CgmFeatureCharacteristic(mockBTCharacteristic(badPayload)) + + Assert.assertFalse(cgmFeatureCharacteristic.successfulParsing) + } + + @Test + fun parseSuccess(){ + + } + + @Test + fun isFeatureSupported() { + + //This test if the [isFeatureSupported] function returns the correct Boolean Value. + + for (flag in Flags.values()) { + val flagValue = flag.bit + val testPacket: ByteArray = byteArrayOf((flagValue and 0x00FF).toByte(), + ((flagValue and 0x00FF00) shr 8).toByte(), + ((flagValue and 0xFF0000) shr 16).toByte(), + 0x00 + ) + + var cgmFeatureCharacteristic = CgmFeatureCharacteristic(mockBTCharacteristic(testPacket)) + + System.out.printf("flag values %04x . E2E flag value %04x\n", flagValue, Flags.E2E_CRC_SUPPORTED.bit) + if(flagValue == Flags.E2E_CRC_SUPPORTED.bit) { + //If the CRC bit is set, the parsing should fail as there is no CRC code attached to the raw packet + Assert.assertEquals(false, cgmFeatureCharacteristic.successfulParsing) + }else{ + Assert.assertEquals(true, cgmFeatureCharacteristic.successfulParsing) + } + //check correct flags are set and supported + for (otherFlag in Flags.values()) { + if (otherFlag != flag) { + Assert.assertEquals(false, cgmFeatureCharacteristic.isFeatureSupported(otherFlag)) + } else { + if(flagValue == Flags.E2E_CRC_SUPPORTED.bit) { + Assert.assertEquals(false, cgmFeatureCharacteristic.isFeatureSupported(otherFlag)) + }else { + Assert.assertEquals(true, cgmFeatureCharacteristic.isFeatureSupported(otherFlag)) + } + } + } + } + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt index 70743bc..723aa2b 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelperTest.kt @@ -1,12 +1,133 @@ package org.ehealthinnovation.jdrfandroidbleparser.utility +import org.junit.Assert import org.junit.Assert.* +import org.junit.Test +import kotlin.jvm.internal.Ref class CrcHelperTest { /** * Test Packet 1 * Null package */ - val testByteArray : ByteArray = byteArrayOf(0x00, 0x00) - val expectedCrc : Short = + val testByteArray1 : ByteArray = byteArrayOf(0x00, 0x00) + val expectedCrc1 : Short = 0xf0b8.toShort(); + + /** + * Test Pakcet 2 + * Three bytes + */ + val testByteArray2 : ByteArray = byteArrayOf(0x01, 0x00, 0x00) + val expectedCrc2 : Short = 0x63ef; + + /** + * Test Packet 3 + * A Glucose Measurement + */ + val testByteArray3 : ByteArray = byteArrayOf(0x13, 0x01, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00, 0x00, 0x54, 0xb0.toByte(), 0x19) + val expectedCrc3 : Short = 0x8368.toShort(); + + /** + * Test Packet 4 + * A Glucose Measurement + */ + val testByteArray4 : ByteArray = byteArrayOf(0x03, 0x02, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x36, 0x12, 0x10, 0x00, 0x60, 0xb0.toByte(), 0x11.toByte()) + val expectedCrc4 : Short = 0xa45f.toShort(); + + /** + * Test Packet 5 + * A Glucose Measurement + */ + val testByteArray5 : ByteArray = byteArrayOf(0x03, 0x03, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x36, 0x2e, 0x00, 0x00, 0x75, 0xb0.toByte(), 0x12.toByte()) + val expectedCrc5 : Short = 0x1662.toShort(); + + /** + * Test Packet 6 + * Test verifier for two null bytes + */ + val testByteArray6 : ByteArray = byteArrayOf(0x00, 0x00, 0xb8.toByte(), 0xf0.toByte()) + val expectedResult6 : Boolean = true + + /** + * Test Packet 7 + * Test verifier for three null bytes + */ + val testByteArray7 : ByteArray = byteArrayOf(0x01, 0x00, 0x00, 0xef.toByte(), 0x63) + val expectedResult7 : Boolean = true + + /** + * Test Packet 8 + * Test verifier for glucose measurement packet + */ + val testByteArray8 : ByteArray = byteArrayOf(0x13, 0x01, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00, 0x00, 0x54, 0xb0.toByte(), 0x19.toByte(), 0x68, 0x83.toByte()) + val expectedResult8 : Boolean = true + + /** + * Test Packet 9 + * Test verifier for glucose measurement packet + */ + val testByteArray9 : ByteArray = byteArrayOf(0x03, 0x02, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x36, 0x12, 0x10, 0x00, 0x60, 0xb0.toByte(), 0x11.toByte(), 0x5f, 0xa4.toByte()) + val expectedResult9 : Boolean = true + + /** + * Test Packet 10 + * Test verifier for glucose measurement packet + */ + val testByteArray10 : ByteArray = byteArrayOf(0x03, 0x03, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x36, 0x2e, 0x00, 0x00, 0x75, 0xb0.toByte(), 0x12.toByte(), 0x62, 0x16) + val expectedResult10 : Boolean = true + + /** + * Test Packet 11 + * Test Verifier for three bytes, negative case + */ + val testByteArray11 : ByteArray = byteArrayOf(0x01, 0x00, 0x00, 0xef.toByte(), 0x64) + val expectedResult11 : Boolean = false + + /** + * Test Packet 12 + * Test Verifier for glucose measurement negative case + */ + val testByteArray12 : ByteArray = byteArrayOf(0x13, 0x01, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00, 0x00, 0x54, 0xb0.toByte(), 0x19.toByte(), 0x68, 0x82.toByte()) + val expectedResult12 : Boolean = false + + /** + * Test Packet 13 + * Test Verifier for glucose measurement negative case + */ + val testByteArray13 : ByteArray = byteArrayOf(0x03, 0x02, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x36, 0x12, 0x10, 0x00, 0x60, 0xb0.toByte(), 0x11.toByte(), 0x5f, 0xa5.toByte()) + val expectedResult13 : Boolean = false; + + /** + * Test Pakcet 14 + * Test Verifier for glucose measurement negative case + */ + val testByteArray14 : ByteArray = byteArrayOf(0x03, 0x03, 0x00, 0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x36, 0x2e, 0x00, 0x00, 0x75, 0xb0.toByte(), 0x12.toByte(), 0x62, 0x17) + val expectedResult14 : Boolean = false; + + @Test + fun testTag() { + Assert.assertEquals(CrcHelper::class.java.canonicalName as String, CrcHelper.tag) + } + + @Test + fun testGeneratingCrcCode(){ + Assert.assertEquals(expectedCrc1, CrcHelper.calculateCcittCrc16(testByteArray1, testByteArray1.size)) + Assert.assertEquals(expectedCrc2, CrcHelper.calculateCcittCrc16(testByteArray2, testByteArray2.size)) + Assert.assertEquals(expectedCrc3, CrcHelper.calculateCcittCrc16(testByteArray3, testByteArray3.size)) + Assert.assertEquals(expectedCrc4, CrcHelper.calculateCcittCrc16(testByteArray4, testByteArray4.size)) + Assert.assertEquals(expectedCrc5, CrcHelper.calculateCcittCrc16(testByteArray5, testByteArray5.size)) + } + + @Test + fun testVerifyCrcAppendedPackets(){ + Assert.assertEquals(expectedResult6, CrcHelper.testCcittCrc16(testByteArray6, testByteArray6.size)) + Assert.assertEquals(expectedResult7, CrcHelper.testCcittCrc16(testByteArray7, testByteArray7.size)) + Assert.assertEquals(expectedResult8, CrcHelper.testCcittCrc16(testByteArray8, testByteArray8.size)) + Assert.assertEquals(expectedResult9, CrcHelper.testCcittCrc16(testByteArray9, testByteArray9.size)) + Assert.assertEquals(expectedResult10, CrcHelper.testCcittCrc16(testByteArray10, testByteArray10.size)) + Assert.assertEquals(expectedResult11, CrcHelper.testCcittCrc16(testByteArray11, testByteArray11.size)) + Assert.assertEquals(expectedResult12, CrcHelper.testCcittCrc16(testByteArray12, testByteArray12.size)) + Assert.assertEquals(expectedResult13, CrcHelper.testCcittCrc16(testByteArray13, testByteArray13.size)) + Assert.assertEquals(expectedResult14, CrcHelper.testCcittCrc16(testByteArray14, testByteArray14.size)) + } } \ No newline at end of file From 4d56495ebedc151b080e340b3fe8804970dd27ce Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Thu, 6 Sep 2018 14:50:04 -0400 Subject: [PATCH 03/11] session start and run time --- .../cgm/characteristic/CgmSessionRunTime.kt | 31 ++++ .../cgm/characteristic/CgmSessionStartTime.kt | 56 +++++++ .../characteristic/CgmStatusCharacteristic.kt | 38 +++++ .../cgm/feature/CgmSampleLocation.kt | 17 +-- .../cgm/sessionstarttime/DstOffset.kt | 14 ++ .../jdrfandroidbleparser/utility/CrcHelper.kt | 5 +- .../jdrfandroidbleparser/BaseTest.kt | 1 + .../CgmFeatureCharacteristicTest.kt | 62 +++++++- .../characteristic/CgmSessionRunTimeTest.kt | 52 +++++++ .../characteristic/CgmSessionStartTimeTest.kt | 141 ++++++++++++++++++ 10 files changed, 401 insertions(+), 16 deletions(-) create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt new file mode 100644 index 0000000..f6765a9 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt @@ -0,0 +1,31 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import android.bluetooth.BluetoothGattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic + +/** + * The CGM Session Run Time shall define the expected run time of the CGM session. Typically CGM + * Sensors have a limited run time which they are approved for. However, this characteristic should + * enable a prediction of the run time depending on physiological effects in future devices. + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_session_run_time.xml + */ +class CgmSessionRunTime(characteristic: BluetoothGattCharacteristic?, hasCrc: Boolean) : BaseCharacteristic(characteristic, GattCharacteristic.CGM_SESSION_RUN_TIME.assigned, hasCrc) { + + override val tag = CgmSessionRunTime::class.java.canonicalName as String + + /** + * The CGM Session Run Time is a relative time, based on the CGM Session Start Time. + * The unit is in hour + */ + var sessionRunTime : Int? = null + + override fun parse(c: BluetoothGattCharacteristic): Boolean { + var errorFreeParse = false + sessionRunTime = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + errorFreeParse = sessionRunTime != null + return errorFreeParse + } + + +} diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt new file mode 100644 index 0000000..9acbfdd --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt @@ -0,0 +1,56 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import android.bluetooth.BluetoothGattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.sessionstarttime.DstOffset +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime + +/** + * The Session Start Time Field defines the time of the initial CGM measurement. The absolute time + * of the first CGM measurement taken is not known, so the Server stores each CGM measurement with + * a relative time stamp (Time Offset), starting with 0 for the first measurement (Session Start). + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_session_start_time.xml + */ +class CgmSessionStartTime(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : BaseCharacteristic(c, GattCharacteristic.CGM_SESSION_START_TIME.assigned, hasCrc) { + + override val tag = CgmSessionStartTime::class.java.canonicalName as String + + /** + * Upon initial connection, if the device supports an automatic start of the CGM session (e.g., + * at power on), or after the Start Session procedure, the Client shall write its current time + * to this characteristic and the Server shall calculate and store the Session Start Time using + * the time of the client and its own current relative time value. + */ + var sessionStartTime : BluetoothDateTime? = null + + /** + * To know an absolute Time, it is necessary to know the Time Zone to which the Session Start + * Time is related to. If unknown, the field shall be set to a value of -128. See definition of + * Time Zone Characteristic in [3]. + */ + var timeZone : Int? = null + + /** + * To know an absolute Time, it is also necessary to know the Daylight Saving setting. + * If unknown, the field shall be set to a value of 255. + */ + var dstOffset : DstOffset? = null + + + override fun parse(c: BluetoothGattCharacteristic): Boolean { + var errorFreeParse = false + sessionStartTime = BluetoothDateTime( + _year = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16), + _month = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), + _day = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), + _hour = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), + _min = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), + _sec = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) + ) + timeZone = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_SINT8) + dstOffset = DstOffset.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_SINT8)) + errorFreeParse = true + return errorFreeParse + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt new file mode 100644 index 0000000..45cafb3 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt @@ -0,0 +1,38 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import android.bluetooth.BluetoothGattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation +import java.util.* + +/** + * The CGM Status allows the client to actively request the status from the CGM Sensor, particularly + * when the CGM measurement is not running and the status cannot be given in the measurement result + * in the Status Annunciation Field. + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_status.xml + */ +class CgmStatusCharacteristic(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : BaseCharacteristic(c, GattCharacteristic.CGM_STATUS.assigned, hasCrc){ + + + override val tag = CgmStatusCharacteristic::class.java.canonicalName as String + + /** + * The Time Offset Field specifies the actual relative time difference to the session start time. + */ + var timeOffset : Int? = null + + /** + * The structure of the CGM Status Field shall be identical to the structure of the Status + * Annunciation Field, as defined in the CGM Measurement Characteristic "Sensor Status + * Annunciation Field". It always consists of three octets regardless the value. + */ + var cgmStatus : EnumSet? = null + + + override fun parse(c: BluetoothGattCharacteristic): Boolean { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt index 4865687..0b3996d 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt @@ -3,17 +3,12 @@ package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature enum class CgmSampleLocation constructor(val key: Int) { RESERVED_FOR_FUTURE_USE(0), - CAPILLARY_WHOLE_BLOOD(1), - CAPILLARY_PLASMA(2), - VENOUS_WHOLE_BLOOD(3), - VENOUS_PLASMA(4), - ARTERIAL_WHOLE_BLOOD(5), - ARTERIAL_PLASMA(6), - UNDETERMINED_WHOLE_BLOOD(7), - UNDETERMINED_PLASMA(8), - INTERSTITIAL_FLUID(9), - CONTROL_SOLUTION(10); - + FINGER(1), + ALTERNATE_SITE_TEST(2), + EARLOBE(3), + CONTROL_SOLUTION(4), + SUBCUTANEOUS_TISSUE(5), + SAMPLE_LOCATION_VALUE_NOT_AVAILABLE(15); companion object { private val map = CgmSampleLocation.values().associateBy(CgmSampleLocation::key) diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt new file mode 100644 index 0000000..e056371 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt @@ -0,0 +1,14 @@ +package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.sessionstarttime + +enum class DstOffset(val key: Int) { + STANDARD_TIME(0), + HALF_AN_HOUR_DAYLIGHT_TIME(2), + DAYLIGHT_TIME(4), + DOUBLE_DAYLIGHT_TIME(8), + DST_IS_NOT_KNOWN(255); + + companion object { + private val map = DstOffset.values().associateBy(DstOffset::key) + fun fromKey(type: Int) = map[type] + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt index 1d1d151..bca8e8a 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/utility/CrcHelper.kt @@ -67,12 +67,9 @@ object CrcHelper { * @return the resulting byte array with CRC code attached to the end in little endian format */ fun attachCcittCrc16ToPacket(message: ByteArray, length: Int): ByteArray { - val output = message.copyOf(length) val crc = calculateCcittCrc16(message, length) - - output[length] = crc.toByte() - output[length + 1] = (crc.toInt() and 0xFF00 shr 8).toByte() + val output = message + crc.toByte() + (crc.toInt() and 0xFF00 shr 8).toByte() return output } diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt index 065830c..e456c5c 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt @@ -76,6 +76,7 @@ open class BaseTest { val offset: Int = it.getArgument(0) payload.sliceArray(offset..(offset + (payload.size - 1))).reversedArray().toString(Charset.defaultCharset()) } + on { value } doAnswer {payload} } } diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt index d60e071..ccfd356 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt @@ -3,6 +3,8 @@ package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic import org.ehealthinnovation.jdrfandroidbleparser.BaseTest import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic.GlucoseFeatureCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmSampleLocation +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmType import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags import org.junit.After import org.junit.Assert @@ -10,6 +12,7 @@ import org.junit.Before import org.junit.Assert.* import org.junit.Test +import java.util.* class CgmFeatureCharacteristicTest : BaseTest(){ @@ -17,17 +20,61 @@ class CgmFeatureCharacteristicTest : BaseTest(){ * Test packet 1 * A normal CGM Feature packet with no CRC */ - private val testPacket1 = byteArrayOf(0x) + private val testPacket1 = byteArrayOf(0b01010101,0b10101010.toByte(),0b10101010.toByte(), 0x52) + private val expectedFlagSet1 = EnumSet.of( + Flags.CALIBRATION_SUPPORTED, + Flags.HYPO_ALERTS_SUPPORTED, + Flags.RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED, + Flags.SENSOR_MALFUNCTION_DETECTION_SUPPORTED, + Flags.LOW_BATTERY_DETECTION_SUPPORTED, + Flags.GENERAL_DEVICE_FAULT_SUPPORTED, + Flags.MULTIPLE_BOND_SUPPORTED, + Flags.CGM_TREND_INFORMATION_SUPPORTED + ) + + private val expectedType1 = CgmType.CAPILLARY_PLASMA + private val expectedSampleLocation1 = CgmSampleLocation.SUBCUTANEOUS_TISSUE /** * Test Packet 2 * A normal CGM feature packet with correct CRC */ + private val testPacket2 = byteArrayOf(0b01010101,0b10111010.toByte(),0b10101010.toByte(), 0x52, 0x40.toByte(), 0x62.toByte()) + private val expectedFlagSet2 = EnumSet.of( + Flags.CALIBRATION_SUPPORTED, + Flags.HYPO_ALERTS_SUPPORTED, + Flags.RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED, + Flags.SENSOR_MALFUNCTION_DETECTION_SUPPORTED, + Flags.LOW_BATTERY_DETECTION_SUPPORTED, + Flags.GENERAL_DEVICE_FAULT_SUPPORTED, + Flags.MULTIPLE_BOND_SUPPORTED, + Flags.E2E_CRC_SUPPORTED, + Flags.CGM_TREND_INFORMATION_SUPPORTED + ) + + private val expectedType2 = CgmType.CAPILLARY_PLASMA + private val expectedSampleLocation2 = CgmSampleLocation.SUBCUTANEOUS_TISSUE + /** * Test Packet 3 * A normal CGM feature packet with incorrect CRC */ + private val testPacket3 = byteArrayOf(0b01010101,0b10111010.toByte(),0b10101010.toByte(), 0x52, 0xd5.toByte(), 0xe6.toByte()) + private val expectedFlagSet3 = EnumSet.of( + Flags.CALIBRATION_SUPPORTED, + Flags.HYPO_ALERTS_SUPPORTED, + Flags.RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED, + Flags.SENSOR_MALFUNCTION_DETECTION_SUPPORTED, + Flags.LOW_BATTERY_DETECTION_SUPPORTED, + Flags.GENERAL_DEVICE_FAULT_SUPPORTED, + Flags.E2E_CRC_SUPPORTED, + Flags.MULTIPLE_BOND_SUPPORTED, + Flags.CGM_TREND_INFORMATION_SUPPORTED + ) + + private val expectedType3 = null + private val expectedSampleLocation3 = null @@ -54,7 +101,20 @@ class CgmFeatureCharacteristicTest : BaseTest(){ @Test fun parseSuccess(){ + Assert.assertTrue(CgmFeatureCharacteristic(mockBTCharacteristic(testPacket1)).successfulParsing) + Assert.assertTrue(CgmFeatureCharacteristic(mockBTCharacteristic(testPacket2)).successfulParsing) + Assert.assertFalse(CgmFeatureCharacteristic(mockBTCharacteristic(testPacket3)).successfulParsing) + } + @Test + fun parseSampleLocationSuccessfully(){ + Assert.assertEquals(expectedSampleLocation1, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket1)).cgmSampleLocation) + Assert.assertEquals(expectedSampleLocation2, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket2)).cgmSampleLocation) + Assert.assertEquals(expectedSampleLocation3, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket3)).cgmSampleLocation) + + Assert.assertEquals(expectedType1, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket1)).cgmType) + Assert.assertEquals(expectedType2, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket2)).cgmType) + Assert.assertEquals(expectedType3, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket3)).cgmType) } @Test diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt new file mode 100644 index 0000000..8dae962 --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt @@ -0,0 +1,52 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test + +class CgmSessionRunTimeTest : BaseTest(){ + /** + * Test Packet 1 + * Normal case without CRC + */ + private val testPacket1 = byteArrayOf(0x01, 0x02) + private val hasCrc1 = false + private val expectedParseResult1 = true + private val expectedSessionRunTime1 = 0x0201 + + /** + * Test Packet 2 + * Normal case with CRC + */ + private val testPacket2 = byteArrayOf(0x01, 0x02, 0x72, 0xca.toByte()) + private val hasCrc2 = true + private val expectedParseResult2 = true + private val expectedSessionRunTime2 = 0x0201 + + + /** + * Test Packet 2 + * Normal case with failed CRC + */ + private val testPacket3 = byteArrayOf(0x01, 0x02, 0x72, 0xcb.toByte()) + private val hasCrc3 = true + private val expectedParseResult3 = false + private val expectedSessionRunTime3 = null + + + @Test + fun testParseSuccessfully(){ + Assert.assertEquals(expectedParseResult1, CgmSessionRunTime(mockBTCharacteristic(testPacket1),hasCrc1).successfulParsing) + Assert.assertEquals(expectedParseResult2, CgmSessionRunTime(mockBTCharacteristic(testPacket2),hasCrc2).successfulParsing) + Assert.assertEquals(expectedParseResult3, CgmSessionRunTime(mockBTCharacteristic(testPacket3),hasCrc3).successfulParsing) + } + + @Test + fun testSessionRunTime(){ + Assert.assertEquals(expectedSessionRunTime1, CgmSessionRunTime(mockBTCharacteristic(testPacket1),hasCrc1).sessionRunTime) + Assert.assertEquals(expectedSessionRunTime2, CgmSessionRunTime(mockBTCharacteristic(testPacket2),hasCrc2).sessionRunTime) + Assert.assertEquals(expectedSessionRunTime3, CgmSessionRunTime(mockBTCharacteristic(testPacket3),hasCrc3).sessionRunTime) + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt new file mode 100644 index 0000000..85f7de4 --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt @@ -0,0 +1,141 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.sessionstarttime.DstOffset +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test + +class CgmSessionStartTimeTest: BaseTest(){ + /** + * Packet 1 + * Standard time, no dst no crc + */ + private val testPacket1 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00, 0x00) + private val expectedParseResult1 = true + private val expectedTime1 = BluetoothDateTime(2018,6,6,14,53,14) + private val expectedDst1 = DstOffset.STANDARD_TIME + private val expectedTimeZone1 = 0 + + /** + * Packet 2 + * Maximum negative timezone , no dst no Crc + */ + private val testPacket2 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0xD0.toByte(), 0x00) + private val expectedParseResult2 = true + private val expectedTime2 = BluetoothDateTime(2018,6,6,14,53,14) + private val expectedDst2 = DstOffset.STANDARD_TIME + private val expectedTimeZone2 = -48 + + /** + * Packet 3 + * Max positive timezone, no dst, no crc + */ + private val testPacket3 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x38.toByte(), 0x00) + private val expectedParseResult3 = true + private val expectedTime3 = BluetoothDateTime(2018,6,6,14,53,14) + private val expectedDst3 = DstOffset.STANDARD_TIME + private val expectedTimeZone3 = 56 + + /** + * Packet 4 + * standard unknown timezone, no dst, no crc + */ + private val testPacket4 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x80.toByte(), 0x00) + private val expectedParseResult4 = true + private val expectedTime4 = BluetoothDateTime(2018,6,6,14,53,14) + private val expectedDst4 = DstOffset.STANDARD_TIME + private val expectedTimeZone4 = -128 + + /** + * Packet 5 + * Standard Timezone, one hour dst, no crc + */ + private val testPacket5 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) + private val expectedParseResult5 = true + private val expectedTime5 = BluetoothDateTime(2018,6,6,14,53,14) + private val expectedDst5 = DstOffset.DAYLIGHT_TIME + private val expectedTimeZone5 = 0 + + /** + * Packet 6 + * Uknown Year, Standard Timezone, one hour dst, no crc + */ + private val testPacket6 = byteArrayOf(0.toByte(), 0, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) + private val expectedParseResult6 = true + private val expectedTime6 = BluetoothDateTime(0,6,6,14,53,14) + private val expectedDst6 = DstOffset.DAYLIGHT_TIME + private val expectedTimeZone6 = 0 + + /** + * Packet 7 + * Unknown month, standard time, one hour dst, no crc + */ + private val testPacket7 = byteArrayOf(0xe2.toByte(), 0x07, 0x00, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) + private val expectedParseResult7 = true + private val expectedTime7 = BluetoothDateTime(2018,0,6,14,53,14) + private val expectedDst7 = DstOffset.DAYLIGHT_TIME + private val expectedTimeZone7 = 0 + + /** + * Packet 8 + * Unknown Day, standard time, one hour dst, no crc + */ + + private val testPacket8 = byteArrayOf(0xe2.toByte(), 0x07, 0x00, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) + private val expectedParseResult8 = true + private val expectedTime8 = BluetoothDateTime(2018,0,6,14,53,14) + private val expectedDst8 = DstOffset.DAYLIGHT_TIME + private val expectedTimeZone8 = 0 + + @Test + fun testParseSuccessfully(){ + Assert.assertEquals(expectedParseResult1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).successfulParsing) + Assert.assertEquals(expectedParseResult2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).successfulParsing) + Assert.assertEquals(expectedParseResult3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).successfulParsing) + Assert.assertEquals(expectedParseResult4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).successfulParsing) + Assert.assertEquals(expectedParseResult5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).successfulParsing) + Assert.assertEquals(expectedParseResult6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).successfulParsing) + Assert.assertEquals(expectedParseResult7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).successfulParsing) + Assert.assertEquals(expectedParseResult8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).successfulParsing) + + } + + @Test + fun testParseDate(){ + Assert.assertEquals(expectedTime1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).sessionStartTime) + Assert.assertEquals(expectedTime2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).sessionStartTime) + Assert.assertEquals(expectedTime3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).sessionStartTime) + Assert.assertEquals(expectedTime4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).sessionStartTime) + Assert.assertEquals(expectedTime5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).sessionStartTime) + Assert.assertEquals(expectedTime6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).sessionStartTime) + Assert.assertEquals(expectedTime7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).sessionStartTime) + Assert.assertEquals(expectedTime8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).sessionStartTime) + } + + @Test + fun testParseDst(){ + Assert.assertEquals(expectedDst1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).dstOffset) + Assert.assertEquals(expectedDst2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).dstOffset) + Assert.assertEquals(expectedDst3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).dstOffset) + Assert.assertEquals(expectedDst4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).dstOffset) + Assert.assertEquals(expectedDst5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).dstOffset) + Assert.assertEquals(expectedDst6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).dstOffset) + Assert.assertEquals(expectedDst7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).dstOffset) + Assert.assertEquals(expectedDst8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).dstOffset) + } + + @Test + fun testParseTimeZone(){ + Assert.assertEquals(expectedTimeZone1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).timeZone) + Assert.assertEquals(expectedTimeZone2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).timeZone) + Assert.assertEquals(expectedTimeZone3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).timeZone) + Assert.assertEquals(expectedTimeZone4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).timeZone) + Assert.assertEquals(expectedTimeZone5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).timeZone) + Assert.assertEquals(expectedTimeZone6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).timeZone) + Assert.assertEquals(expectedTimeZone7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).timeZone) + Assert.assertEquals(expectedTimeZone8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).timeZone) + + } +} \ No newline at end of file From 6b4f5e9716c2560e80484954962e5c6925921772 Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Tue, 11 Sep 2018 09:22:37 -0400 Subject: [PATCH 04/11] wip --- .../CgmMeasurementCharacteristic.kt | 78 +++++++++++++++++++ .../characteristic/CgmStatusCharacteristic.kt | 15 +++- .../CgmMeasurementCharacteristicTest.kt | 6 ++ .../CgmStatusCharacteristicTest.kt | 75 ++++++++++++++++++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt new file mode 100644 index 0000000..ef3fbf5 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt @@ -0,0 +1,78 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import android.bluetooth.BluetoothGattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.Flags +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation +import java.util.* + +/** + * The CGM Measurement characteristic is a variable length structure containing one or more CGM + * Measurement records, each comprising a Size field, a Flags Field, a Glucose Concentration field, + * a Time Offset field, a Sensor Status Annunciation field (optional), a CGM Trend Information Field + * (optional), a CGM Quality Field (optional), and an E2E-CRC Field (mandatory if this feature is + * supported). + * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_measurement.xml + */ +class CgmMeasurementCharacteristic(c :BluetoothGattCharacteristic, hasCrc : Boolean = false) : BaseCharacteristic(c, GattCharacteristic.CGM_MEASUREMENT.assigned, hasCrc) { + override val tag: String = CgmMeasurementCharacteristic::class.java.canonicalName + + /** + * The Size Field represents the size of the CGM Measurement record in an UINT 8. The minimum + * size is 6 octets and is enlarged if more octets are indicated by the Flags Field (Sensor + * Status Annunciation Field, CGM Trend Information Field and CGM Quality Field) and the + * optional E2E-CRC Field. The Size Field itself is included in the length calculation. + */ + var size: Int? = null + + + var flags: EnumSet? = null + var cgmGlucoseConcentration: Float? = null + var timeOffset: Int? = null + var sensorStatusAnnunciation: EnumSet? = null + var cgmTrendInformation: Float? = null + var cgmQuality: Float? = null + val hasCrc = hasCrc + + + + override fun parse(c: BluetoothGattCharacteristic): Boolean { + var errorFreeParsing = false + var sizeCounter = 0 + size = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) + + Flags.parseFlags(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)).let { + flags = it + cgmGlucoseConcentration = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + timeOffset = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + var annunciationFlagHolder: Int = 0 + if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_STATUS_OCTET_PRESENT)) { + annunciationFlagHolder = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) + } + + if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT)) { + annunciationFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 8 + } + + if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT)) { + annunciationFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 16 + } + + sensorStatusAnnunciation = SensorStatusAnnunciation.parseFlags(annunciationFlagHolder) + + + if (it.contains(Flags.CGM_TREND_INFORMATION_PRESENT)) { + cgmTrendInformation = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_SFLOAT) + } + + if (it.contains(Flags.CGM_QUALITY_PRESENT)) { + cgmQuality = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_SFLOAT) + } + + } + + errorFreeParsing = let{ if(hasCrc) {2} else {0}} + offset == size + return errorFreeParsing + } +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt index 45cafb3..768e8d5 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt @@ -31,7 +31,20 @@ class CgmStatusCharacteristic(c : BluetoothGattCharacteristic, hasCrc : Boolean override fun parse(c: BluetoothGattCharacteristic): Boolean { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + var errorFreeParse = false + timeOffset = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + + //The structure for the status field is 24 bit, non-standard integer size + var statusFlagHolder : Int + statusFlagHolder = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) + statusFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 8 + statusFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 16 + + cgmStatus = SensorStatusAnnunciation.parseFlags(statusFlagHolder) + + errorFreeParse = true + + return errorFreeParse } diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt new file mode 100644 index 0000000..3249525 --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt @@ -0,0 +1,6 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.junit.Assert.* + +class CgmMeasurementCharacteristicTest : BaseTest \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt new file mode 100644 index 0000000..f6282e8 --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt @@ -0,0 +1,75 @@ +package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic + +import android.hardware.Sensor +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation +import org.ehealthinnovation.jdrfandroidbleparser.utility.CrcHelper +import org.junit.Assert +import org.junit.Assert.* +import org.junit.Test +import java.util.* + +class CgmStatusCharacteristicTest : BaseTest() { + /** + * Test packet 1 + * Normal test case without crc + */ + private val testPacket1: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01,0x01) + private val expectedParseResult1: Boolean = true + private val expectedTimeOffset1 : Int = 256 + private val expectedFlagSet1 : EnumSet = EnumSet.of( + SensorStatusAnnunciation.SESSION_STOPPED, + SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED + ) + + /** + * Test packet 2 + * Normal failed test case without crc + */ + private val testPacket2: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01) + private val expectedParseResult2: Boolean = false + + /** + * Test packet 3 + * Normal test case (successful) with crc + */ + private val testPacket3: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01,0x01, 0xbe.toByte(), 0x7e) + private val expectedParseResult3: Boolean = true + private val expectedTimeOffset3 : Int = 256 + private val expectedFlagSet3 : EnumSet = EnumSet.of( + SensorStatusAnnunciation.SESSION_STOPPED, + SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED + ) + + /** + * Test packet 4 + * Normalfaild test case with CRC + */ + private val testPacket4: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01,0x01, 0xbe.toByte(), 0x7d) + private val expectedParseResult4: Boolean = false + + @Test + fun testParseResult(){ + Assert.assertEquals(expectedParseResult1, CgmStatusCharacteristic(mockBTCharacteristic(testPacket1)).successfulParsing) + Assert.assertEquals(expectedParseResult2, CgmStatusCharacteristic(mockBTCharacteristic(testPacket2)).successfulParsing) + Assert.assertEquals(expectedParseResult3, CgmStatusCharacteristic(mockBTCharacteristic(testPacket3), true).successfulParsing) + Assert.assertEquals(expectedParseResult4, CgmStatusCharacteristic(mockBTCharacteristic(testPacket4), true).successfulParsing) + } + + @Test + fun testTimeOffset(){ + Assert.assertEquals(expectedTimeOffset1, CgmStatusCharacteristic(mockBTCharacteristic(testPacket1)).timeOffset) + Assert.assertEquals(expectedTimeOffset3, CgmStatusCharacteristic(mockBTCharacteristic(testPacket3)).timeOffset) + + } + + @Test + fun testStatusFlag(){ + Assert.assertEquals(expectedFlagSet1, CgmStatusCharacteristic(mockBTCharacteristic(testPacket1)).cgmStatus) + Assert.assertEquals(expectedFlagSet3, CgmStatusCharacteristic(mockBTCharacteristic(testPacket3)).cgmStatus) + } + + +} \ No newline at end of file From cd91b0b88c21e5cde447e2fe478eeedcfe04c70f Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Tue, 11 Sep 2018 17:05:06 -0400 Subject: [PATCH 05/11] wip --- .../compoundcharacteristic/RACP.kt | 126 +++++++++ .../CgmMeasurementCharacteristic.kt | 52 +++- .../jdrfandroidbleparser/common/Composable.kt | 7 +- .../CgmMeasurementCharacteristicTest.kt | 241 +++++++++++++++++- 4 files changed, 418 insertions(+), 8 deletions(-) create mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt new file mode 100644 index 0000000..1cdc029 --- /dev/null +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt @@ -0,0 +1,126 @@ +package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic + +import android.bluetooth.BluetoothGattCharacteristic +import android.util.Log +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.common.Composable +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Filter +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Opcode +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Operator +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime +import kotlin.math.log + +class RACP(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : + BaseCharacteristic(c, GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc), + Composable { + override val tag: String = RACP::class.java.canonicalName + + var opcode: Opcode? = null + var operator: Operator? = null + var filterType: Filter? = null + var minimumFilterValueSequenceNumber: Int? = null + var maximumFilterValueSequenceNumber: Int? = null + var minimumFilterValueUserFacingTime: BluetoothDateTime? = null + var maximumFilterValueUserFacingTime: BluetoothDateTime? = null + + val hasCrc: Boolean = hasCrc + + override fun parse(c: BluetoothGattCharacteristic): Boolean { + var errorFreeParsing = false + opcode = Opcode.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + //Extract operator + when (opcode){ + null -> { + Log.e(tag, "Opcode is null, packet might have been corrucpted") + return errorFreeParsing + } + Opcode.REPORT_NUMBER_OF_STORED_RECORDS, + Opcode.DELETE_STORED_RECORDS, + Opcode.REPORT_STORED_RECORDS->{ + operator = Operator.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + } + Opcode.ABORT_OPERATION, + Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE, + Opcode.RESPONSE_CODE->{ + operator = Operator.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + if(operator != Operator.NULL){ + Log.e(tag, "operator must be null, when opcode is Abort Operation") + return errorFreeParsing + } + } + else->{ + Log.e(tag, "unknown opcode $opcode , exiting parsing") + return errorFreeParsing + } + } + + //Extract operand + when (operator) { + Operator.GREATER_THAN_OR_EQUAL_TO->{ + filterType = Filter.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + minimumFilterValue = getNextIntValue() + } + Operator.LESS_THAN_OR_EQUAL_TO, + + } + + + + } + + private fun parseGenericOperand(c : BluetoothGattCharacteristic){ + if(filterType == Filter.SEQUENCE_NUMBER){ + when(operator){ + Operator.LESS_THAN_OR_EQUAL_TO ->{ + maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + } + Operator.GREATER_THAN_OR_EQUAL_TO ->{ + minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + } + Operator.WITHIN_RANGE_OF_INCLUSIVE->{ + maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + } + Operator.ALL_RECORDS, + Operator.FIRST_RECORD, + Operator.LAST_RECORD -> { + Log.i(tag, "${operator.toString()} does not need operand") + return + } + else->{ + Log.e(tag, "unknown operator $operator") + } + } + }else if (filterType == Filter.USER_FACING_TIME){ + when(operator){ + Operator.LESS_THAN_OR_EQUAL_TO->{ + maximumFilterValueUserFacingTime = parseBluetoothDateTime(c) + } + Operator.GREATER_THAN_OR_EQUAL_TO->{ + minimumFilterValueUserFacingTime = parseBluetoothDateTime(c) + } + Operator.WITHIN_RANGE_OF_INCLUSIVE->{ + + } + } + } + + } + + private fun parseBluetoothDateTime(c : BluetoothGattCharacteristic) : BluetoothDateTime{ + return BluetoothDateTime( + _year = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16)), + _month = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)), + _day = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)), + _hour = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)), + _min = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)), + _sec = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + ) + } + + override fun composeCharacteristic(hasCrc: Boolean): ByteArray { + TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + } + +} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt index ef3fbf5..959ee6b 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt @@ -26,13 +26,61 @@ class CgmMeasurementCharacteristic(c :BluetoothGattCharacteristic, hasCrc : Bool */ var size: Int? = null - + /** + * The Flags Field indicates the presence of optional fields and the Sensor Status Annunciation + * Field in the CGM Measurement record. + */ var flags: EnumSet? = null + + /** + * The CGM Glucose Concentration field contains the CGM glucose concentration in a SFLOAT data + * type. The SFLOAT-Type is a 16-bit word comprising a signed 4-bit integer exponent followed + * by a signed 12-bit Mantissa. + * + * Note that the unit of the CGM Glucose concentration is in mg/dL only. + */ var cgmGlucoseConcentration: Float? = null + + /** + * The Time Offset field is used in conjunction with the CGM Session Start Time to represent + * the time difference of the separate CGM measurements in relation to the session start time. + * Note that this Time Offset field serves also as a sequence number for the client, allowing + * the client to identify gaps / missing results in the data stream. + * + * The Time Offset field is defined as a UINT 16 representing the number of minutes the user-facing + * time differs from the Session Start Time. The default initial value shall be 0x0000. The Time + * Offset field shall be incremented by the measurement interval with each CGM measurement record + */ var timeOffset: Int? = null + + /** + * The Sensor Status Annunciation field may form part of the CGM Measurement record. This field + * has a variable length between 1 and 3 octets. If one or more bits in the Sensor Status + * Annunciation field are set to “1” the Sensor Status Annunciation field shall form part of + * every CGM Measurement Record to which it applies. + */ var sensorStatusAnnunciation: EnumSet? = null + + /** + * If the device supports CGM Trend information (CGM-Trend-Information Supported bit is set in + * CGM Features), this field may be included in the record. The presence of this field in a + * record is indicated by the Flags Field. This field contains the CGM Trend information in + * (mg/dL)/min as an SFLOAT data type. + */ var cgmTrendInformation: Float? = null + + /** + * If the device supports CGM Quality (CGM-Quality Supported bit is set in CGM Features), this + * field may be included in the CGM measurement record. The presence of this field in a CGM + * measurement record is indicated by the Flags Field. This field contains the CGM Quality + * information in % as an SFLOAT data type + */ var cgmQuality: Float? = null + + /** + * If the device supports E2E-safety (E2E-CRC Supported bit is set in CGM Features), the + * measurement shall be protected by a CRC calculated over all fields + */ val hasCrc = hasCrc @@ -44,7 +92,7 @@ class CgmMeasurementCharacteristic(c :BluetoothGattCharacteristic, hasCrc : Bool Flags.parseFlags(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)).let { flags = it - cgmGlucoseConcentration = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + cgmGlucoseConcentration = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_SFLOAT) timeOffset = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) var annunciationFlagHolder: Int = 0 if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_STATUS_OCTET_PRESENT)) { diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt index fed7c06..bd21030 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/Composable.kt @@ -1,14 +1,11 @@ package org.ehealthinnovation.jdrfandroidbleparser.common -import android.bluetooth.BluetoothGattCharacteristic - /** * Many base Bluetooth Characteristics not only have the requirement that they must decode a given * [BluetoothGattCharacteristic] to primitive data types, they must also be able to do the reverse * as well. These characteristics, must implement the [Composable] interface. * [BaseCharacteristic] classes can just extend this class and not worry about implementation. * - * Created by miantorno on 2018-06-19. */ interface Composable { @@ -16,6 +13,6 @@ interface Composable { * Compose a given characteristic into the resulting [ByteArray]. */ @Throws(IllegalStateException::class) - fun composeCharacteristic(): ByteArray + fun composeCharacteristic(hasCrc : Boolean): ByteArray -} \ No newline at end of file +} diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt index 3249525..0c820b7 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt @@ -1,6 +1,245 @@ package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.Flags +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation +import org.junit.Assert import org.junit.Assert.* +import org.junit.Test +import java.util.* -class CgmMeasurementCharacteristicTest : BaseTest \ No newline at end of file +class CgmMeasurementCharacteristicTest : BaseTest(){ + + /** + * Test Packet 1 + * Concentration Only Packet + */ + private val testPacket1: ByteArray = byteArrayOf(0x06, 0x00, 0x62, 0xF1.toByte(), 0x12, 0x34) + private val expectedParseResult1: Boolean = true + private val expectedConcentration1: Float = 35.4.toFloat() + private val expectedTrend1 = null + private val expectedQuality1 = null + private val expectedSensorStatusAnnunciation1: EnumSet = EnumSet.noneOf(SensorStatusAnnunciation::class.java) + private val expectedFlags1: EnumSet = EnumSet.noneOf(Flags::class.java) + private val expectedTimeOffset1 = 13330 + private val expectedSize1 = 7 + + /** + * Test Packet 2 + * Has Status Octet in the annunciation + */ + private val testPacket2: ByteArray = byteArrayOf(0x06, 0x00, 0x62, 0xF1.toByte(), 0x12, 0x34) + private val expectedParseResult2: Boolean = true + private val expectedConcentration2: Float = 35.4.toFloat() + private val expectedTrend2 = null + private val expectedQuality2 = null + private val expectedSensorStatusAnnunciation2: EnumSet = EnumSet.noneOf(SensorStatusAnnunciation::class.java) + private val expectedFlags2: EnumSet = EnumSet.noneOf(Flags::class.java) + private val expectedTimeOffset2 = 13330 + private val expectedSize2 = 6 + + /** + * Test Packet 3 + * + * Has Calibration Octet in the annunciation + * + */ + private val testPacket3: ByteArray = byteArrayOf(0x07, 0x40.toByte(), 0x62, 0xF1.toByte(), 0x12, 0x34, 0x01) + private val expectedParseResult3: Boolean = true + private val expectedConcentration3: Float = 35.4.toFloat() + private val expectedTrend3 = null + private val expectedQuality3 = null + private val expectedSensorStatusAnnunciation3: EnumSet = EnumSet.of( + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) + private val expectedFlags3: EnumSet = EnumSet.of( + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT) + private val expectedTimeOffset3 = 13330 + private val expectedSize3 = 7 + + /** + * Test Packet 4 + * Has Warning Octet in the annunciation + */ + private val testPacket4: ByteArray = byteArrayOf(0x07, 0x20.toByte(), 0x62, 0xF1.toByte(), 0x12, 0x34, 0x01) + private val expectedParseResult4: Boolean = true + private val expectedConcentration4: Float = 35.4.toFloat() + private val expectedTrend4 = null + private val expectedQuality4 = null + private val expectedSensorStatusAnnunciation4: EnumSet = EnumSet.of(SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL) + private val expectedFlags4: EnumSet = EnumSet.of(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) + private val expectedTimeOffset4 = 13330 + private val expectedSize4 = 7 + + /** + * Test Packet 5 + * Has Warning Octet and calibration in the annunciation + */ + private val testPacket5: ByteArray = byteArrayOf(0x08, 0x60.toByte(), 0x62, 0xF1.toByte(), 0x12, 0x34, 0x01, 0x01) + private val expectedParseResult5: Boolean = true + private val expectedConcentration5: Float = 35.4.toFloat() + private val expectedTrend5 = null + private val expectedQuality5 = null + private val expectedSensorStatusAnnunciation5: EnumSet = EnumSet.of( + SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) + private val expectedFlags5: EnumSet = EnumSet.of( + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) + private val expectedTimeOffset5 = 13330 + private val expectedSize5 = 8 + + /** + * Test Packet 6 + * Nagative Concentration, a erroneous case, but it wont report error because it is not the parser + * responsibility to validate values. + */ + private val testPacket6: ByteArray = byteArrayOf(0x08, 0x60.toByte(), 0xDD.toByte(), 0xFF.toByte(), 0x12, 0x34, 0x01, 0x01) + private val expectedParseResult6: Boolean = true + private val expectedConcentration6: Float = -3.5.toFloat() + private val expectedTrend6 = null + private val expectedQuality6 = null + private val expectedSensorStatusAnnunciation6: EnumSet = EnumSet.of( + SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) + private val expectedFlags6: EnumSet = EnumSet.of( + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) + private val expectedTimeOffset6 = 13330 + private val expectedSize6 = 8 + + /** + * Test Packet 7 + * Trend present + */ + private val testPacket7: ByteArray = byteArrayOf(0x0A, 0x61.toByte(), 0x62.toByte(), 0xF1.toByte(), 0x12, 0x34, 0x01, 0x01, 0xF3.toByte(), 0xFF.toByte()) + private val expectedParseResult7: Boolean = true + private val expectedConcentration7: Float = 35.4.toFloat() + private val expectedTrend7 = -1.3.toFloat() + private val expectedQuality7 = null + private val expectedSensorStatusAnnunciation7: EnumSet = EnumSet.of( + SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) + private val expectedFlags7: EnumSet = EnumSet.of( + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT, + Flags.CGM_TREND_INFORMATION_PRESENT) + private val expectedTimeOffset7 = 13330 + private val expectedSize7 = 10 + + + /** + * Test Packet 8 + * Quality present + */ + private val testPacket8: ByteArray = byteArrayOf(0x0A, 0x62.toByte(), 0x62.toByte(), 0xF1.toByte(), 0x12, 0x34, 0x01, 0x01, 0xe7.toByte(), 0xF3.toByte()) + private val expectedParseResult8: Boolean = true + private val expectedConcentration8: Float = 35.4.toFloat() + private val expectedTrend8 = null + private val expectedQuality8 = 99.9.toFloat() + private val expectedSensorStatusAnnunciation8: EnumSet = EnumSet.of( + SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, + SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) + private val expectedFlags8: EnumSet = EnumSet.of( + Flags.CGM_QUALITY_PRESENT, + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, + Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) + private val expectedTimeOffset8 = 13330 + private val expectedSize8 = 10 + + @Test + fun testParseSuccessfully() { + Assert.assertEquals(expectedParseResult1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).successfulParsing) + Assert.assertEquals(expectedParseResult2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).successfulParsing) + Assert.assertEquals(expectedParseResult3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).successfulParsing) + Assert.assertEquals(expectedParseResult4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).successfulParsing) + Assert.assertEquals(expectedParseResult5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).successfulParsing) + Assert.assertEquals(expectedParseResult6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).successfulParsing) + Assert.assertEquals(expectedParseResult7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).successfulParsing) + Assert.assertEquals(expectedParseResult8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).successfulParsing) + } + + @Test + fun testParsingConcentrationField() { + Assert.assertEquals(expectedConcentration1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).cgmGlucoseConcentration) + Assert.assertEquals(expectedConcentration8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).cgmGlucoseConcentration) + } + + @Test + fun testParsingTrendInformation() { + Assert.assertEquals(expectedTrend1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).cgmTrendInformation) + Assert.assertEquals(expectedTrend2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).cgmTrendInformation) + Assert.assertEquals(expectedTrend3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).cgmTrendInformation) + Assert.assertEquals(expectedTrend4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).cgmTrendInformation) + Assert.assertEquals(expectedTrend5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).cgmTrendInformation) + Assert.assertEquals(expectedTrend6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).cgmTrendInformation) + Assert.assertEquals(expectedTrend7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).cgmTrendInformation) + Assert.assertEquals(expectedTrend8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).cgmTrendInformation) + } + + @Test + fun testParsingQualityField() { + Assert.assertEquals(expectedQuality1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).cgmQuality) + Assert.assertEquals(expectedQuality2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).cgmQuality) + Assert.assertEquals(expectedQuality3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).cgmQuality) + Assert.assertEquals(expectedQuality4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).cgmQuality) + Assert.assertEquals(expectedQuality5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).cgmQuality) + Assert.assertEquals(expectedQuality6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).cgmQuality) + Assert.assertEquals(expectedQuality7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).cgmQuality) + Assert.assertEquals(expectedQuality8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).cgmQuality) + } + + @Test + fun testParsingStatusAnnunciationFlags() { + Assert.assertEquals(expectedSensorStatusAnnunciation1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).sensorStatusAnnunciation) + Assert.assertEquals(expectedSensorStatusAnnunciation8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).sensorStatusAnnunciation) + } + + @Test + fun testParsingFlags() { + Assert.assertEquals(expectedFlags1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).flags) + Assert.assertEquals(expectedFlags2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).flags) + Assert.assertEquals(expectedFlags3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).flags) + Assert.assertEquals(expectedFlags4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).flags) + Assert.assertEquals(expectedFlags5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).flags) + Assert.assertEquals(expectedFlags6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).flags) + Assert.assertEquals(expectedFlags7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).flags) + Assert.assertEquals(expectedFlags8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).flags) + } + + @Test + fun testParsingSize() { + Assert.assertEquals(expectedSize1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).size) + Assert.assertEquals(expectedSize2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).size) + Assert.assertEquals(expectedSize3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).size) + Assert.assertEquals(expectedSize4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).size) + Assert.assertEquals(expectedSize5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).size) + Assert.assertEquals(expectedSize6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).size) + Assert.assertEquals(expectedSize7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).size) + Assert.assertEquals(expectedSize8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).size) + } + + @Test + fun testParsingOffset() { + Assert.assertEquals(expectedTimeOffset1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).timeOffset) + Assert.assertEquals(expectedTimeOffset2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).timeOffset) + Assert.assertEquals(expectedTimeOffset3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).timeOffset) + Assert.assertEquals(expectedTimeOffset4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).timeOffset) + Assert.assertEquals(expectedTimeOffset5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).timeOffset) + Assert.assertEquals(expectedTimeOffset6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).timeOffset) + Assert.assertEquals(expectedTimeOffset7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).timeOffset) + Assert.assertEquals(expectedTimeOffset8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).timeOffset) + } + +} \ No newline at end of file From 3bb46b3ebd6ecd1f82c313c837fe36150c427e44 Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Wed, 12 Sep 2018 09:11:33 -0400 Subject: [PATCH 06/11] wip racp test --- .../compoundcharacteristic/RACP.kt | 102 +++++++++++------- .../compoundcharacteristic/RACPTest.kt | 43 ++++++++ 2 files changed, 107 insertions(+), 38 deletions(-) create mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt index 1cdc029..6bc3356 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt @@ -1,5 +1,6 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic +import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic import android.util.Log import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic @@ -8,21 +9,30 @@ import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristi import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Filter import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Opcode import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Operator +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.ResponseCode import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import kotlin.math.log -class RACP(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : +class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : BaseCharacteristic(c, GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc), Composable { override val tag: String = RACP::class.java.canonicalName + var opcode: Opcode? = null var operator: Operator? = null var filterType: Filter? = null + + /** + * The following variables stores the possible variables from parsing + */ var minimumFilterValueSequenceNumber: Int? = null var maximumFilterValueSequenceNumber: Int? = null var minimumFilterValueUserFacingTime: BluetoothDateTime? = null var maximumFilterValueUserFacingTime: BluetoothDateTime? = null + var numberOfRecordResponse : Int? = null + var requestOpcode : Opcode? = null + var responseCode : ResponseCode? = null val hasCrc: Boolean = hasCrc @@ -30,55 +40,61 @@ class RACP(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : var errorFreeParsing = false opcode = Opcode.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) //Extract operator - when (opcode){ + when (opcode) { null -> { Log.e(tag, "Opcode is null, packet might have been corrucpted") return errorFreeParsing } Opcode.REPORT_NUMBER_OF_STORED_RECORDS, Opcode.DELETE_STORED_RECORDS, - Opcode.REPORT_STORED_RECORDS->{ + Opcode.REPORT_STORED_RECORDS -> { operator = Operator.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + parseGenericOperand(c) } - Opcode.ABORT_OPERATION, - Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE, - Opcode.RESPONSE_CODE->{ + Opcode.ABORT_OPERATION -> { operator = Operator.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) - if(operator != Operator.NULL){ + if (operator != Operator.NULL) { Log.e(tag, "operator must be null, when opcode is Abort Operation") - return errorFreeParsing + return errorFreeParsing } } - else->{ + Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE -> { + operator = Operator.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + if (operator != Operator.NULL) { + Log.e(tag, "operator must be null, when opcode is Abort Operation") + return errorFreeParsing + } + numberOfRecordResponse = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + } + Opcode.RESPONSE_CODE -> { + operator = Operator.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + if (operator != Operator.NULL) { + Log.e(tag, "operator must be null, when opcode is Abort Operation") + return errorFreeParsing + } + requestOpcode = Opcode.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + responseCode = ResponseCode.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + } + else -> { Log.e(tag, "unknown opcode $opcode , exiting parsing") return errorFreeParsing } } - - //Extract operand - when (operator) { - Operator.GREATER_THAN_OR_EQUAL_TO->{ - filterType = Filter.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) - minimumFilterValue = getNextIntValue() - } - Operator.LESS_THAN_OR_EQUAL_TO, - - } - - + errorFreeParsing = true + return errorFreeParsing } - private fun parseGenericOperand(c : BluetoothGattCharacteristic){ - if(filterType == Filter.SEQUENCE_NUMBER){ - when(operator){ - Operator.LESS_THAN_OR_EQUAL_TO ->{ + private fun parseGenericOperand(c: BluetoothGattCharacteristic) { + if (filterType == Filter.SEQUENCE_NUMBER) { + when (operator) { + Operator.LESS_THAN_OR_EQUAL_TO -> { maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) } - Operator.GREATER_THAN_OR_EQUAL_TO ->{ + Operator.GREATER_THAN_OR_EQUAL_TO -> { minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) } - Operator.WITHIN_RANGE_OF_INCLUSIVE->{ + Operator.WITHIN_RANGE_OF_INCLUSIVE -> { maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) } @@ -86,30 +102,40 @@ class RACP(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : Operator.FIRST_RECORD, Operator.LAST_RECORD -> { Log.i(tag, "${operator.toString()} does not need operand") - return } - else->{ + else -> { Log.e(tag, "unknown operator $operator") } } - }else if (filterType == Filter.USER_FACING_TIME){ - when(operator){ - Operator.LESS_THAN_OR_EQUAL_TO->{ + } else if (filterType == Filter.USER_FACING_TIME) { + when (operator) { + Operator.LESS_THAN_OR_EQUAL_TO -> { maximumFilterValueUserFacingTime = parseBluetoothDateTime(c) } - Operator.GREATER_THAN_OR_EQUAL_TO->{ + Operator.GREATER_THAN_OR_EQUAL_TO -> { minimumFilterValueUserFacingTime = parseBluetoothDateTime(c) } - Operator.WITHIN_RANGE_OF_INCLUSIVE->{ - + Operator.WITHIN_RANGE_OF_INCLUSIVE -> { + minimumFilterValueUserFacingTime = parseBluetoothDateTime(c) + maximumFilterValueUserFacingTime = parseBluetoothDateTime(c) + + } + Operator.ALL_RECORDS, + Operator.FIRST_RECORD, + Operator.LAST_RECORD -> { + Log.i(tag, "opcode $opcode does not need operands") + } + else -> { + Log.e(tag, "unknown operator $operator") } } + }else{ + throw IllegalStateException("unable to handle filter type $filterType") } - } - private fun parseBluetoothDateTime(c : BluetoothGattCharacteristic) : BluetoothDateTime{ - return BluetoothDateTime( + private fun parseBluetoothDateTime(c: BluetoothGattCharacteristic): BluetoothDateTime { + return BluetoothDateTime( _year = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16)), _month = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)), _day = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)), diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt new file mode 100644 index 0000000..ab1cc5c --- /dev/null +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt @@ -0,0 +1,43 @@ +package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic + +import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Opcode +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Operator +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.ResponseCode +import org.junit.Assert.* + +class RACPTest : BaseTest() { + /** + * Test Packet 1 + * General Response, successful2w + */ + private val testPacket1 = byteArrayOf(0x06, 0x00, 0x01, 0x01) + private val expectedParsingResult1 = true + private val expectedOpcode1 = Opcode.RESPONSE_CODE + private val expectedOperator1 = Operator.NULL + private val expectedFilterType1 = null + private val expectedMinimumSequenceNumber1 = null + private val expectedMaximumSequenceNumber1 = null + private val expectedMinimumUserFacingTime1 = null + private val expectedMaximumUserFacingTime1 = null + private val expectedNumberOfRecordResponse = null + private val expectedRequestCode1 = Opcode.REPORT_STORED_RECORDS + private val expectedRequestResult1 = ResponseCode.SUCCESS + + /** + * Test Packet xx + * General Response, successful2w + */ + private val testPacketxx = byteArrayOf(0x06, 0x00, 0x01, 0x01) + private val expectedParsingResultxx = true + private val expectedOpcodexx = Opcode.RESPONSE_CODE + private val expectedOperatorxx = Operator.NULL + private val expectedFilterTypexx = null + private val expectedMinimumSequenceNumberxx = null + private val expectedMaximumSequenceNumberxx = null + private val expectedMinimumUserFacingTimexx = null + private val expectedMaximumUserFacingTimexx = null + private val expectedNumberOfRecordResponse = null + private val expectedRequestCodexx = Opcode.REPORT_STORED_RECORDS + private val expectedRequestResultxx = ResponseCode.SUCCESS +} From 41ff7c64adbb09d4165b8e3460c73b95d0bebeb3 Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Mon, 17 Sep 2018 08:51:18 -0400 Subject: [PATCH 07/11] wip --- .../compoundcharacteristic/RACP.kt | 181 +++++++- .../common/BaseCharacteristic.kt | 43 ++ .../compoundcharacteristic/RACPTest.kt | 422 ++++++++++++++++-- 3 files changed, 597 insertions(+), 49 deletions(-) diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt index 6bc3356..0dbc800 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt @@ -13,11 +13,20 @@ import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Response import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import kotlin.math.log -class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : - BaseCharacteristic(c, GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc), - Composable { +class RACP : BaseCharacteristic, Composable { override val tag: String = RACP::class.java.canonicalName + /**Constructor for parsing mode*/ + constructor(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : + super(c, GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc) { + this.hasCrc = hasCrc + } + + /** Constructor for composing mode*/ + constructor(hasCrc: Boolean) : + super(GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc) { + this.hasCrc = hasCrc + } var opcode: Opcode? = null var operator: Operator? = null @@ -30,11 +39,11 @@ class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : var maximumFilterValueSequenceNumber: Int? = null var minimumFilterValueUserFacingTime: BluetoothDateTime? = null var maximumFilterValueUserFacingTime: BluetoothDateTime? = null - var numberOfRecordResponse : Int? = null - var requestOpcode : Opcode? = null - var responseCode : ResponseCode? = null + var numberOfRecordResponse: Int? = null + var requestOpcode: Opcode? = null + var responseCode: ResponseCode? = null - val hasCrc: Boolean = hasCrc + var hasCrc: Boolean override fun parse(c: BluetoothGattCharacteristic): Boolean { var errorFreeParsing = false @@ -86,6 +95,18 @@ class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : } private fun parseGenericOperand(c: BluetoothGattCharacteristic) { + when(operator){ + null -> throw NullPointerException("operator is null") + Operator.ALL_RECORDS, + Operator.FIRST_RECORD, + Operator.LAST_RECORD -> { + Log.i(tag, "${operator.toString()} does not need operand") + return + } + } + + filterType = Filter.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) + if (filterType == Filter.SEQUENCE_NUMBER) { when (operator) { Operator.LESS_THAN_OR_EQUAL_TO -> { @@ -98,11 +119,6 @@ class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) } - Operator.ALL_RECORDS, - Operator.FIRST_RECORD, - Operator.LAST_RECORD -> { - Log.i(tag, "${operator.toString()} does not need operand") - } else -> { Log.e(tag, "unknown operator $operator") } @@ -120,20 +136,16 @@ class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : maximumFilterValueUserFacingTime = parseBluetoothDateTime(c) } - Operator.ALL_RECORDS, - Operator.FIRST_RECORD, - Operator.LAST_RECORD -> { - Log.i(tag, "opcode $opcode does not need operands") - } else -> { - Log.e(tag, "unknown operator $operator") + Log.e(tag, "unknown operator $operator") } } - }else{ + } else { throw IllegalStateException("unable to handle filter type $filterType") } } + private fun parseBluetoothDateTime(c: BluetoothGattCharacteristic): BluetoothDateTime { return BluetoothDateTime( _year = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16)), @@ -146,7 +158,136 @@ class RACP(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : } override fun composeCharacteristic(hasCrc: Boolean): ByteArray { - TODO("not implemented") //To change body of created functions use File | Settings | File Templates. + opcode?.run { + when (this) { + Opcode.REPORT_STORED_RECORDS, + Opcode.REPORT_NUMBER_OF_STORED_RECORDS, + Opcode.DELETE_STORED_RECORDS -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + composeQueryParameters() + return rawData + } + Opcode.RESPONSE_CODE -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(Operator.NULL.key, BluetoothGattCharacteristic.FORMAT_UINT8) + requestOpcode?.run { putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) } + ?: throw NullPointerException(" request opcode is null") + responseCode?.run { putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) } + ?: throw NullPointerException(" reponse code is null") + } + Opcode.ABORT_OPERATION -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(Operator.NULL.key, BluetoothGattCharacteristic.FORMAT_UINT8) + } + Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(Operator.NULL.key, BluetoothGattCharacteristic.FORMAT_UINT8) + numberOfRecordResponse?.run { putIntValue(this, BluetoothGattCharacteristic.FORMAT_UINT16) } + ?: throw NullPointerException(" nnumber of records is null") + } + else -> { + Log.e(tag, "unknown opcode") + } + } + } + return rawData + } + + private fun composeQueryParameters() { + operator?.run { + when (this) { + Operator.LAST_RECORD, + Operator.FIRST_RECORD, + Operator.ALL_RECORDS -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + } + Operator.GREATER_THAN_OR_EQUAL_TO -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + filterType?.run { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + when (this) { + Filter.SEQUENCE_NUMBER -> { + minimumFilterValueSequenceNumber?.run { + putIntValue(this, BluetoothGattCharacteristic.FORMAT_UINT16) + } ?: throw NullPointerException("The minimum value is null") + } + Filter.USER_FACING_TIME -> { + minimumFilterValueUserFacingTime?.run { + putBluetoothDateTime(this) + } ?: throw NullPointerException("The minimum value is null") + } + else -> { + throw IllegalArgumentException("Unsupported filter type") + } + } + } + } + Operator.LESS_THAN_OR_EQUAL_TO -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + filterType?.run { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + when (this) { + Filter.SEQUENCE_NUMBER -> { + maximumFilterValueSequenceNumber?.run { + putIntValue(this, BluetoothGattCharacteristic.FORMAT_UINT16) + } ?: throw NullPointerException("The maximum value is null") + } + Filter.USER_FACING_TIME -> { + maximumFilterValueUserFacingTime?.run { + putBluetoothDateTime(this) + } ?: throw NullPointerException("The maximum value is null") + } + else -> { + throw IllegalArgumentException("Unsupported filter type") + } + } + } + } + Operator.WITHIN_RANGE_OF_INCLUSIVE -> { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + filterType?.run { + putIntValue(this.key, BluetoothGattCharacteristic.FORMAT_UINT8) + when (this) { + Filter.SEQUENCE_NUMBER -> { + minimumFilterValueSequenceNumber?.run { + putIntValue(this, BluetoothGattCharacteristic.FORMAT_UINT16) + } ?: throw NullPointerException("The minimum value is null") + maximumFilterValueSequenceNumber?.run { + putIntValue(this, BluetoothGattCharacteristic.FORMAT_UINT16) + } ?: throw NullPointerException("The maximum value is null") + } + Filter.USER_FACING_TIME -> { + minimumFilterValueUserFacingTime?.run { + putBluetoothDateTime(this) + } ?: throw NullPointerException("The minimum value is null") + maximumFilterValueUserFacingTime?.run { + putBluetoothDateTime(this) + } ?: throw NullPointerException("The maximum value is null") + } + else -> { + throw IllegalArgumentException("Unsupported filter type") + } + } + } + } + else -> { + throw IllegalArgumentException("Unknown operator") + } + + } + + } + + + } + + private fun putBluetoothDateTime(input: BluetoothDateTime) { + putIntValue(input._year, BluetoothGattCharacteristic.FORMAT_UINT16) + putIntValue(input._month, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(input._day, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(input._hour, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(input._min, BluetoothGattCharacteristic.FORMAT_UINT8) + putIntValue(input._sec, BluetoothGattCharacteristic.FORMAT_UINT8) } } \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt index 07aa4c0..3243fcb 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt @@ -4,6 +4,7 @@ import android.bluetooth.BluetoothGattCharacteristic import android.util.Log import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.FormatType import org.ehealthinnovation.jdrfandroidbleparser.utility.CrcHelper +import java.util.* import kotlin.jvm.Throws import kotlin.jvm.java @@ -31,12 +32,23 @@ abstract class BaseCharacteristic(val uuid: Int) { } } + /** + * Use this constructor when a characteristic is created to compose/serialize a bluetooth object. + */ + constructor(uuid: Int, hasCrc: Boolean = false): this(uuid) { + this.composingcharacteristic = BluetoothGattCharacteristic(UUID.randomUUID(), + BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, + BluetoothGattCharacteristic.PERMISSION_WRITE) + } + open val tag = BaseCharacteristic::class.java.canonicalName as String val nullValueException = "Null characteristic interpretation, aborting parsing." var rawData: ByteArray = ByteArray(0) var characteristic: BluetoothGattCharacteristic? = null var successfulParsing: Boolean = false var offset = 0 + /**A dummy characteristic for composing a new characteristic*/ + private var composingcharacteristic: BluetoothGattCharacteristic? = null /** * Swallowing the exception is one of two viable options, some users might want any error to @@ -156,6 +168,36 @@ abstract class BaseCharacteristic(val uuid: Int) { } ?: throw NullPointerException("Format \"$formatType\" at offset \"$offset\" does " + "not relate to valid Float value...") + @Throws(NullPointerException::class) + + /** + * Put the input [value] of Bluetooth type [formatType] into a the internal [composingcharacteristic] + * object. The [offset] property will be incremented by the size of [formatType] + * + * @param value The integer value to be put into the serial buffer + * @param formatType Int indicating the format type of the input. An example is + * [BluetoothGattCharacteristic.FORMAT_UINT8] + * @return true if operation is successful; false otherwise + * @throws NullPointerException If the internal serialization buffer [composingcharacteristic] + * is null, this happens when [BaseCharacteristic] + */ + protected fun putIntValue(value :Int, formatType: Int) : Boolean{ + composingcharacteristic?.run { + val results = this.setValue(value, formatType, offset) + if(results) { + offset = getNextOffset(formatType, offset) + rawData = this.value ?: ByteArray(0) + } + return results + } ?: throw NullPointerException("composingcharacteristic is null, make sure the " + + "characteristic is initiated with the composing constructor") + } + + + + + + /** * Increments the current read index by the appropriate amount for the format type passed in. * @@ -171,4 +213,5 @@ abstract class BaseCharacteristic(val uuid: Int) { return newIndex } + } diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt index ab1cc5c..146efb2 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt @@ -1,43 +1,407 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import org.ehealthinnovation.jdrfandroidbleparser.BaseTest +import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Filter import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Opcode import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Operator import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.ResponseCode +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime +import org.junit.Assert import org.junit.Assert.* +import org.junit.Test -class RACPTest : BaseTest() { +class RACPTest : BaseTest(){ /** - * Test Packet 1 - * General Response, successful2w + * Data class for hosting test vector + */ + class racpTestVector( + val testPacket: ByteArray, + val expectedParsingResult: Boolean, + val expectedOpcode: Opcode, + val expectedOperator: Operator, + val expectedFilter: Filter? = null, + val expectedMinimumSequenceNumber: Int? = null, + val expectedMaximumSequenceNumber: Int? = null, + val expectedMinimumUserFacingTime: BluetoothDateTime? = null, + val expectedMaximumUserFacingTime: BluetoothDateTime? = null, + val expectedRequestOpcode: Opcode? = null, + val expectedResponseCode: ResponseCode? = null + ) + + val racpTestVectors: Map = HashMap() + /** + * Packet1 + * General response successful */ - private val testPacket1 = byteArrayOf(0x06, 0x00, 0x01, 0x01) - private val expectedParsingResult1 = true - private val expectedOpcode1 = Opcode.RESPONSE_CODE - private val expectedOperator1 = Operator.NULL - private val expectedFilterType1 = null + init { + racpTestVectors. + + } + private val testPacket1 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x01) + private val expectedParsedResult1 : Boolean = true + private val expectedOpcode1 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator1 : Operator = Operator.NULL + private val expectedFilterType1 = null private val expectedMinimumSequenceNumber1 = null private val expectedMaximumSequenceNumber1 = null private val expectedMinimumUserFacingTime1 = null private val expectedMaximumUserFacingTime1 = null - private val expectedNumberOfRecordResponse = null - private val expectedRequestCode1 = Opcode.REPORT_STORED_RECORDS - private val expectedRequestResult1 = ResponseCode.SUCCESS - - /** - * Test Packet xx - * General Response, successful2w - */ - private val testPacketxx = byteArrayOf(0x06, 0x00, 0x01, 0x01) - private val expectedParsingResultxx = true - private val expectedOpcodexx = Opcode.RESPONSE_CODE - private val expectedOperatorxx = Operator.NULL - private val expectedFilterTypexx = null - private val expectedMinimumSequenceNumberxx = null - private val expectedMaximumSequenceNumberxx = null - private val expectedMinimumUserFacingTimexx = null - private val expectedMaximumUserFacingTimexx = null - private val expectedNumberOfRecordResponse = null - private val expectedRequestCodexx = Opcode.REPORT_STORED_RECORDS - private val expectedRequestResultxx = ResponseCode.SUCCESS -} + private val expectedNumberOfRecordResponse1 = null + private val expectedRequestOpcode1 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode1 : ResponseCode = ResponseCode.SUCCESS + + /** + * Packet2 + * Opcode not supported + */ + private val testPacket2 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x02) + private val expectedParsedResult2 : Boolean = true + private val expectedOpcode2 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator2 : Operator = Operator.NULL + private val expectedFilterType2 = null + private val expectedMinimumSequenceNumber2 = null + private val expectedMaximumSequenceNumber2 = null + private val expectedMinimumUserFacingTime2 = null + private val expectedMaximumUserFacingTime2 = null + private val expectedNumberOfRecordResponse2 = null + private val expectedRequestOpcode2 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode2 : ResponseCode = ResponseCode.OP_CODE_NOT_SUPPORTED + + /** + * Packet3 + * Invalid Operator + */ + private val testPacket3 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x03) + private val expectedParsedResult3 : Boolean = true + private val expectedOpcode3 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator3 : Operator = Operator.NULL + private val expectedFilterType3 = null + private val expectedMinimumSequenceNumber3 = null + private val expectedMaximumSequenceNumber3 = null + private val expectedMinimumUserFacingTime3 = null + private val expectedMaximumUserFacingTime3 = null + private val expectedNumberOfRecordResponse3 = null + private val expectedRequestOpcode3 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode3 : ResponseCode = ResponseCode.INVALID_OPERATOR + + /** + * Packet4 + * Operator not supported + */ + private val testPacket4 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x04) + private val expectedParsedResult4 : Boolean = true + private val expectedOpcode4 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator4 : Operator = Operator.NULL + private val expectedFilterType4 = null + private val expectedMinimumSequenceNumber4 = null + private val expectedMaximumSequenceNumber4 = null + private val expectedMinimumUserFacingTime4 = null + private val expectedMaximumUserFacingTime4 = null + private val expectedNumberOfRecordResponse4 = null + private val expectedRequestOpcode4 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode4 : ResponseCode = ResponseCode.OPERATOR_NOT_SUPPORTED + + /** + * Packet5 + * General response successful + */ + private val testPacket5 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x05) + private val expectedParsedResult5 : Boolean = true + private val expectedOpcode5 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator5 : Operator = Operator.NULL + private val expectedFilterType5 = null + private val expectedMinimumSequenceNumber5 = null + private val expectedMaximumSequenceNumber5 = null + private val expectedMinimumUserFacingTime5 = null + private val expectedMaximumUserFacingTime5 = null + private val expectedNumberOfRecordResponse5 = null + private val expectedRequestOpcode5 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode5 : ResponseCode = ResponseCode.INVALID_OPERAND + + /** + * Packet6 + * No record found + */ + private val testPacket6 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x06) + private val expectedParsedResult6 : Boolean = true + private val expectedOpcode6 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator6 : Operator = Operator.NULL + private val expectedFilterType6 = null + private val expectedMinimumSequenceNumber6 = null + private val expectedMaximumSequenceNumber6 = null + private val expectedMinimumUserFacingTime6 = null + private val expectedMaximumUserFacingTime6 = null + private val expectedNumberOfRecordResponse6 = null + private val expectedRequestOpcode6 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode6 : ResponseCode = ResponseCode.NO_RECORDS_FOUND + + /** + * Packet7 + * Abort unsuccessful + */ + private val testPacket7 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x07) + private val expectedParsedResult7 : Boolean = true + private val expectedOpcode7 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator7 : Operator = Operator.NULL + private val expectedFilterType7 = null + private val expectedMinimumSequenceNumber7 = null + private val expectedMaximumSequenceNumber7 = null + private val expectedMinimumUserFacingTime7 = null + private val expectedMaximumUserFacingTime7 = null + private val expectedNumberOfRecordResponse7 = null + private val expectedRequestOpcode7 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode7 : ResponseCode = ResponseCode.ABORT_UNSUCCESSFUL + + /** + * Packet8 + * Procedure not completed + */ + private val testPacket8 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x08) + private val expectedParsedResult8 : Boolean = true + private val expectedOpcode8 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator8 : Operator = Operator.NULL + private val expectedFilterType8 = null + private val expectedMinimumSequenceNumber8 = null + private val expectedMaximumSequenceNumber8 = null + private val expectedMinimumUserFacingTime8 = null + private val expectedMaximumUserFacingTime8 = null + private val expectedNumberOfRecordResponse8 = null + private val expectedRequestOpcode8 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode8 : ResponseCode = ResponseCode.PROCEDURE_NOT_COMPLETED + + /** + * Packet9 + * Operand not supported + */ + private val testPacket9 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x09) + private val expectedParsedResult9 : Boolean = true + private val expectedOpcode9 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator9 : Operator = Operator.NULL + private val expectedFilterType9 = null + private val expectedMinimumSequenceNumber9 = null + private val expectedMaximumSequenceNumber9 = null + private val expectedMinimumUserFacingTime9 = null + private val expectedMaximumUserFacingTime9 = null + private val expectedNumberOfRecordResponse9 = null + private val expectedRequestOpcode9 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedResponseCode9 : ResponseCode = ResponseCode.OPERAND_NOT_SUPPORTED + + /** + * Packet10 + * reponse parser, opcode - delete stored record + */ + private val testPacket10 : ByteArray = byteArrayOf(0x06, 0x00, 0x02, 0x01) + private val expectedParsedResult10 : Boolean = true + private val expectedOpcode10 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator10 : Operator = Operator.NULL + private val expectedFilterType10 = null + private val expectedMinimumSequenceNumber10 = null + private val expectedMaximumSequenceNumber10 = null + private val expectedMinimumUserFacingTime10 = null + private val expectedMaximumUserFacingTime10 = null + private val expectedNumberOfRecordResponse10 = null + private val expectedRequestOpcode10 : Opcode = Opcode.DELETE_STORED_RECORDS + private val expectedResponseCode10 : ResponseCode = ResponseCode.SUCCESS + + /** + * Packet11 + * response parser, opcode - abort operation + */ + private val testPacket11 : ByteArray = byteArrayOf(0x06, 0x00, 0x03, 0x01) + private val expectedParsedResult11 : Boolean = true + private val expectedOpcode11 : Opcode = Opcode.RESPONSE_CODE + private val expectedOperator11 : Operator = Operator.NULL + private val expectedFilterType11 = null + private val expectedMinimumSequenceNumber11 = null + private val expectedMaximumSequenceNumber11 = null + private val expectedMinimumUserFacingTime11 = null + private val expectedMaximumUserFacingTime11 = null + private val expectedNumberOfRecordResponse11 = null + private val expectedRequestOpcode11 : Opcode = Opcode.ABORT_OPERATION + private val expectedResponseCode11 : ResponseCode = ResponseCode.SUCCESS + + /** + * Packet12 + * report number of records + */ + private val testPacket12 : ByteArray = byteArrayOf(0x05, 0x00, 0x03, 0x00) + private val expectedParsedResult12 : Boolean = true + private val expectedOpcode12 : Opcode = Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE + private val expectedOperator12 : Operator = Operator.NULL + private val expectedFilterType12 = null + private val expectedMinimumSequenceNumber12 = null + private val expectedMaximumSequenceNumber12 = null + private val expectedMinimumUserFacingTime12 = null + private val expectedMaximumUserFacingTime12 = null + private val expectedNumberOfRecordResponse12 = 3 + private val expectedRequestOpcode12 = null + private val expectedResponseCode12 = null + + /** + * Packet13 + * Composing packet - Report all records + */ + private val testPacket13 : ByteArray = byteArrayOf(0x01, 0x01) + private val expectedParsedResult13 : Boolean = true + private val expectedOpcode13 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator13 : Operator = Operator.ALL_RECORDS + private val expectedFilterType13 = null + private val expectedMinimumSequenceNumber13 = null + private val expectedMaximumSequenceNumber13 = null + private val expectedMinimumUserFacingTime13 = null + private val expectedMaximumUserFacingTime13 = null + private val expectedNumberOfRecordResponse13 = null + private val expectedRequestOpcode13 = null + private val expectedResponseCode13 = null + + /** + * Packet14 + * Composing packet - report records - larger than or equal to + */ + private val testPacket14 : ByteArray = byteArrayOf(0x01, 0x03, 0x01, 0x05, 0x00) + private val expectedParsedResult14 : Boolean = true + private val expectedOpcode14 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator14 : Operator = Operator.GREATER_THAN_OR_EQUAL_TO + private val expectedFilterType14 : Filter = Filter.SEQUENCE_NUMBER + private val expectedMinimumSequenceNumber14 = 5 + private val expectedMaximumSequenceNumber14 = null + private val expectedMinimumUserFacingTime14 = null + private val expectedMaximumUserFacingTime14 = null + private val expectedNumberOfRecordResponse14 = null + private val expectedRequestOpcode14 = null + private val expectedResponseCode14 = null + + /** + * Packet15 + * Composing packet - report number of records - less than or equal to + * + */ + private val testPacket15 : ByteArray = byteArrayOf(0x01, 0x02, 0x01, 0xff.toByte(), 0x00) + private val expectedParsedResult15 : Boolean = true + private val expectedOpcode15 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator15 : Operator = Operator.LESS_THAN_OR_EQUAL_TO + private val expectedFilterType15 : Filter = Filter.SEQUENCE_NUMBER + private val expectedMinimumSequenceNumber15 = null + private val expectedMaximumSequenceNumber15 = 255 + private val expectedMinimumUserFacingTime15 = null + private val expectedMaximumUserFacingTime15 = null + private val expectedNumberOfRecordResponse15 = null + private val expectedRequestOpcode15 = null + private val expectedResponseCode15 = null + + /** + * Packet16 + * Composing packet - report records - between A and B + */ + private val testPacket16 : ByteArray = byteArrayOf(0x01, 0x04, 0x01, 0x01, 0x00, 0xFE.toByte(), 0x00) + private val expectedParsedResult16 : Boolean = true + private val expectedOpcode16 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator16 : Operator = Operator.WITHIN_RANGE_OF_INCLUSIVE + private val expectedFilterType16 : Filter = Filter.SEQUENCE_NUMBER + private val expectedMinimumSequenceNumber16 = 1 + private val expectedMaximumSequenceNumber16 = 254 + private val expectedMinimumUserFacingTime16 = null + private val expectedMaximumUserFacingTime16 = null + private val expectedNumberOfRecordResponse16 = null + private val expectedRequestOpcode16 = null + private val expectedResponseCode16 = null + + /** + * Packet17 + * Composing packet - report records - first record + */ + private val testPacket17 : ByteArray = byteArrayOf(0x01, 0x05) + private val expectedParsedResult17 : Boolean = true + private val expectedOpcode17 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator17 : Operator = Operator.FIRST_RECORD + private val expectedFilterType17 = null + private val expectedMinimumSequenceNumber17 = null + private val expectedMaximumSequenceNumber17 = null + private val expectedMinimumUserFacingTime17 = null + private val expectedMaximumUserFacingTime17 = null + private val expectedNumberOfRecordResponse17 = null + private val expectedRequestOpcode17 = null + private val expectedResponseCode17 = null + + /** + * Packet18 + * Composing packet - report records - last record + */ + private val testPacket18 : ByteArray = byteArrayOf(0x01, 0x06) + private val expectedParsedResult18 : Boolean = true + private val expectedOpcode18 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator18 : Operator = Operator.FIRST_RECORD + private val expectedFilterType18 = null + private val expectedMinimumSequenceNumber18 = null + private val expectedMaximumSequenceNumber18 = null + private val expectedMinimumUserFacingTime18 = null + private val expectedMaximumUserFacingTime18 = null + private val expectedNumberOfRecordResponse18 = null + private val expectedRequestOpcode18 = null + private val expectedResponseCode18 = null + + /** + * Packet19 + * Composing packet - report records - error case, unsupported operator + */ + private val testPacket19 = byteArrayOf(0x01,0x00) + private val expectedParsedResult19 : Boolean = false + private val expectedOpcode19 : Opcode = Opcode.REPORT_STORED_RECORDS + private val expectedOperator19 : Operator = Operator.NULL + private val expectedFilterType19 = null + private val expectedMinimumSequenceNumber19 = null + private val expectedMaximumSequenceNumber19 = null + private val expectedMinimumUserFacingTime19 = null + private val expectedMaximumUserFacingTime19 = null + private val expectedNumberOfRecordResponse19 = null + private val expectedRequestOpcode19 = null + private val expectedResponseCode19 = null + + /** + * Packet20 + * Composing packet - report records - error case, unsupported opcode + */ + private val testPacket20 = byteArrayOf(0x00,0x00) + private val expectedParsedResult20 : Boolean = false + private val expectedOpcode20 : Opcode = Opcode.RESERVED_FOR_FUTURE_USE + private val expectedOperator20 : Operator = Operator.NULL + private val expectedFilterType20 = null + private val expectedMinimumSequenceNumber20 = null + private val expectedMaximumSequenceNumber20 = null + private val expectedMinimumUserFacingTime20 = null + private val expectedMaximumUserFacingTime20 = null + private val expectedNumberOfRecordResponse20 = null + private val expectedRequestOpcode20 = null + private val expectedResponseCode20 = null + + + @Test + fun testParsingSuccessIndicator(){ + Assert.assertEquals(expectedParsedResult1, RACP(mockBTCharacteristic(testPacket1), false).successfulParsing) + Assert.assertEquals(expectedParsedResult2, RACP(mockBTCharacteristic(testPacket2), false).successfulParsing) + Assert.assertEquals(expectedParsedResult3, RACP(mockBTCharacteristic(testPacket3), false).successfulParsing) + Assert.assertEquals(expectedParsedResult4, RACP(mockBTCharacteristic(testPacket4), false).successfulParsing) + Assert.assertEquals(expectedParsedResult5, RACP(mockBTCharacteristic(testPacket5), false).successfulParsing) + Assert.assertEquals(expectedParsedResult6, RACP(mockBTCharacteristic(testPacket6), false).successfulParsing) + Assert.assertEquals(expectedParsedResult7, RACP(mockBTCharacteristic(testPacket7), false).successfulParsing) + Assert.assertEquals(expectedParsedResult8, RACP(mockBTCharacteristic(testPacket8), false).successfulParsing) + Assert.assertEquals(expectedParsedResult9, RACP(mockBTCharacteristic(testPacket9), false).successfulParsing) + Assert.assertEquals(expectedParsedResult10, RACP(mockBTCharacteristic(testPacket10), false).successfulParsing) + Assert.assertEquals(expectedParsedResult11, RACP(mockBTCharacteristic(testPacket11), false).successfulParsing) + Assert.assertEquals(expectedParsedResult12, RACP(mockBTCharacteristic(testPacket12), false).successfulParsing) + Assert.assertEquals(expectedParsedResult13, RACP(mockBTCharacteristic(testPacket13), false).successfulParsing) + Assert.assertEquals(expectedParsedResult14, RACP(mockBTCharacteristic(testPacket14), false).successfulParsing) + Assert.assertEquals(expectedParsedResult15, RACP(mockBTCharacteristic(testPacket15), false).successfulParsing) + Assert.assertEquals(expectedParsedResult16, RACP(mockBTCharacteristic(testPacket16), false).successfulParsing) + Assert.assertEquals(expectedParsedResult17, RACP(mockBTCharacteristic(testPacket17), false).successfulParsing) + Assert.assertEquals(expectedParsedResult18, RACP(mockBTCharacteristic(testPacket18), false).successfulParsing) + Assert.assertEquals(expectedParsedResult19, RACP(mockBTCharacteristic(testPacket19), false).successfulParsing) + Assert.assertEquals(expectedParsedResult20, RACP(mockBTCharacteristic(testPacket20), false).successfulParsing) + + } + + @Test + fun testParsingOpcode(){ + + } +} \ No newline at end of file From 852c939ae3c3a03a9845744c9f965bfaa529913e Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Mon, 17 Sep 2018 13:08:31 -0400 Subject: [PATCH 08/11] wip --- .../compoundcharacteristic/RACP.kt | 4 +- .../compoundcharacteristic/RACPTest.kt | 846 ++++++++++-------- 2 files changed, 496 insertions(+), 354 deletions(-) diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt index 0dbc800..6b4a7c6 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt @@ -95,7 +95,7 @@ class RACP : BaseCharacteristic, Composable { } private fun parseGenericOperand(c: BluetoothGattCharacteristic) { - when(operator){ + when (operator) { null -> throw NullPointerException("operator is null") Operator.ALL_RECORDS, Operator.FIRST_RECORD, @@ -116,8 +116,8 @@ class RACP : BaseCharacteristic, Composable { minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) } Operator.WITHIN_RANGE_OF_INCLUSIVE -> { - maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) minimumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) + maximumFilterValueSequenceNumber = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) } else -> { Log.e(tag, "unknown operator $operator") diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt index 146efb2..45a54e0 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt @@ -9,399 +9,541 @@ import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import org.junit.Assert import org.junit.Assert.* import org.junit.Test +import java.util.logging.LogRecord -class RACPTest : BaseTest(){ +class RACPTest : BaseTest() { /** * Data class for hosting test vector - */ - class racpTestVector( + */ + class RacpTestVector( val testPacket: ByteArray, val expectedParsingResult: Boolean, val expectedOpcode: Opcode, - val expectedOperator: Operator, + val expectedOperator: Operator?, val expectedFilter: Filter? = null, val expectedMinimumSequenceNumber: Int? = null, val expectedMaximumSequenceNumber: Int? = null, val expectedMinimumUserFacingTime: BluetoothDateTime? = null, val expectedMaximumUserFacingTime: BluetoothDateTime? = null, val expectedRequestOpcode: Opcode? = null, - val expectedResponseCode: ResponseCode? = null + val expectedResponseCode: ResponseCode? = null, + val expectedNumberOfRecord: Int? = null, + val hasCrc: Boolean = false ) - val racpTestVectors: Map = HashMap() - /** - * Packet1 - * General response successful - */ + val racpTestVectors = mutableMapOf() + init { - racpTestVectors. + /** + * packet1 + * general response successful + */ + racpTestVectors[1] = RacpTestVector( + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x01), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.SUCCESS + ) + /** + * Packet2 + * Opcode not supported + */ + racpTestVectors[2] = RacpTestVector( + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x02), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.OP_CODE_NOT_SUPPORTED) - } - private val testPacket1 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x01) - private val expectedParsedResult1 : Boolean = true - private val expectedOpcode1 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator1 : Operator = Operator.NULL - private val expectedFilterType1 = null - private val expectedMinimumSequenceNumber1 = null - private val expectedMaximumSequenceNumber1 = null - private val expectedMinimumUserFacingTime1 = null - private val expectedMaximumUserFacingTime1 = null - private val expectedNumberOfRecordResponse1 = null - private val expectedRequestOpcode1 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode1 : ResponseCode = ResponseCode.SUCCESS + /** + * Packet3 + * Invalid Operator + */ + racpTestVectors[3] = RacpTestVector( + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x03), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.INVALID_OPERATOR + ) + /** - /** - * Packet2 - * Opcode not supported - */ - private val testPacket2 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x02) - private val expectedParsedResult2 : Boolean = true - private val expectedOpcode2 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator2 : Operator = Operator.NULL - private val expectedFilterType2 = null - private val expectedMinimumSequenceNumber2 = null - private val expectedMaximumSequenceNumber2 = null - private val expectedMinimumUserFacingTime2 = null - private val expectedMaximumUserFacingTime2 = null - private val expectedNumberOfRecordResponse2 = null - private val expectedRequestOpcode2 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode2 : ResponseCode = ResponseCode.OP_CODE_NOT_SUPPORTED + * Packet4 + * Operator not supported + */ + racpTestVectors[4] = RacpTestVector( - /** - * Packet3 - * Invalid Operator - */ - private val testPacket3 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x03) - private val expectedParsedResult3 : Boolean = true - private val expectedOpcode3 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator3 : Operator = Operator.NULL - private val expectedFilterType3 = null - private val expectedMinimumSequenceNumber3 = null - private val expectedMaximumSequenceNumber3 = null - private val expectedMinimumUserFacingTime3 = null - private val expectedMaximumUserFacingTime3 = null - private val expectedNumberOfRecordResponse3 = null - private val expectedRequestOpcode3 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode3 : ResponseCode = ResponseCode.INVALID_OPERATOR + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x04), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.OPERATOR_NOT_SUPPORTED - /** - * Packet4 - * Operator not supported - */ - private val testPacket4 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x04) - private val expectedParsedResult4 : Boolean = true - private val expectedOpcode4 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator4 : Operator = Operator.NULL - private val expectedFilterType4 = null - private val expectedMinimumSequenceNumber4 = null - private val expectedMaximumSequenceNumber4 = null - private val expectedMinimumUserFacingTime4 = null - private val expectedMaximumUserFacingTime4 = null - private val expectedNumberOfRecordResponse4 = null - private val expectedRequestOpcode4 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode4 : ResponseCode = ResponseCode.OPERATOR_NOT_SUPPORTED + ) + /** - /** - * Packet5 - * General response successful - */ - private val testPacket5 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x05) - private val expectedParsedResult5 : Boolean = true - private val expectedOpcode5 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator5 : Operator = Operator.NULL - private val expectedFilterType5 = null - private val expectedMinimumSequenceNumber5 = null - private val expectedMaximumSequenceNumber5 = null - private val expectedMinimumUserFacingTime5 = null - private val expectedMaximumUserFacingTime5 = null - private val expectedNumberOfRecordResponse5 = null - private val expectedRequestOpcode5 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode5 : ResponseCode = ResponseCode.INVALID_OPERAND + * Packet5 + * General response successful + */ + racpTestVectors[5] = RacpTestVector( - /** - * Packet6 - * No record found - */ - private val testPacket6 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x06) - private val expectedParsedResult6 : Boolean = true - private val expectedOpcode6 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator6 : Operator = Operator.NULL - private val expectedFilterType6 = null - private val expectedMinimumSequenceNumber6 = null - private val expectedMaximumSequenceNumber6 = null - private val expectedMinimumUserFacingTime6 = null - private val expectedMaximumUserFacingTime6 = null - private val expectedNumberOfRecordResponse6 = null - private val expectedRequestOpcode6 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode6 : ResponseCode = ResponseCode.NO_RECORDS_FOUND + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x05), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.INVALID_OPERAND - /** - * Packet7 - * Abort unsuccessful - */ - private val testPacket7 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x07) - private val expectedParsedResult7 : Boolean = true - private val expectedOpcode7 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator7 : Operator = Operator.NULL - private val expectedFilterType7 = null - private val expectedMinimumSequenceNumber7 = null - private val expectedMaximumSequenceNumber7 = null - private val expectedMinimumUserFacingTime7 = null - private val expectedMaximumUserFacingTime7 = null - private val expectedNumberOfRecordResponse7 = null - private val expectedRequestOpcode7 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode7 : ResponseCode = ResponseCode.ABORT_UNSUCCESSFUL + ) + /** - /** - * Packet8 - * Procedure not completed - */ - private val testPacket8 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x08) - private val expectedParsedResult8 : Boolean = true - private val expectedOpcode8 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator8 : Operator = Operator.NULL - private val expectedFilterType8 = null - private val expectedMinimumSequenceNumber8 = null - private val expectedMaximumSequenceNumber8 = null - private val expectedMinimumUserFacingTime8 = null - private val expectedMaximumUserFacingTime8 = null - private val expectedNumberOfRecordResponse8 = null - private val expectedRequestOpcode8 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode8 : ResponseCode = ResponseCode.PROCEDURE_NOT_COMPLETED + * Packet6 + * No record found + */ + racpTestVectors[6] = RacpTestVector( - /** - * Packet9 - * Operand not supported - */ - private val testPacket9 : ByteArray = byteArrayOf(0x06, 0x00, 0x01, 0x09) - private val expectedParsedResult9 : Boolean = true - private val expectedOpcode9 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator9 : Operator = Operator.NULL - private val expectedFilterType9 = null - private val expectedMinimumSequenceNumber9 = null - private val expectedMaximumSequenceNumber9 = null - private val expectedMinimumUserFacingTime9 = null - private val expectedMaximumUserFacingTime9 = null - private val expectedNumberOfRecordResponse9 = null - private val expectedRequestOpcode9 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedResponseCode9 : ResponseCode = ResponseCode.OPERAND_NOT_SUPPORTED + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x06), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.NO_RECORDS_FOUND - /** - * Packet10 - * reponse parser, opcode - delete stored record - */ - private val testPacket10 : ByteArray = byteArrayOf(0x06, 0x00, 0x02, 0x01) - private val expectedParsedResult10 : Boolean = true - private val expectedOpcode10 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator10 : Operator = Operator.NULL - private val expectedFilterType10 = null - private val expectedMinimumSequenceNumber10 = null - private val expectedMaximumSequenceNumber10 = null - private val expectedMinimumUserFacingTime10 = null - private val expectedMaximumUserFacingTime10 = null - private val expectedNumberOfRecordResponse10 = null - private val expectedRequestOpcode10 : Opcode = Opcode.DELETE_STORED_RECORDS - private val expectedResponseCode10 : ResponseCode = ResponseCode.SUCCESS + ) + /** - /** - * Packet11 - * response parser, opcode - abort operation - */ - private val testPacket11 : ByteArray = byteArrayOf(0x06, 0x00, 0x03, 0x01) - private val expectedParsedResult11 : Boolean = true - private val expectedOpcode11 : Opcode = Opcode.RESPONSE_CODE - private val expectedOperator11 : Operator = Operator.NULL - private val expectedFilterType11 = null - private val expectedMinimumSequenceNumber11 = null - private val expectedMaximumSequenceNumber11 = null - private val expectedMinimumUserFacingTime11 = null - private val expectedMaximumUserFacingTime11 = null - private val expectedNumberOfRecordResponse11 = null - private val expectedRequestOpcode11 : Opcode = Opcode.ABORT_OPERATION - private val expectedResponseCode11 : ResponseCode = ResponseCode.SUCCESS + * Packet7 + * Abort unsuccessful + */ + racpTestVectors[7] = RacpTestVector( - /** - * Packet12 - * report number of records - */ - private val testPacket12 : ByteArray = byteArrayOf(0x05, 0x00, 0x03, 0x00) - private val expectedParsedResult12 : Boolean = true - private val expectedOpcode12 : Opcode = Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE - private val expectedOperator12 : Operator = Operator.NULL - private val expectedFilterType12 = null - private val expectedMinimumSequenceNumber12 = null - private val expectedMaximumSequenceNumber12 = null - private val expectedMinimumUserFacingTime12 = null - private val expectedMaximumUserFacingTime12 = null - private val expectedNumberOfRecordResponse12 = 3 - private val expectedRequestOpcode12 = null - private val expectedResponseCode12 = null + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x07), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.ABORT_UNSUCCESSFUL - /** - * Packet13 - * Composing packet - Report all records - */ - private val testPacket13 : ByteArray = byteArrayOf(0x01, 0x01) - private val expectedParsedResult13 : Boolean = true - private val expectedOpcode13 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator13 : Operator = Operator.ALL_RECORDS - private val expectedFilterType13 = null - private val expectedMinimumSequenceNumber13 = null - private val expectedMaximumSequenceNumber13 = null - private val expectedMinimumUserFacingTime13 = null - private val expectedMaximumUserFacingTime13 = null - private val expectedNumberOfRecordResponse13 = null - private val expectedRequestOpcode13 = null - private val expectedResponseCode13 = null + ) + /** - /** - * Packet14 - * Composing packet - report records - larger than or equal to - */ - private val testPacket14 : ByteArray = byteArrayOf(0x01, 0x03, 0x01, 0x05, 0x00) - private val expectedParsedResult14 : Boolean = true - private val expectedOpcode14 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator14 : Operator = Operator.GREATER_THAN_OR_EQUAL_TO - private val expectedFilterType14 : Filter = Filter.SEQUENCE_NUMBER - private val expectedMinimumSequenceNumber14 = 5 - private val expectedMaximumSequenceNumber14 = null - private val expectedMinimumUserFacingTime14 = null - private val expectedMaximumUserFacingTime14 = null - private val expectedNumberOfRecordResponse14 = null - private val expectedRequestOpcode14 = null - private val expectedResponseCode14 = null + * Packet8 + * Procedure not completed + */ + racpTestVectors[8] = RacpTestVector( - /** - * Packet15 - * Composing packet - report number of records - less than or equal to - * - */ - private val testPacket15 : ByteArray = byteArrayOf(0x01, 0x02, 0x01, 0xff.toByte(), 0x00) - private val expectedParsedResult15 : Boolean = true - private val expectedOpcode15 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator15 : Operator = Operator.LESS_THAN_OR_EQUAL_TO - private val expectedFilterType15 : Filter = Filter.SEQUENCE_NUMBER - private val expectedMinimumSequenceNumber15 = null - private val expectedMaximumSequenceNumber15 = 255 - private val expectedMinimumUserFacingTime15 = null - private val expectedMaximumUserFacingTime15 = null - private val expectedNumberOfRecordResponse15 = null - private val expectedRequestOpcode15 = null - private val expectedResponseCode15 = null + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x08), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.PROCEDURE_NOT_COMPLETED - /** - * Packet16 - * Composing packet - report records - between A and B - */ - private val testPacket16 : ByteArray = byteArrayOf(0x01, 0x04, 0x01, 0x01, 0x00, 0xFE.toByte(), 0x00) - private val expectedParsedResult16 : Boolean = true - private val expectedOpcode16 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator16 : Operator = Operator.WITHIN_RANGE_OF_INCLUSIVE - private val expectedFilterType16 : Filter = Filter.SEQUENCE_NUMBER - private val expectedMinimumSequenceNumber16 = 1 - private val expectedMaximumSequenceNumber16 = 254 - private val expectedMinimumUserFacingTime16 = null - private val expectedMaximumUserFacingTime16 = null - private val expectedNumberOfRecordResponse16 = null - private val expectedRequestOpcode16 = null - private val expectedResponseCode16 = null + ) + /** - /** - * Packet17 - * Composing packet - report records - first record - */ - private val testPacket17 : ByteArray = byteArrayOf(0x01, 0x05) - private val expectedParsedResult17 : Boolean = true - private val expectedOpcode17 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator17 : Operator = Operator.FIRST_RECORD - private val expectedFilterType17 = null - private val expectedMinimumSequenceNumber17 = null - private val expectedMaximumSequenceNumber17 = null - private val expectedMinimumUserFacingTime17 = null - private val expectedMaximumUserFacingTime17 = null - private val expectedNumberOfRecordResponse17 = null - private val expectedRequestOpcode17 = null - private val expectedResponseCode17 = null + * Packet9 + * Operand not supported + */ + racpTestVectors[9] = RacpTestVector( - /** - * Packet18 - * Composing packet - report records - last record - */ - private val testPacket18 : ByteArray = byteArrayOf(0x01, 0x06) - private val expectedParsedResult18 : Boolean = true - private val expectedOpcode18 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator18 : Operator = Operator.FIRST_RECORD - private val expectedFilterType18 = null - private val expectedMinimumSequenceNumber18 = null - private val expectedMaximumSequenceNumber18 = null - private val expectedMinimumUserFacingTime18 = null - private val expectedMaximumUserFacingTime18 = null - private val expectedNumberOfRecordResponse18 = null - private val expectedRequestOpcode18 = null - private val expectedResponseCode18 = null + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x09), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.OPERAND_NOT_SUPPORTED - /** - * Packet19 - * Composing packet - report records - error case, unsupported operator - */ - private val testPacket19 = byteArrayOf(0x01,0x00) - private val expectedParsedResult19 : Boolean = false - private val expectedOpcode19 : Opcode = Opcode.REPORT_STORED_RECORDS - private val expectedOperator19 : Operator = Operator.NULL - private val expectedFilterType19 = null - private val expectedMinimumSequenceNumber19 = null - private val expectedMaximumSequenceNumber19 = null - private val expectedMinimumUserFacingTime19 = null - private val expectedMaximumUserFacingTime19 = null - private val expectedNumberOfRecordResponse19 = null - private val expectedRequestOpcode19 = null - private val expectedResponseCode19 = null - - /** - * Packet20 - * Composing packet - report records - error case, unsupported opcode - */ - private val testPacket20 = byteArrayOf(0x00,0x00) - private val expectedParsedResult20 : Boolean = false - private val expectedOpcode20 : Opcode = Opcode.RESERVED_FOR_FUTURE_USE - private val expectedOperator20 : Operator = Operator.NULL - private val expectedFilterType20 = null - private val expectedMinimumSequenceNumber20 = null - private val expectedMaximumSequenceNumber20 = null - private val expectedMinimumUserFacingTime20 = null - private val expectedMaximumUserFacingTime20 = null - private val expectedNumberOfRecordResponse20 = null - private val expectedRequestOpcode20 = null - private val expectedResponseCode20 = null + ) + /** + + * Packet10 + * reponse parser, opcode - delete stored record + */ + racpTestVectors[10] = RacpTestVector( + + testPacket = byteArrayOf(0x06, 0x00, 0x02, 0x01), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.DELETE_STORED_RECORDS, + expectedResponseCode = ResponseCode.SUCCESS + + ) + /** + + * Packet11 + * response parser, opcode - abort operation + */ + racpTestVectors[11] = RacpTestVector( + + testPacket = byteArrayOf(0x06, 0x00, 0x03, 0x01), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.ABORT_OPERATION, + expectedResponseCode = ResponseCode.SUCCESS + + ) + /** + + * Packet12 + * report number of records + */ + racpTestVectors[12] = RacpTestVector( + + testPacket = byteArrayOf(0x05, 0x00, 0x03, 0x00), + expectedParsingResult = true, + expectedOpcode = Opcode.NUMBER_OF_STORED_RECORDS_RESPONSE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = 3, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet13 + * Composing packet - Report all records + */ + racpTestVectors[13] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x01), + expectedParsingResult = true, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.ALL_RECORDS, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet14 + * Composing packet - report records - larger than or equal to + */ + racpTestVectors[14] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x03, 0x01, 0x05, 0x00), + expectedParsingResult = true, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.GREATER_THAN_OR_EQUAL_TO, + expectedFilter = Filter.SEQUENCE_NUMBER, + expectedMinimumSequenceNumber = 5, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet15 + * Composing packet - report number of records - less than or equal to + * + */ + racpTestVectors[15] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x02, 0x01, 0xff.toByte(), 0x00), + expectedParsingResult = true, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.LESS_THAN_OR_EQUAL_TO, + expectedFilter = Filter.SEQUENCE_NUMBER, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = 255, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet16 + * Composing packet - report records - between A and B + */ + racpTestVectors[16] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x04, 0x01, 0x01, 0x00, 0xFE.toByte(), 0x00), + expectedParsingResult = true, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.WITHIN_RANGE_OF_INCLUSIVE, + expectedFilter = Filter.SEQUENCE_NUMBER, + expectedMinimumSequenceNumber = 1, + expectedMaximumSequenceNumber = 254, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet17 + * Composing packet - report records - first record + */ + racpTestVectors[17] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x05), + expectedParsingResult = true, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.FIRST_RECORD, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet18 + * Composing packet - report records - last record + */ + racpTestVectors[18] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x06), + expectedParsingResult = true, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.LAST_RECORD, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + + ) + /** + + * Packet19 + * Composing packet - report records - error case, unsupported operator + */ + racpTestVectors[19] = RacpTestVector( + + testPacket = byteArrayOf(0x01, 0x00), + expectedParsingResult = false, + expectedOpcode = Opcode.REPORT_STORED_RECORDS, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + ) + + /** + * Packet20 + * Composing packet - report records - error case, unsupported opcode + */ + racpTestVectors[20] = RacpTestVector( + + testPacket = byteArrayOf(0x00, 0x00), + expectedParsingResult = false, + expectedOpcode = Opcode.RESERVED_FOR_FUTURE_USE, + expectedOperator = null, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = null, + expectedResponseCode = null + ) + + } @Test - fun testParsingSuccessIndicator(){ - Assert.assertEquals(expectedParsedResult1, RACP(mockBTCharacteristic(testPacket1), false).successfulParsing) - Assert.assertEquals(expectedParsedResult2, RACP(mockBTCharacteristic(testPacket2), false).successfulParsing) - Assert.assertEquals(expectedParsedResult3, RACP(mockBTCharacteristic(testPacket3), false).successfulParsing) - Assert.assertEquals(expectedParsedResult4, RACP(mockBTCharacteristic(testPacket4), false).successfulParsing) - Assert.assertEquals(expectedParsedResult5, RACP(mockBTCharacteristic(testPacket5), false).successfulParsing) - Assert.assertEquals(expectedParsedResult6, RACP(mockBTCharacteristic(testPacket6), false).successfulParsing) - Assert.assertEquals(expectedParsedResult7, RACP(mockBTCharacteristic(testPacket7), false).successfulParsing) - Assert.assertEquals(expectedParsedResult8, RACP(mockBTCharacteristic(testPacket8), false).successfulParsing) - Assert.assertEquals(expectedParsedResult9, RACP(mockBTCharacteristic(testPacket9), false).successfulParsing) - Assert.assertEquals(expectedParsedResult10, RACP(mockBTCharacteristic(testPacket10), false).successfulParsing) - Assert.assertEquals(expectedParsedResult11, RACP(mockBTCharacteristic(testPacket11), false).successfulParsing) - Assert.assertEquals(expectedParsedResult12, RACP(mockBTCharacteristic(testPacket12), false).successfulParsing) - Assert.assertEquals(expectedParsedResult13, RACP(mockBTCharacteristic(testPacket13), false).successfulParsing) - Assert.assertEquals(expectedParsedResult14, RACP(mockBTCharacteristic(testPacket14), false).successfulParsing) - Assert.assertEquals(expectedParsedResult15, RACP(mockBTCharacteristic(testPacket15), false).successfulParsing) - Assert.assertEquals(expectedParsedResult16, RACP(mockBTCharacteristic(testPacket16), false).successfulParsing) - Assert.assertEquals(expectedParsedResult17, RACP(mockBTCharacteristic(testPacket17), false).successfulParsing) - Assert.assertEquals(expectedParsedResult18, RACP(mockBTCharacteristic(testPacket18), false).successfulParsing) - Assert.assertEquals(expectedParsedResult19, RACP(mockBTCharacteristic(testPacket19), false).successfulParsing) - Assert.assertEquals(expectedParsedResult20, RACP(mockBTCharacteristic(testPacket20), false).successfulParsing) + fun testParsingSuccessIndicator() { + System.out.printf("testParsingSuccessIndicator\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedParsingResult, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).successfulParsing) + } + } + @Test + fun testParsingOpcode() { + System.out.printf("testParsingOpcode\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedOpcode, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).opcode) + } } @Test - fun testParsingOpcode(){ + fun testParsingOperator() { + System.out.printf("testParsingOperator\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedOperator, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).operator) + } + } + @Test + fun testParsingFilter() { + System.out.printf("testParsingFilter\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedFilter, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).filterType) + } + } + + @Test + fun testParsingMinimumSequenceNumber() { + System.out.printf("testMinimumSequenceNumber\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedMinimumSequenceNumber, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).minimumFilterValueSequenceNumber) + } + } + + @Test + fun testParsingMaximumSequenceNumber() { + System.out.printf("testMaximumSequenceNumber\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedMaximumSequenceNumber, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).maximumFilterValueSequenceNumber) + } + } + + @Test + fun testParsingMinimumUserFacingTime() { + System.out.printf("testMinimumUserFacingTime\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedMinimumUserFacingTime, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).minimumFilterValueUserFacingTime) + } + } + + @Test + fun testParsingMaximumUserFacingTime() { + System.out.printf("testMaximumUserFacingTime\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedMaximumUserFacingTime, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).maximumFilterValueUserFacingTime) + } + } + + @Test + fun testParsingRequestedOpcode() { + System.out.printf("testRequestedOpcode\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedRequestOpcode, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).requestOpcode) + } + } + + @Test + fun testParsingRequestedResponse() { + System.out.printf("testRequestedResponse\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedResponseCode, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).responseCode) + } + } + + @Test + fun testParsingNumberOfRecordResponse() { + System.out.printf("testNumberOfRecordResponse\n") + for (testVector in racpTestVectors){ + System.out.printf("testing racpTestVector ${testVector.key}\n") + Assert.assertEquals(testVector.value.expectedNumberOfRecord, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).numberOfRecordResponse) + } } } \ No newline at end of file From 218c899e451261dc0f247277b342b242c0314267 Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Thu, 20 Sep 2018 11:37:06 -0400 Subject: [PATCH 09/11] add in RACP support --- .../GlucoseMeasurementCharacteristic.kt | 7 +- .../PnPIdCharacteristic.kt | 1 - .../compoundcharacteristic/RACP.kt | 66 +++++-- .../SystemIdCharacteristic.kt | 1 - .../common/BaseCharacteristic.kt | 30 ++-- .../jdrfandroidbleparser/BaseTest.kt | 165 +++++++++++++++--- .../compoundcharacteristic/RACPTest.kt | 58 ++++-- 7 files changed, 261 insertions(+), 67 deletions(-) diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt index 544b968..b754ecb 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/GlucoseMeasurementCharacteristic.kt @@ -1,14 +1,14 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Flags import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.SampleLocation import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.SensorStatusAnnunciation import org.ehealthinnovation.jdrfandroidbleparser.bgm.encodedvalue.bgmmeasurement.Type -import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime +import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.Units +import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import java.util.* /** @@ -80,8 +80,7 @@ class GlucoseMeasurementCharacteristic(characteristic: BluetoothGattCharacterist sampleLocation = SampleLocation.fromKey((tempIntHolder and 0xF0) shr 4) if (it.contains(Flags.GLUCOSE_CONCENTRATION_UNITS)) { unit = Units.MOLE_PER_LITRE - } - else { + } else { unit = Units.KILOGRAM_PER_LITRE } } diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt index e8dbced..dd9d526 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/PnPIdCharacteristic.kt @@ -5,7 +5,6 @@ import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.dis.pnpid.VendorId import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.dis.pnpid.VendorId.Companion.fromVendorId -import kotlin.jvm.java /** * The PnP_ID characteristic is a set of values that used to create a device ID value that is diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt index 6b4a7c6..cacd73e 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt @@ -1,6 +1,5 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic -import android.bluetooth.BluetoothGatt import android.bluetooth.BluetoothGattCharacteristic import android.util.Log import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic @@ -11,40 +10,67 @@ import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Opcode import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Operator import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.ResponseCode import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime -import kotlin.math.log + +/** + * This control point is used with a service to provide basic management functionality for the + * Glucose Sensor patient record database. This enables functions including counting records, + * transmitting records and clearing records based on filter criterion. The filter criterion in + * the Operand field is defined by the service that references this characteristic as is the format + * of a record (which may be comprised of one or more characteristics) and the sequence of + * transferred records. + */ class RACP : BaseCharacteristic, Composable { override val tag: String = RACP::class.java.canonicalName - /**Constructor for parsing mode*/ - constructor(c: BluetoothGattCharacteristic, hasCrc: Boolean = false) : - super(c, GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc) { + constructor(c: BluetoothGattCharacteristic, hasCrc: Boolean = false, isComposing: Boolean = false) : + super(c, GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc, isComposing) { this.hasCrc = hasCrc } - /** Constructor for composing mode*/ - constructor(hasCrc: Boolean) : - super(GattCharacteristic.RECORD_ACCESS_CONTROL_POINT.assigned, hasCrc) { - this.hasCrc = hasCrc - } + /** + * Op Code specifying the operation + */ var opcode: Opcode? = null + + /** + * [operator] is a modifier to the operand. For example, [Operator.LAST_RECORD], + * [Operator.LESS_THAN_OR_EQUAL_TO] + */ var operator: Operator? = null + + /** Since the value of the Operand is defined per service, when the RACP is used with the + * Glucose Service, a Filter Type field is defined to enable the flexibility to filter based + * on different criteria (i.e., Sequence Number or optionally User Facing Time). + */ var filterType: Filter? = null /** - * The following variables stores the possible variables from parsing + * The following variables stores the possible fields which constitute operands. */ var minimumFilterValueSequenceNumber: Int? = null var maximumFilterValueSequenceNumber: Int? = null var minimumFilterValueUserFacingTime: BluetoothDateTime? = null var maximumFilterValueUserFacingTime: BluetoothDateTime? = null + + /** + * When the Report Number of Stored Records Op Code is written to the Record Access Control + * Point, the Server shall calculate and respond with a record count in UINT16 format based on + * filter criteria, Operator and Operand values. + */ var numberOfRecordResponse: Int? = null var requestOpcode: Opcode? = null var responseCode: ResponseCode? = null + /** + * Indicate whether the packet requires CRC + */ var hasCrc: Boolean + /** + * Main entry point for parsing a [BluetoothGattCharacteristic] + */ override fun parse(c: BluetoothGattCharacteristic): Boolean { var errorFreeParsing = false opcode = Opcode.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)) @@ -94,6 +120,9 @@ class RACP : BaseCharacteristic, Composable { } + /** + * Helper function to deserialize the generic operand portion of the packet + */ private fun parseGenericOperand(c: BluetoothGattCharacteristic) { when (operator) { null -> throw NullPointerException("operator is null") @@ -146,6 +175,9 @@ class RACP : BaseCharacteristic, Composable { } + /** + * A helper function for deserializing [BluetoothDateTime] + */ private fun parseBluetoothDateTime(c: BluetoothGattCharacteristic): BluetoothDateTime { return BluetoothDateTime( _year = getNextIntValue(c, getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16)), @@ -157,6 +189,12 @@ class RACP : BaseCharacteristic, Composable { ) } + /** + * Serialize the current [RACP] into a [ByteArray], it can be loaded up onto a communication to + * write to remote device + * @param hasCrc if the characteristics need CRC + * @return the [ByteArray] of the resulting composition + */ override fun composeCharacteristic(hasCrc: Boolean): ByteArray { opcode?.run { when (this) { @@ -193,6 +231,9 @@ class RACP : BaseCharacteristic, Composable { return rawData } + /** + * A helper function to compose the parameter portion of the packet + */ private fun composeQueryParameters() { operator?.run { when (this) { @@ -281,6 +322,9 @@ class RACP : BaseCharacteristic, Composable { } + /** + * A helper function to serialize [BluetoothDateTime] + */ private fun putBluetoothDateTime(input: BluetoothDateTime) { putIntValue(input._year, BluetoothGattCharacteristic.FORMAT_UINT16) putIntValue(input._month, BluetoothGattCharacteristic.FORMAT_UINT8) diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt index e3c2b02..7cad83c 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/SystemIdCharacteristic.kt @@ -3,7 +3,6 @@ package org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundch import android.bluetooth.BluetoothGattCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic -import kotlin.jvm.java /** * The SYSTEM ID characteristic consists of a structure with two fields. The first field are the diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt index 3243fcb..fbe0148 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt @@ -23,24 +23,25 @@ abstract class BaseCharacteristic(val uuid: Int) { * The default value for CRC check is false. There are some characteristics that requires a * first pass of parsing to know if CRC is present, and a second pass to parse the content with * the [hasCrc] flag set correctly. + * + * */ - constructor(characteristic: BluetoothGattCharacteristic?, uuid: Int, hasCrc: Boolean = false): this(uuid) { - this.characteristic = characteristic - characteristic?.let { - rawData = it.value ?: ByteArray(0) - this.successfulParsing = tryParse(it, hasCrc) + constructor(characteristic: BluetoothGattCharacteristic?, uuid: Int, hasCrc: Boolean = false, isComposing: Boolean = false): this(uuid) { + if(!isComposing) { + this.characteristic = characteristic + characteristic?.let { + rawData = it.value ?: ByteArray(0) + this.successfulParsing = tryParse(it, hasCrc) + } + }else{ + characteristic?.let { + this.composingcharacteristic = it } + if(characteristic == null){ + this.composingcharacteristic = BluetoothGattCharacteristic(UUID.randomUUID(), BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE) + } } } - /** - * Use this constructor when a characteristic is created to compose/serialize a bluetooth object. - */ - constructor(uuid: Int, hasCrc: Boolean = false): this(uuid) { - this.composingcharacteristic = BluetoothGattCharacteristic(UUID.randomUUID(), - BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, - BluetoothGattCharacteristic.PERMISSION_WRITE) - } - open val tag = BaseCharacteristic::class.java.canonicalName as String val nullValueException = "Null characteristic interpretation, aborting parsing." var rawData: ByteArray = ByteArray(0) @@ -214,4 +215,5 @@ abstract class BaseCharacteristic(val uuid: Int) { } + } diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt index e456c5c..0e244ec 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/BaseTest.kt @@ -19,14 +19,22 @@ import kotlin.jvm.java open class BaseTest { - private lateinit var payload: ByteArray + private lateinit var testPayload: ByteArray + private var mockPayload: ByteArray = ByteArray(0) private lateinit var mockBTCharacteristic: BluetoothGattCharacteristic private lateinit var stringByteArray: ByteArray private lateinit var testString: String private fun any(type: Class): T = Mockito.any(type) - protected fun mockBTCharacteristic(payload: ByteArray): BluetoothGattCharacteristic { + + protected fun mockBTCharacteristic(payload2: ByteArray): BluetoothGattCharacteristic { + if(payload2.isNotEmpty()){ + mockPayload = payload2 + }else{ + mockPayload = ByteArray(0) + } + return mock { on { getIntValue(any(Int::class.java), any(Int::class.java)) } doAnswer { val formatType: Int = it.getArgument(0) @@ -37,10 +45,10 @@ open class BaseTest { FORMAT_SINT8, FORMAT_UINT8, FORMAT_SINT16, FORMAT_UINT16 -> { val offset: Int = it.getArgument(1) FormatType.fromType(formatType)?.let { - if( payload.size <= offset+it.length()-1){ + if( mockPayload.size <= offset+it.length()-1){ throw IllegalArgumentException("Trying to access non-existing byte") } - val reversedArray = payload.sliceArray(offset..(offset + (it.length() - 1))) + val reversedArray = mockPayload.sliceArray(offset..(offset + (it.length() - 1))) if (it.signed) { unsignedToSigned(unsignedBytesToInt(reversedArray), reversedArray.size * 8) } else { @@ -59,7 +67,7 @@ open class BaseTest { FORMAT_FLOAT, FORMAT_SFLOAT -> { val offset: Int = it.getArgument(1) FormatType.fromType(formatType)?.let { - val reversedArray = payload.sliceArray(offset..(offset + (it.length() - 1))) + val reversedArray = mockPayload.sliceArray(offset..(offset + (it.length() - 1))) when (it) { FORMAT_FLOAT -> bytesToFloat(reversedArray[0], reversedArray[1], reversedArray[2], reversedArray[3]) FORMAT_SFLOAT -> bytesToFloat(reversedArray[0], reversedArray[1]) @@ -74,35 +82,58 @@ open class BaseTest { } on { getStringValue(any(Int::class.java)) } doAnswer { val offset: Int = it.getArgument(0) - payload.sliceArray(offset..(offset + (payload.size - 1))).reversedArray().toString(Charset.defaultCharset()) + mockPayload.sliceArray(offset..(offset + (mockPayload.size - 1))).reversedArray().toString(Charset.defaultCharset()) + } + on { value } doAnswer {mockPayload} + on {setValue(any(Int::class.java), any(Int::class.java), any(Int::class.java))} doAnswer { + val value: Int = it.getArgument(0) + val formatType : Int = it.getArgument(1) + val offset: Int = it.getArgument(2) + + when (FormatType.fromType(formatType)) { + FORMAT_UINT8, FORMAT_UINT16-> { + setPayloadValueInt(value, formatType, offset) + } + else->{ + throw IllegalArgumentException("Unknown type") + } + } } - on { value } doAnswer {payload} } } @Before fun setUp() { + } + + @Test + fun testMockUINT8() { /* * Data is little endian formatted. So the LSO (least significant octet is loaded in first, * followed by the second least significant octet, and so on. * * In this case, we want the payload to be 0x0123456789ABCDEF */ - payload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), + testPayload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), 0x89.toByte(), 0x67.toByte(), 0x45.toByte(), 0x23.toByte(), 0x01.toByte()) - mockBTCharacteristic = mockBTCharacteristic(payload) - } - - @Test - fun testMockUINT8() { - for ((index, value) in payload.withIndex()) { + mockBTCharacteristic = mockBTCharacteristic(testPayload) + for ((index, value) in testPayload.withIndex()) { Assert.assertEquals(String.format("%02X", value).toInt(radix = 16), mockBTCharacteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, index)) } } @Test fun testMockSINT8() { - for ((index, value) in payload.withIndex()) { + /* + * Data is little endian formatted. So the LSO (least significant octet is loaded in first, + * followed by the second least significant octet, and so on. + * + * In this case, we want the payload to be 0x0123456789ABCDEF + */ + testPayload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), + 0x89.toByte(), 0x67.toByte(), 0x45.toByte(), 0x23.toByte(), 0x01.toByte()) + mockBTCharacteristic = mockBTCharacteristic(testPayload) + for ((index, value) in testPayload.withIndex()) { Assert.assertEquals(unsignedToSigned(String.format("%02X", value).toInt(radix = 16), FORMAT_SINT8.bits()), mockBTCharacteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT8, index)) } @@ -110,9 +141,18 @@ open class BaseTest { @Test fun testMockUINT16() { + /* + * Data is little endian formatted. So the LSO (least significant octet is loaded in first, + * followed by the second least significant octet, and so on. + * + * In this case, we want the payload to be 0x0123456789ABCDEF + */ + testPayload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), + 0x89.toByte(), 0x67.toByte(), 0x45.toByte(), 0x23.toByte(), 0x01.toByte()) + mockBTCharacteristic = mockBTCharacteristic(testPayload) var index = 0 - while (index < payload.size) { - Assert.assertEquals(payload.sliceArray(index..(index + FORMAT_UINT16.length() - 1)).reversedArray().toHex()!!.toInt(radix = 16), + while (index < testPayload.size) { + Assert.assertEquals(testPayload.sliceArray(index..(index + FORMAT_UINT16.length() - 1)).reversedArray().toHex()!!.toInt(radix = 16), mockBTCharacteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT16, index)) index += FORMAT_UINT16.length() } @@ -120,9 +160,18 @@ open class BaseTest { @Test fun testMockSINT16() { + /* + * Data is little endian formatted. So the LSO (least significant octet is loaded in first, + * followed by the second least significant octet, and so on. + * + * In this case, we want the payload to be 0x0123456789ABCDEF + */ + testPayload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), + 0x89.toByte(), 0x67.toByte(), 0x45.toByte(), 0x23.toByte(), 0x01.toByte()) + mockBTCharacteristic = mockBTCharacteristic(testPayload) var index = 0 - while (index < payload.size) { - Assert.assertEquals(unsignedToSigned(payload.sliceArray(index..(index + FORMAT_SINT16.length() - 1)).reversedArray().toHex()!!.toInt(radix = 16), FORMAT_SINT16.bits()), + while (index < testPayload.size) { + Assert.assertEquals(unsignedToSigned(testPayload.sliceArray(index..(index + FORMAT_SINT16.length() - 1)).reversedArray().toHex()!!.toInt(radix = 16), FORMAT_SINT16.bits()), mockBTCharacteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, index)) index += FORMAT_UINT16.length() } @@ -130,9 +179,18 @@ open class BaseTest { @Test fun testMockFLOAT() { + /* + * Data is little endian formatted. So the LSO (least significant octet is loaded in first, + * followed by the second least significant octet, and so on. + * + * In this case, we want the payload to be 0x0123456789ABCDEF + */ + testPayload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), + 0x89.toByte(), 0x67.toByte(), 0x45.toByte(), 0x23.toByte(), 0x01.toByte()) + mockBTCharacteristic = mockBTCharacteristic(testPayload) var index = 0 - while (index < payload.size) { - val sliced = payload.sliceArray(index..(index + FORMAT_FLOAT.length() - 1)) + while (index < testPayload.size) { + val sliced = testPayload.sliceArray(index..(index + FORMAT_FLOAT.length() - 1)) Assert.assertEquals(bytesToFloat(sliced[0], sliced[1], sliced[2], sliced[3]), mockBTCharacteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_FLOAT, index)) index += FORMAT_FLOAT.length() @@ -141,9 +199,18 @@ open class BaseTest { @Test fun testMockSFLOAT() { + /* + * Data is little endian formatted. So the LSO (least significant octet is loaded in first, + * followed by the second least significant octet, and so on. + * + * In this case, we want the payload to be 0x0123456789ABCDEF + */ + testPayload = byteArrayOf(0xef.toByte(), 0xcd.toByte(), 0xab.toByte(), + 0x89.toByte(), 0x67.toByte(), 0x45.toByte(), 0x23.toByte(), 0x01.toByte()) + mockBTCharacteristic = mockBTCharacteristic(testPayload) var index = 0 - while (index < payload.size) { - val sliced = payload.sliceArray(index..(index + FORMAT_SFLOAT.length() - 1)) + while (index < testPayload.size) { + val sliced = testPayload.sliceArray(index..(index + FORMAT_SFLOAT.length() - 1)) Assert.assertEquals(bytesToFloat(sliced[0], sliced[1]), mockBTCharacteristic.getFloatValue(BluetoothGattCharacteristic.FORMAT_SFLOAT, index)) index += FORMAT_SFLOAT.length() @@ -160,6 +227,26 @@ open class BaseTest { Assert.assertEquals(testString, mockBTCharacteristic.getStringValue(0)) } + @Test + fun testSettingUint8(){ + mockPayload = ByteArray(1) + val expectedPayload: ByteArray = byteArrayOf(0x69) + val valueToSet:Byte = 0x69 + mockBTCharacteristic = mockBTCharacteristic(ByteArray(0)) + mockBTCharacteristic.setValue(valueToSet.toInt(), FORMAT_UINT8.formatType, 0) + Assert.assertTrue(mockPayload.contentEquals(expectedPayload)) + } + + @Test + fun testSettingUint16(){ + mockPayload = ByteArray(2) + val expectedPayload: ByteArray = byteArrayOf(0x69,0x38) + val valueToSet:Int = 0x3869 + mockBTCharacteristic = mockBTCharacteristic(ByteArray(0)) + mockBTCharacteristic.setValue(valueToSet, FORMAT_UINT16.formatType, 0) + Assert.assertTrue(mockPayload.contentEquals(expectedPayload)) + } + companion object { /** @@ -239,4 +326,36 @@ open class BaseTest { fun ok(): String { return Base64.getDecoder().decode(OK).toString(Charsets.UTF_8) } + + fun setPayloadValueInt(value:Int, formatType:Int, offset:Int):Boolean{ + + val newArraySize = getFormatTypeSize(formatType)+offset + if(newArraySize>mockPayload.size){ + mockPayload = mockPayload.copyOf(newArraySize) + } + when(FormatType.fromType(formatType)){ + FORMAT_UINT8->{ + mockPayload.set(offset, value.toByte()) + return true + } + FORMAT_UINT16->{ + mockPayload.set(offset, value.toByte()) + mockPayload.set(offset+1, (value shr 8).toByte()) + return true + } + else ->{ + throw IllegalArgumentException("Currently we does not support this integer type") + } + } + return false + } + + /** + * Get the size of format type + */ + private fun getFormatTypeSize(formatType:Int):Int{ + return formatType and 0x0f + } + + } \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt index 45a54e0..a2f10fd 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt @@ -7,9 +7,7 @@ import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.Operator import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.bgm.racp.ResponseCode import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime import org.junit.Assert -import org.junit.Assert.* import org.junit.Test -import java.util.logging.LogRecord class RACPTest : BaseTest() { /** @@ -451,7 +449,7 @@ class RACPTest : BaseTest() { @Test fun testParsingSuccessIndicator() { System.out.printf("testParsingSuccessIndicator\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedParsingResult, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).successfulParsing) } @@ -460,7 +458,7 @@ class RACPTest : BaseTest() { @Test fun testParsingOpcode() { System.out.printf("testParsingOpcode\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedOpcode, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).opcode) } @@ -469,7 +467,7 @@ class RACPTest : BaseTest() { @Test fun testParsingOperator() { System.out.printf("testParsingOperator\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedOperator, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).operator) } @@ -478,7 +476,7 @@ class RACPTest : BaseTest() { @Test fun testParsingFilter() { System.out.printf("testParsingFilter\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedFilter, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).filterType) } @@ -487,7 +485,7 @@ class RACPTest : BaseTest() { @Test fun testParsingMinimumSequenceNumber() { System.out.printf("testMinimumSequenceNumber\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedMinimumSequenceNumber, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).minimumFilterValueSequenceNumber) } @@ -496,7 +494,7 @@ class RACPTest : BaseTest() { @Test fun testParsingMaximumSequenceNumber() { System.out.printf("testMaximumSequenceNumber\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedMaximumSequenceNumber, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).maximumFilterValueSequenceNumber) } @@ -505,7 +503,7 @@ class RACPTest : BaseTest() { @Test fun testParsingMinimumUserFacingTime() { System.out.printf("testMinimumUserFacingTime\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedMinimumUserFacingTime, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).minimumFilterValueUserFacingTime) } @@ -514,7 +512,7 @@ class RACPTest : BaseTest() { @Test fun testParsingMaximumUserFacingTime() { System.out.printf("testMaximumUserFacingTime\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedMaximumUserFacingTime, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).maximumFilterValueUserFacingTime) } @@ -523,7 +521,7 @@ class RACPTest : BaseTest() { @Test fun testParsingRequestedOpcode() { System.out.printf("testRequestedOpcode\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedRequestOpcode, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).requestOpcode) } @@ -532,7 +530,7 @@ class RACPTest : BaseTest() { @Test fun testParsingRequestedResponse() { System.out.printf("testRequestedResponse\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedResponseCode, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).responseCode) } @@ -541,9 +539,43 @@ class RACPTest : BaseTest() { @Test fun testParsingNumberOfRecordResponse() { System.out.printf("testNumberOfRecordResponse\n") - for (testVector in racpTestVectors){ + for (testVector in racpTestVectors) { System.out.printf("testing racpTestVector ${testVector.key}\n") Assert.assertEquals(testVector.value.expectedNumberOfRecord, RACP(mockBTCharacteristic(testVector.value.testPacket), testVector.value.hasCrc).numberOfRecordResponse) } } + + @Test + fun testComposingRacp() { + System.out.printf("testComposingRacp\n") + var testRacp: RACP + var successCount = 0 + var skipCount = 0 + + for (testVector in racpTestVectors) { + System.out.printf("testing racpTestVector ${testVector.key}\n") + if (testVector.value.expectedParsingResult == false) { + System.out.printf("This case is expected to failed in parsing, so cant be composed backwards.\n") + skipCount++ + continue + } + testRacp = RACP(mockBTCharacteristic(ByteArray(0)), testVector.value.hasCrc, isComposing = true) + testRacp.operator = testVector.value.expectedOperator + testRacp.opcode = testVector.value.expectedOpcode + testRacp.filterType = testVector.value.expectedFilter + testRacp.minimumFilterValueUserFacingTime = testVector.value.expectedMinimumUserFacingTime + testRacp.minimumFilterValueSequenceNumber = testVector.value.expectedMinimumSequenceNumber + testRacp.maximumFilterValueUserFacingTime = testVector.value.expectedMaximumUserFacingTime + testRacp.maximumFilterValueSequenceNumber = testVector.value.expectedMaximumSequenceNumber + testRacp.requestOpcode = testVector.value.expectedRequestOpcode + testRacp.responseCode = testVector.value.expectedResponseCode + testRacp.hasCrc = testVector.value.hasCrc + testRacp.numberOfRecordResponse = testVector.value.expectedNumberOfRecord + val composedPacket = testRacp.composeCharacteristic(testVector.value.hasCrc) + System.out.printf("composed: " + composedPacket.contentToString() + "\n") + System.out.printf("test packet: " + testVector.value.testPacket.contentToString() + "\n") + Assert.assertTrue(testVector.value.testPacket.contentEquals(composedPacket)) + } + System.out.printf("Total cases: ${racpTestVectors.size} Cases skipped: $skipCount\n") + } } \ No newline at end of file From 1d6dde59c5c44971b4b6fa0bcdee10426463c8d4 Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Thu, 20 Sep 2018 11:41:02 -0400 Subject: [PATCH 10/11] remove cgm and ids module --- .../CgmFeatureCharacteristic.kt | 76 ------ .../CgmMeasurementCharacteristic.kt | 126 --------- .../cgm/characteristic/CgmSessionRunTime.kt | 31 --- .../cgm/characteristic/CgmSessionStartTime.kt | 56 ---- .../characteristic/CgmStatusCharacteristic.kt | 51 ---- .../cgm/cgmcp/CalibrationStatus.kt | 25 -- .../encodedvalue/cgm/cgmcp/Opcode.kt | 39 --- .../encodedvalue/cgm/cgmcp/ResponseCode.kt | 15 -- .../cgm/feature/CgmSampleLocation.kt | 17 -- .../encodedvalue/cgm/feature/CgmType.kt | 22 -- .../encodedvalue/cgm/feature/Flags.kt | 38 --- .../encodedvalue/cgm/measurement/Flags.kt | 26 -- .../measurement/SensorStatusAnnunciation.kt | 41 --- .../encodedvalue/cgm/racp/Filter.kt | 11 - .../encodedvalue/cgm/racp/Opcode.kt | 18 -- .../encodedvalue/cgm/racp/Operator.kt | 17 -- .../encodedvalue/cgm/racp/ResponseCode.kt | 20 -- .../cgm/sessionstarttime/DstOffset.kt | 14 - .../CgmFeatureCharacteristicTest.kt | 157 ----------- .../CgmMeasurementCharacteristicTest.kt | 245 ------------------ .../characteristic/CgmSessionRunTimeTest.kt | 52 ---- .../characteristic/CgmSessionStartTimeTest.kt | 141 ---------- .../CgmStatusCharacteristicTest.kt | 75 ------ .../encodedvalue/cgm/feature/FlagsTest.kt | 34 --- .../encodedvalue/cgm/measurement/FlagsTest.kt | 32 --- .../SensorStatusAnnunciationTest.kt | 31 --- 26 files changed, 1410 deletions(-) delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt delete mode 100644 jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt delete mode 100644 jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt deleted file mode 100644 index 3dfbf83..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristic.kt +++ /dev/null @@ -1,76 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmSampleLocation -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmType -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags -import java.lang.reflect.Type -import java.util.* - -/** - * The CGM Feature characteristic is used to describe the supported features of the Server. - * When read, the CGM Feature characteristic returns a value that is used by a Client to determine - * the supported features of the Server. Additionally, the CGM Feature contains the CGM Type-Sample - * Location field: This field is the combination of the Type field and the Sample Location field and - * is static for a CGM sensor. - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_feature.xml - */ -class CgmFeatureCharacteristic(characteristic: BluetoothGattCharacteristic?) :BaseCharacteristic(characteristic, GattCharacteristic.CGM_FEATURE.assigned, false) { - - override val tag = CgmFeatureCharacteristic::class.java.canonicalName as String - - /** - * The set of feature flags contained in the binary packet. - * Use [isFeatureSupported] to query if a device supports a certain feature. - */ - private var flags: EnumSet? = null - - /** - * The location and type of the cgm sample. - */ - var cgmType : CgmType? = null - var cgmSampleLocation : CgmSampleLocation? = null - - /** - * The parsing of this characteristic consists of two passes. The pass determine if CRC is present - * The second pass verify that the CRC is right if it is present. - */ - override fun parse(c: BluetoothGattCharacteristic): Boolean { - var errorFreeParse = false - var flagValue : Int = 0 - //The feature flag consist of 24 bit, which is not a standard data field length. - flagValue = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) - flagValue += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 8 - flagValue += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 16 - Flags.parseFlags(flagValue).let { - if(it.contains(Flags.E2E_CRC_SUPPORTED)){ - if(!testCrc(rawData)){ - throw Exception("CRC Fails") - } - }else{ - flags = it - } - } - - val temporalSampleTypeHolder = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) - cgmType = CgmType.fromKey(temporalSampleTypeHolder and 0x0F) - cgmSampleLocation = CgmSampleLocation.fromKey((temporalSampleTypeHolder and 0xF0) shr 4) - - errorFreeParse = true - return errorFreeParse - } - - /** - * Query if a feature is supported as described in the packet - * @param queryFeature the glucose meter feature to be queried - * @return true if the [queryFeature] is supported, false otherwise - * This function returns false even when the packet is not parsed successfully. - * Before using this value, make sure [successfulParsing] is true. - */ - fun isFeatureSupported(queryFeature: Flags): Boolean { - return (flags?.contains(queryFeature) == true) - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt deleted file mode 100644 index 959ee6b..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristic.kt +++ /dev/null @@ -1,126 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.Flags -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation -import java.util.* - -/** - * The CGM Measurement characteristic is a variable length structure containing one or more CGM - * Measurement records, each comprising a Size field, a Flags Field, a Glucose Concentration field, - * a Time Offset field, a Sensor Status Annunciation field (optional), a CGM Trend Information Field - * (optional), a CGM Quality Field (optional), and an E2E-CRC Field (mandatory if this feature is - * supported). - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_measurement.xml - */ -class CgmMeasurementCharacteristic(c :BluetoothGattCharacteristic, hasCrc : Boolean = false) : BaseCharacteristic(c, GattCharacteristic.CGM_MEASUREMENT.assigned, hasCrc) { - override val tag: String = CgmMeasurementCharacteristic::class.java.canonicalName - - /** - * The Size Field represents the size of the CGM Measurement record in an UINT 8. The minimum - * size is 6 octets and is enlarged if more octets are indicated by the Flags Field (Sensor - * Status Annunciation Field, CGM Trend Information Field and CGM Quality Field) and the - * optional E2E-CRC Field. The Size Field itself is included in the length calculation. - */ - var size: Int? = null - - /** - * The Flags Field indicates the presence of optional fields and the Sensor Status Annunciation - * Field in the CGM Measurement record. - */ - var flags: EnumSet? = null - - /** - * The CGM Glucose Concentration field contains the CGM glucose concentration in a SFLOAT data - * type. The SFLOAT-Type is a 16-bit word comprising a signed 4-bit integer exponent followed - * by a signed 12-bit Mantissa. - * - * Note that the unit of the CGM Glucose concentration is in mg/dL only. - */ - var cgmGlucoseConcentration: Float? = null - - /** - * The Time Offset field is used in conjunction with the CGM Session Start Time to represent - * the time difference of the separate CGM measurements in relation to the session start time. - * Note that this Time Offset field serves also as a sequence number for the client, allowing - * the client to identify gaps / missing results in the data stream. - * - * The Time Offset field is defined as a UINT 16 representing the number of minutes the user-facing - * time differs from the Session Start Time. The default initial value shall be 0x0000. The Time - * Offset field shall be incremented by the measurement interval with each CGM measurement record - */ - var timeOffset: Int? = null - - /** - * The Sensor Status Annunciation field may form part of the CGM Measurement record. This field - * has a variable length between 1 and 3 octets. If one or more bits in the Sensor Status - * Annunciation field are set to “1” the Sensor Status Annunciation field shall form part of - * every CGM Measurement Record to which it applies. - */ - var sensorStatusAnnunciation: EnumSet? = null - - /** - * If the device supports CGM Trend information (CGM-Trend-Information Supported bit is set in - * CGM Features), this field may be included in the record. The presence of this field in a - * record is indicated by the Flags Field. This field contains the CGM Trend information in - * (mg/dL)/min as an SFLOAT data type. - */ - var cgmTrendInformation: Float? = null - - /** - * If the device supports CGM Quality (CGM-Quality Supported bit is set in CGM Features), this - * field may be included in the CGM measurement record. The presence of this field in a CGM - * measurement record is indicated by the Flags Field. This field contains the CGM Quality - * information in % as an SFLOAT data type - */ - var cgmQuality: Float? = null - - /** - * If the device supports E2E-safety (E2E-CRC Supported bit is set in CGM Features), the - * measurement shall be protected by a CRC calculated over all fields - */ - val hasCrc = hasCrc - - - - override fun parse(c: BluetoothGattCharacteristic): Boolean { - var errorFreeParsing = false - var sizeCounter = 0 - size = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) - - Flags.parseFlags(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8)).let { - flags = it - cgmGlucoseConcentration = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_SFLOAT) - timeOffset = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) - var annunciationFlagHolder: Int = 0 - if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_STATUS_OCTET_PRESENT)) { - annunciationFlagHolder = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) - } - - if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT)) { - annunciationFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 8 - } - - if (it.contains(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT)) { - annunciationFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 16 - } - - sensorStatusAnnunciation = SensorStatusAnnunciation.parseFlags(annunciationFlagHolder) - - - if (it.contains(Flags.CGM_TREND_INFORMATION_PRESENT)) { - cgmTrendInformation = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_SFLOAT) - } - - if (it.contains(Flags.CGM_QUALITY_PRESENT)) { - cgmQuality = getNextFloatValue(c, BluetoothGattCharacteristic.FORMAT_SFLOAT) - } - - } - - errorFreeParsing = let{ if(hasCrc) {2} else {0}} + offset == size - return errorFreeParsing - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt deleted file mode 100644 index f6765a9..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTime.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic - -/** - * The CGM Session Run Time shall define the expected run time of the CGM session. Typically CGM - * Sensors have a limited run time which they are approved for. However, this characteristic should - * enable a prediction of the run time depending on physiological effects in future devices. - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_session_run_time.xml - */ -class CgmSessionRunTime(characteristic: BluetoothGattCharacteristic?, hasCrc: Boolean) : BaseCharacteristic(characteristic, GattCharacteristic.CGM_SESSION_RUN_TIME.assigned, hasCrc) { - - override val tag = CgmSessionRunTime::class.java.canonicalName as String - - /** - * The CGM Session Run Time is a relative time, based on the CGM Session Start Time. - * The unit is in hour - */ - var sessionRunTime : Int? = null - - override fun parse(c: BluetoothGattCharacteristic): Boolean { - var errorFreeParse = false - sessionRunTime = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) - errorFreeParse = sessionRunTime != null - return errorFreeParse - } - - -} diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt deleted file mode 100644 index 9acbfdd..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTime.kt +++ /dev/null @@ -1,56 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.sessionstarttime.DstOffset -import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime - -/** - * The Session Start Time Field defines the time of the initial CGM measurement. The absolute time - * of the first CGM measurement taken is not known, so the Server stores each CGM measurement with - * a relative time stamp (Time Offset), starting with 0 for the first measurement (Session Start). - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_session_start_time.xml - */ -class CgmSessionStartTime(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : BaseCharacteristic(c, GattCharacteristic.CGM_SESSION_START_TIME.assigned, hasCrc) { - - override val tag = CgmSessionStartTime::class.java.canonicalName as String - - /** - * Upon initial connection, if the device supports an automatic start of the CGM session (e.g., - * at power on), or after the Start Session procedure, the Client shall write its current time - * to this characteristic and the Server shall calculate and store the Session Start Time using - * the time of the client and its own current relative time value. - */ - var sessionStartTime : BluetoothDateTime? = null - - /** - * To know an absolute Time, it is necessary to know the Time Zone to which the Session Start - * Time is related to. If unknown, the field shall be set to a value of -128. See definition of - * Time Zone Characteristic in [3]. - */ - var timeZone : Int? = null - - /** - * To know an absolute Time, it is also necessary to know the Daylight Saving setting. - * If unknown, the field shall be set to a value of 255. - */ - var dstOffset : DstOffset? = null - - - override fun parse(c: BluetoothGattCharacteristic): Boolean { - var errorFreeParse = false - sessionStartTime = BluetoothDateTime( - _year = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16), - _month = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), - _day = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), - _hour = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), - _min = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8), - _sec = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) - ) - timeZone = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_SINT8) - dstOffset = DstOffset.fromKey(getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_SINT8)) - errorFreeParse = true - return errorFreeParse - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt deleted file mode 100644 index 768e8d5..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristic.kt +++ /dev/null @@ -1,51 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import android.bluetooth.BluetoothGattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.common.BaseCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation -import java.util.* - -/** - * The CGM Status allows the client to actively request the status from the CGM Sensor, particularly - * when the CGM measurement is not running and the status cannot be given in the measurement result - * in the Status Annunciation Field. - * https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.cgm_status.xml - */ -class CgmStatusCharacteristic(c : BluetoothGattCharacteristic, hasCrc : Boolean = false) : BaseCharacteristic(c, GattCharacteristic.CGM_STATUS.assigned, hasCrc){ - - - override val tag = CgmStatusCharacteristic::class.java.canonicalName as String - - /** - * The Time Offset Field specifies the actual relative time difference to the session start time. - */ - var timeOffset : Int? = null - - /** - * The structure of the CGM Status Field shall be identical to the structure of the Status - * Annunciation Field, as defined in the CGM Measurement Characteristic "Sensor Status - * Annunciation Field". It always consists of three octets regardless the value. - */ - var cgmStatus : EnumSet? = null - - - override fun parse(c: BluetoothGattCharacteristic): Boolean { - var errorFreeParse = false - timeOffset = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT16) - - //The structure for the status field is 24 bit, non-standard integer size - var statusFlagHolder : Int - statusFlagHolder = getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) - statusFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 8 - statusFlagHolder += getNextIntValue(c, BluetoothGattCharacteristic.FORMAT_UINT8) shl 16 - - cgmStatus = SensorStatusAnnunciation.parseFlags(statusFlagHolder) - - errorFreeParse = true - - return errorFreeParse - } - - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt deleted file mode 100644 index 16eb1a0..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/CalibrationStatus.kt +++ /dev/null @@ -1,25 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.cgmcp - -import java.util.* - -enum class CalibrationStatus constructor(val bit: Int) { - CALIBRATION_DATA_REJECTED(1 shl 0), - CALIBRATION_DATA_OUT_OF_RANGE(1 shl 1), - CALIBRATION_PROCESS_PENDING(1 shl 2); - - companion object { - /** - * Takes a passed in 8bit flag value and extracts the set mask values. Returns an - * [EnumSet]<[CalibrationStatus]> of set properties - */ - fun parseFlags(calibrationStatusFlag: Int): EnumSet { - val setFlags = EnumSet.noneOf(CalibrationStatus::class.java) - CalibrationStatus.values().forEach { - val flag = it.bit - if (flag and calibrationStatusFlag == flag) setFlags.add(it) - } - return setFlags - } - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt deleted file mode 100644 index b00bad5..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/Opcode.kt +++ /dev/null @@ -1,39 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.cgmcp - -enum class Opcode constructor(val key: Int) { - RESERVED_FOR_FUTURE_USE(0), - SET_CGM_COMMUNICATION_INTERVAL(1), - GET_CGM_COMMUNICATION_INTERVAL(2), - CGM_COMMUNICATION_INTERVAL_RESPONSE(3), - SET_GLUCOSE_CALIBRATION_VALUE(4), - GET_GLUCOSE_CALIBRATION_VALUE(5), - GLUCOSE_CALIBRATION_VALUE_RESPONSE(6), - SET_PATIENT_HIGH_ALERT_LEVEL(7), - GET_PATIENT_HIGH_ALERT_LEVEL(8), - PATIENT_HIGH_ALERT_LEVEL_RESPONSE(9), - SET_PATIENT_LOW_ALERT_LEVEL(10), - GET_PATIENT_LOW_ALERT_LEVEL(11), - PATIENT_LOW_ALERT_LEVEL_RESPONSE(12), - SET_HYPO_ALERT_LEVEL(13), - GET_HYPO_ALERT_LEVEL(14), - HYPO_ALERT_LEVEL_RESPONSE(15), - SET_HYPER_ALERT_LEVEL(16), - GET_HYPER_ALERT_LEVEL(17), - HYPER_ALERT_LEVEL_RESPONSE(18), - SET_RATE_OF_DECREASE_ALERT_LEVEL(19), - GET_RATE_OF_DECREASE_ALERT_LEVEL(20), - RATE_OF_DECREASE_ALERT_LEVEL_RESPONSE(21), - SET_RATE_OF_INCREASE_ALERT_LEVEL(22), - GET_RATE_OF_INCREASE_ALERT_LEVEL(23), - RATE_OF_INCREASE_ALERT_LEVEL_RESPONSE(24), - RESET_DEVICE_SPECIFIC_ALERT(25), - START_THE_SESSION(26), - STOP_THE_SESSION(27), - RESPONSE_CODE(28); - - companion object { - private val map = Opcode.values().associateBy(Opcode::key) - fun fromKey(type: Int) = map[type] - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt deleted file mode 100644 index 0058b40..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/cgmcp/ResponseCode.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.cgmcp - -enum class ResponseCode constructor(val key: Int) { - RESERVED_FOR_FUTURE_USE(0), - SUCCESS(1), - OP_CODE_NOT_SUPPORTED(2), - INVALID_OPERAND(3), - PROCEDURE_NOT_COMPLETED(4), - PARAMETER_OUT_OF_RANGE(5); - - companion object { - private val map = ResponseCode.values().associateBy (ResponseCode::key) - fun fromKey(key: Int) = map[key] - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt deleted file mode 100644 index 0b3996d..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmSampleLocation.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature - -enum class CgmSampleLocation constructor(val key: Int) { - - RESERVED_FOR_FUTURE_USE(0), - FINGER(1), - ALTERNATE_SITE_TEST(2), - EARLOBE(3), - CONTROL_SOLUTION(4), - SUBCUTANEOUS_TISSUE(5), - SAMPLE_LOCATION_VALUE_NOT_AVAILABLE(15); - - companion object { - private val map = CgmSampleLocation.values().associateBy(CgmSampleLocation::key) - fun fromKey(type: Int) = map[type] - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt deleted file mode 100644 index 79f66c3..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/CgmType.kt +++ /dev/null @@ -1,22 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature - -enum class CgmType constructor(val key: Int) { - - RESERVED_FOR_FUTURE_USE(0), - CAPILLARY_WHOLE_BLOOD(1), - CAPILLARY_PLASMA(2), - VENOUS_WHOLE_BLOOD(3), - VENOUS_PLASMA(4), - ARTERIAL_WHOLE_BLOOD(5), - ARTERIAL_PLASMA(6), - UNDETERMINED_WHOLE_BLOOD(7), - UNDETERMINED_PLASMA(8), - INTERSTITIAL_FLUID(9), - CONTROL_SOLUTION(10); - - - companion object { - private val map = CgmType.values().associateBy(CgmType::key) - fun fromKey(type: Int) = map[type] - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt deleted file mode 100644 index 831b9bf..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/Flags.kt +++ /dev/null @@ -1,38 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature - -import java.util.* - -enum class Flags constructor(val bit: Int) { - CALIBRATION_SUPPORTED(1 shl 0), - PATIENT_HIGH_LOW_ALERTS_SUPPORTED(1 shl 1), - HYPO_ALERTS_SUPPORTED(1 shl 2), - HYPER_ALERTS_SUPPORTED(1 shl 3), - RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED(1 shl 4), - DEVICE_SPECIFIC_ALERT_SUPPORTED(1 shl 5), - SENSOR_MALFUNCTION_DETECTION_SUPPORTED(1 shl 6), - SENSOR_TEMPERATURE_HIGH_LOW_DETECTION_SUPPORTED(1 shl 7), - SENSOR_RESULT_HIGH_LOW_DETECTION_SUPPORTED(1 shl 8), - LOW_BATTERY_DETECTION_SUPPORTED(1 shl 9), - SENSOR_TYPE_ERROR_DETECTION_SUPPORTED(1 shl 10), - GENERAL_DEVICE_FAULT_SUPPORTED(1 shl 11), - E2E_CRC_SUPPORTED(1 shl 12), - MULTIPLE_BOND_SUPPORTED(1 shl 13), - MULTIPLE_SESSIONS_SUPPORTED(1 shl 14), - CGM_TREND_INFORMATION_SUPPORTED(1 shl 15), - CGM_QUALITY_SUPPORTED(1 shl 16); - - companion object { - /** - * Takes a passed in 8bit flag value and extracts the set mask values. Returns an - * [EnumSet]<[Flags]> of set properties - */ - fun parseFlags(characteristicFlags: Int): EnumSet { - val setFlags = EnumSet.noneOf(Flags::class.java) - Flags.values().forEach { - val flag = it.bit - if(flag and characteristicFlags == flag) setFlags.add(it) - } - return setFlags - } - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt deleted file mode 100644 index 9d21f85..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/Flags.kt +++ /dev/null @@ -1,26 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement - -import java.util.* - -enum class Flags constructor(val bit: Int) { - CGM_TREND_INFORMATION_PRESENT(1 shl 0), - CGM_QUALITY_PRESENT(1 shl 1), - SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT(1 shl 5), - SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT(1 shl 6), - SENSOR_STATUS_ANNUNCIATION_FIELD_STATUS_OCTET_PRESENT(1 shl 7); - - companion object { - /** - * Takes a passed in 8bit flag value and extracts the set mask values. Returns an - * [EnumSet]<[Flags]> of set properties - */ - fun parseFlags(characteristicFlags: Int): EnumSet { - val setFlags = EnumSet.noneOf(Flags::class.java) - Flags.values().forEach { - val flag = it.bit - if(flag and characteristicFlags == flag) setFlags.add(it) - } - return setFlags - } - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt deleted file mode 100644 index ba6f4d8..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciation.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement - -import java.util.* - -enum class SensorStatusAnnunciation constructor(val bit: Int) { - SESSION_STOPPED(1 shl 0), - DEVICE_BATTERY_LOW(1 shl 1), - SENSOR_TYPE_INCORRECT_FOR_DEVICE(1 shl 2), - SENSOR_MALFUNCTION(1 shl 3), - DEVICE_SPECIFIC_ALERT(1 shl 4), - GENERAL_DEVICE_FAULT_HAS_OCCURRED_IN_THE_SENSOR(1 shl 5), - TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED(1 shl 8), - CALIBRATION_NOT_ALLOWED(1 shl 9), - CALIBRATION_RECOMMENDED(1 shl 10), - CALIBRATION_REQUIRED(1 shl 11), - SENSOR_TEMPERATURE_TOO_HIGH_FOR_VALID_RESULT_AT_TIME_OF_MEASUREMENT(1 shl 12), - SENSOR_TEMPERATURE_TOO_LOW_FOR_VALID_RESULT_AT_TIME_OF_MEASUREMENT(1 shl 13), - SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL(1 shl 16), - SENSOR_RESULT_HIGHER_THAN_THE_PATIENT_HIGH_LEVEL(1 shl 17), - SENSOR_RESULT_LOWER_THAN_THE_HYPO_LEVEL(1 shl 18), - SENSOR_RESULT_HIGHER_THAN_THE_HYPER_LEVEL(1 shl 19), - SENSOR_RATE_OF_DECREASE_EXCEEDED(1 shl 20), - SENSOR_RATE_OF_INCREASE_EXCEEDED(1 shl 21), - SENSOR_RESULT_LOWER_THAN_THE_DEVICE_CAN_PROCESS(1 shl 22), - SENSOR_RESULT_HIGHER_THAN_THE_DEVICE_CAN_PROCESS(1 shl 23); - - companion object { - /** - * Takes a passed in 8bit flag value and extracts the set mask values. Returns an - * [EnumSet]<[SensorStatusAnnunciation]> of set properties - */ - fun parseFlags(characteristicFlags: Int): EnumSet { - val setFlags = EnumSet.noneOf(SensorStatusAnnunciation::class.java) - SensorStatusAnnunciation.values().forEach { - val flag = it.bit - if(flag and characteristicFlags == flag) setFlags.add(it) - } - return setFlags - } - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt deleted file mode 100644 index 329f67e..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Filter.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp - -enum class Filter constructor(val key: Int) { - RESERVED_FOR_FUTURE_USE(0), - TIME_OFFSET(1); - - companion object { - private val map = Filter.values().associateBy(Filter::key) - fun fromKey(type: Int) = map[type] - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt deleted file mode 100644 index a718f69..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Opcode.kt +++ /dev/null @@ -1,18 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp - -enum class Opcode constructor(val key: Int) { - - RESERVED_FOR_FUTURE_USE(0), - REPORT_STORED_RECORDS(1), - DELETE_STORED_RECORDS(2), - ABORT_OPERATION(3), - REPORT_NUMBER_OF_STORED_RECORDS(4), - NUMBER_OF_STORED_RECORDS_RESPONSE(5), - RESPONSE_CODE(6); - - companion object { - private val map = Opcode.values().associateBy(Opcode::key) - fun fromKey(type: Int) = map[type] - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt deleted file mode 100644 index ea6198d..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/Operator.kt +++ /dev/null @@ -1,17 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp - -enum class Operator constructor(val key: Int) { - NULL(0), - ALL_RECORDS(1), - LESS_THAN_OR_EQUAL_TO(2), - GREATER_THAN_OR_EQUAL_TO(3), - WITHIN_RANGE_OF_INCLUSIVE(4), - FIRST_RECORD(5), - LAST_RECORD(6); - - companion object { - private val map = Operator.values().associateBy(Operator::key) - fun fromKey(type: Int) = map[type] - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt deleted file mode 100644 index 00e62b4..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/racp/ResponseCode.kt +++ /dev/null @@ -1,20 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.racp - -enum class ResponseCode constructor(val key: Int) { - RESERVED_FOR_FUTURE_USE(0), - SUCCESS(1), - OP_CODE_NOT_SUPPORTED(2), - INVALID_OPERATOR(3), - OPERATOR_NOT_SUPPORTED(4), - INVALID_OPERAND(5), - NO_RECORDS_FOUND(6), - ABORT_UNSUCCESSFUL(7), - PROCEDURE_NOT_COMPLETED(8), - OPERAND_NOT_SUPPORTED(9); - - companion object { - private val map = ResponseCode.values().associateBy(ResponseCode::key) - fun fromKey(type: Int) = map[type] - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt deleted file mode 100644 index e056371..0000000 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/sessionstarttime/DstOffset.kt +++ /dev/null @@ -1,14 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.sessionstarttime - -enum class DstOffset(val key: Int) { - STANDARD_TIME(0), - HALF_AN_HOUR_DAYLIGHT_TIME(2), - DAYLIGHT_TIME(4), - DOUBLE_DAYLIGHT_TIME(8), - DST_IS_NOT_KNOWN(255); - - companion object { - private val map = DstOffset.values().associateBy(DstOffset::key) - fun fromKey(type: Int) = map[type] - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt deleted file mode 100644 index ccfd356..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmFeatureCharacteristicTest.kt +++ /dev/null @@ -1,157 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.bgm.characteristic.compoundcharacteristic.GlucoseFeatureCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.GattCharacteristic -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmSampleLocation -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.CgmType -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags -import org.junit.After -import org.junit.Assert -import org.junit.Before - -import org.junit.Assert.* -import org.junit.Test -import java.util.* - -class CgmFeatureCharacteristicTest : BaseTest(){ - - /** - * Test packet 1 - * A normal CGM Feature packet with no CRC - */ - private val testPacket1 = byteArrayOf(0b01010101,0b10101010.toByte(),0b10101010.toByte(), 0x52) - private val expectedFlagSet1 = EnumSet.of( - Flags.CALIBRATION_SUPPORTED, - Flags.HYPO_ALERTS_SUPPORTED, - Flags.RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED, - Flags.SENSOR_MALFUNCTION_DETECTION_SUPPORTED, - Flags.LOW_BATTERY_DETECTION_SUPPORTED, - Flags.GENERAL_DEVICE_FAULT_SUPPORTED, - Flags.MULTIPLE_BOND_SUPPORTED, - Flags.CGM_TREND_INFORMATION_SUPPORTED - ) - - private val expectedType1 = CgmType.CAPILLARY_PLASMA - private val expectedSampleLocation1 = CgmSampleLocation.SUBCUTANEOUS_TISSUE - - /** - * Test Packet 2 - * A normal CGM feature packet with correct CRC - */ - private val testPacket2 = byteArrayOf(0b01010101,0b10111010.toByte(),0b10101010.toByte(), 0x52, 0x40.toByte(), 0x62.toByte()) - private val expectedFlagSet2 = EnumSet.of( - Flags.CALIBRATION_SUPPORTED, - Flags.HYPO_ALERTS_SUPPORTED, - Flags.RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED, - Flags.SENSOR_MALFUNCTION_DETECTION_SUPPORTED, - Flags.LOW_BATTERY_DETECTION_SUPPORTED, - Flags.GENERAL_DEVICE_FAULT_SUPPORTED, - Flags.MULTIPLE_BOND_SUPPORTED, - Flags.E2E_CRC_SUPPORTED, - Flags.CGM_TREND_INFORMATION_SUPPORTED - ) - - private val expectedType2 = CgmType.CAPILLARY_PLASMA - private val expectedSampleLocation2 = CgmSampleLocation.SUBCUTANEOUS_TISSUE - - - /** - * Test Packet 3 - * A normal CGM feature packet with incorrect CRC - */ - private val testPacket3 = byteArrayOf(0b01010101,0b10111010.toByte(),0b10101010.toByte(), 0x52, 0xd5.toByte(), 0xe6.toByte()) - private val expectedFlagSet3 = EnumSet.of( - Flags.CALIBRATION_SUPPORTED, - Flags.HYPO_ALERTS_SUPPORTED, - Flags.RATE_OF_INCREASE_DECREASE_ALERTS_SUPPORTED, - Flags.SENSOR_MALFUNCTION_DETECTION_SUPPORTED, - Flags.LOW_BATTERY_DETECTION_SUPPORTED, - Flags.GENERAL_DEVICE_FAULT_SUPPORTED, - Flags.E2E_CRC_SUPPORTED, - Flags.MULTIPLE_BOND_SUPPORTED, - Flags.CGM_TREND_INFORMATION_SUPPORTED - ) - - private val expectedType3 = null - private val expectedSampleLocation3 = null - - - - @Test - fun testTag() { - val cgmFeatureCharacteristic = CgmFeatureCharacteristic(null) - Assert.assertEquals(CgmFeatureCharacteristic::class.java.canonicalName as String, cgmFeatureCharacteristic.tag) - } - - @Test - fun testAssignedNumber() { - val cgmFeatureCharacteristic = CgmFeatureCharacteristic(null) - Assert.assertEquals(GattCharacteristic.CGM_FEATURE.assigned, cgmFeatureCharacteristic.uuid) - } - - @Test - fun testPartialParseFail(){ - //This is a garbage payload, with no readable data. - val badPayload = byteArrayOf(Byte.MIN_VALUE) - val cgmFeatureCharacteristic = CgmFeatureCharacteristic(mockBTCharacteristic(badPayload)) - - Assert.assertFalse(cgmFeatureCharacteristic.successfulParsing) - } - - @Test - fun parseSuccess(){ - Assert.assertTrue(CgmFeatureCharacteristic(mockBTCharacteristic(testPacket1)).successfulParsing) - Assert.assertTrue(CgmFeatureCharacteristic(mockBTCharacteristic(testPacket2)).successfulParsing) - Assert.assertFalse(CgmFeatureCharacteristic(mockBTCharacteristic(testPacket3)).successfulParsing) - } - - @Test - fun parseSampleLocationSuccessfully(){ - Assert.assertEquals(expectedSampleLocation1, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket1)).cgmSampleLocation) - Assert.assertEquals(expectedSampleLocation2, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket2)).cgmSampleLocation) - Assert.assertEquals(expectedSampleLocation3, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket3)).cgmSampleLocation) - - Assert.assertEquals(expectedType1, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket1)).cgmType) - Assert.assertEquals(expectedType2, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket2)).cgmType) - Assert.assertEquals(expectedType3, CgmFeatureCharacteristic(mockBTCharacteristic(testPacket3)).cgmType) - } - - @Test - fun isFeatureSupported() { - - //This test if the [isFeatureSupported] function returns the correct Boolean Value. - - for (flag in Flags.values()) { - val flagValue = flag.bit - val testPacket: ByteArray = byteArrayOf((flagValue and 0x00FF).toByte(), - ((flagValue and 0x00FF00) shr 8).toByte(), - ((flagValue and 0xFF0000) shr 16).toByte(), - 0x00 - ) - - var cgmFeatureCharacteristic = CgmFeatureCharacteristic(mockBTCharacteristic(testPacket)) - - System.out.printf("flag values %04x . E2E flag value %04x\n", flagValue, Flags.E2E_CRC_SUPPORTED.bit) - if(flagValue == Flags.E2E_CRC_SUPPORTED.bit) { - //If the CRC bit is set, the parsing should fail as there is no CRC code attached to the raw packet - Assert.assertEquals(false, cgmFeatureCharacteristic.successfulParsing) - }else{ - Assert.assertEquals(true, cgmFeatureCharacteristic.successfulParsing) - } - //check correct flags are set and supported - for (otherFlag in Flags.values()) { - if (otherFlag != flag) { - Assert.assertEquals(false, cgmFeatureCharacteristic.isFeatureSupported(otherFlag)) - } else { - if(flagValue == Flags.E2E_CRC_SUPPORTED.bit) { - Assert.assertEquals(false, cgmFeatureCharacteristic.isFeatureSupported(otherFlag)) - }else { - Assert.assertEquals(true, cgmFeatureCharacteristic.isFeatureSupported(otherFlag)) - } - } - } - } - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt deleted file mode 100644 index 0c820b7..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmMeasurementCharacteristicTest.kt +++ /dev/null @@ -1,245 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.Flags -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test -import java.util.* - -class CgmMeasurementCharacteristicTest : BaseTest(){ - - /** - * Test Packet 1 - * Concentration Only Packet - */ - private val testPacket1: ByteArray = byteArrayOf(0x06, 0x00, 0x62, 0xF1.toByte(), 0x12, 0x34) - private val expectedParseResult1: Boolean = true - private val expectedConcentration1: Float = 35.4.toFloat() - private val expectedTrend1 = null - private val expectedQuality1 = null - private val expectedSensorStatusAnnunciation1: EnumSet = EnumSet.noneOf(SensorStatusAnnunciation::class.java) - private val expectedFlags1: EnumSet = EnumSet.noneOf(Flags::class.java) - private val expectedTimeOffset1 = 13330 - private val expectedSize1 = 7 - - /** - * Test Packet 2 - * Has Status Octet in the annunciation - */ - private val testPacket2: ByteArray = byteArrayOf(0x06, 0x00, 0x62, 0xF1.toByte(), 0x12, 0x34) - private val expectedParseResult2: Boolean = true - private val expectedConcentration2: Float = 35.4.toFloat() - private val expectedTrend2 = null - private val expectedQuality2 = null - private val expectedSensorStatusAnnunciation2: EnumSet = EnumSet.noneOf(SensorStatusAnnunciation::class.java) - private val expectedFlags2: EnumSet = EnumSet.noneOf(Flags::class.java) - private val expectedTimeOffset2 = 13330 - private val expectedSize2 = 6 - - /** - * Test Packet 3 - * - * Has Calibration Octet in the annunciation - * - */ - private val testPacket3: ByteArray = byteArrayOf(0x07, 0x40.toByte(), 0x62, 0xF1.toByte(), 0x12, 0x34, 0x01) - private val expectedParseResult3: Boolean = true - private val expectedConcentration3: Float = 35.4.toFloat() - private val expectedTrend3 = null - private val expectedQuality3 = null - private val expectedSensorStatusAnnunciation3: EnumSet = EnumSet.of( - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) - private val expectedFlags3: EnumSet = EnumSet.of( - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT) - private val expectedTimeOffset3 = 13330 - private val expectedSize3 = 7 - - /** - * Test Packet 4 - * Has Warning Octet in the annunciation - */ - private val testPacket4: ByteArray = byteArrayOf(0x07, 0x20.toByte(), 0x62, 0xF1.toByte(), 0x12, 0x34, 0x01) - private val expectedParseResult4: Boolean = true - private val expectedConcentration4: Float = 35.4.toFloat() - private val expectedTrend4 = null - private val expectedQuality4 = null - private val expectedSensorStatusAnnunciation4: EnumSet = EnumSet.of(SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL) - private val expectedFlags4: EnumSet = EnumSet.of(Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) - private val expectedTimeOffset4 = 13330 - private val expectedSize4 = 7 - - /** - * Test Packet 5 - * Has Warning Octet and calibration in the annunciation - */ - private val testPacket5: ByteArray = byteArrayOf(0x08, 0x60.toByte(), 0x62, 0xF1.toByte(), 0x12, 0x34, 0x01, 0x01) - private val expectedParseResult5: Boolean = true - private val expectedConcentration5: Float = 35.4.toFloat() - private val expectedTrend5 = null - private val expectedQuality5 = null - private val expectedSensorStatusAnnunciation5: EnumSet = EnumSet.of( - SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) - private val expectedFlags5: EnumSet = EnumSet.of( - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) - private val expectedTimeOffset5 = 13330 - private val expectedSize5 = 8 - - /** - * Test Packet 6 - * Nagative Concentration, a erroneous case, but it wont report error because it is not the parser - * responsibility to validate values. - */ - private val testPacket6: ByteArray = byteArrayOf(0x08, 0x60.toByte(), 0xDD.toByte(), 0xFF.toByte(), 0x12, 0x34, 0x01, 0x01) - private val expectedParseResult6: Boolean = true - private val expectedConcentration6: Float = -3.5.toFloat() - private val expectedTrend6 = null - private val expectedQuality6 = null - private val expectedSensorStatusAnnunciation6: EnumSet = EnumSet.of( - SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) - private val expectedFlags6: EnumSet = EnumSet.of( - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) - private val expectedTimeOffset6 = 13330 - private val expectedSize6 = 8 - - /** - * Test Packet 7 - * Trend present - */ - private val testPacket7: ByteArray = byteArrayOf(0x0A, 0x61.toByte(), 0x62.toByte(), 0xF1.toByte(), 0x12, 0x34, 0x01, 0x01, 0xF3.toByte(), 0xFF.toByte()) - private val expectedParseResult7: Boolean = true - private val expectedConcentration7: Float = 35.4.toFloat() - private val expectedTrend7 = -1.3.toFloat() - private val expectedQuality7 = null - private val expectedSensorStatusAnnunciation7: EnumSet = EnumSet.of( - SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) - private val expectedFlags7: EnumSet = EnumSet.of( - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT, - Flags.CGM_TREND_INFORMATION_PRESENT) - private val expectedTimeOffset7 = 13330 - private val expectedSize7 = 10 - - - /** - * Test Packet 8 - * Quality present - */ - private val testPacket8: ByteArray = byteArrayOf(0x0A, 0x62.toByte(), 0x62.toByte(), 0xF1.toByte(), 0x12, 0x34, 0x01, 0x01, 0xe7.toByte(), 0xF3.toByte()) - private val expectedParseResult8: Boolean = true - private val expectedConcentration8: Float = 35.4.toFloat() - private val expectedTrend8 = null - private val expectedQuality8 = 99.9.toFloat() - private val expectedSensorStatusAnnunciation8: EnumSet = EnumSet.of( - SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED) - private val expectedFlags8: EnumSet = EnumSet.of( - Flags.CGM_QUALITY_PRESENT, - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_CALTEMP_OCTET_PRESENT, - Flags.SENSOR_STATUS_ANNUNCIATION_FIELD_WARNING_OCTET_PRESENT) - private val expectedTimeOffset8 = 13330 - private val expectedSize8 = 10 - - @Test - fun testParseSuccessfully() { - Assert.assertEquals(expectedParseResult1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).successfulParsing) - Assert.assertEquals(expectedParseResult2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).successfulParsing) - Assert.assertEquals(expectedParseResult3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).successfulParsing) - Assert.assertEquals(expectedParseResult4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).successfulParsing) - Assert.assertEquals(expectedParseResult5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).successfulParsing) - Assert.assertEquals(expectedParseResult6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).successfulParsing) - Assert.assertEquals(expectedParseResult7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).successfulParsing) - Assert.assertEquals(expectedParseResult8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).successfulParsing) - } - - @Test - fun testParsingConcentrationField() { - Assert.assertEquals(expectedConcentration1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).cgmGlucoseConcentration) - Assert.assertEquals(expectedConcentration8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).cgmGlucoseConcentration) - } - - @Test - fun testParsingTrendInformation() { - Assert.assertEquals(expectedTrend1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).cgmTrendInformation) - Assert.assertEquals(expectedTrend2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).cgmTrendInformation) - Assert.assertEquals(expectedTrend3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).cgmTrendInformation) - Assert.assertEquals(expectedTrend4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).cgmTrendInformation) - Assert.assertEquals(expectedTrend5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).cgmTrendInformation) - Assert.assertEquals(expectedTrend6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).cgmTrendInformation) - Assert.assertEquals(expectedTrend7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).cgmTrendInformation) - Assert.assertEquals(expectedTrend8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).cgmTrendInformation) - } - - @Test - fun testParsingQualityField() { - Assert.assertEquals(expectedQuality1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).cgmQuality) - Assert.assertEquals(expectedQuality2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).cgmQuality) - Assert.assertEquals(expectedQuality3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).cgmQuality) - Assert.assertEquals(expectedQuality4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).cgmQuality) - Assert.assertEquals(expectedQuality5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).cgmQuality) - Assert.assertEquals(expectedQuality6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).cgmQuality) - Assert.assertEquals(expectedQuality7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).cgmQuality) - Assert.assertEquals(expectedQuality8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).cgmQuality) - } - - @Test - fun testParsingStatusAnnunciationFlags() { - Assert.assertEquals(expectedSensorStatusAnnunciation1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).sensorStatusAnnunciation) - Assert.assertEquals(expectedSensorStatusAnnunciation8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).sensorStatusAnnunciation) - } - - @Test - fun testParsingFlags() { - Assert.assertEquals(expectedFlags1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).flags) - Assert.assertEquals(expectedFlags2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).flags) - Assert.assertEquals(expectedFlags3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).flags) - Assert.assertEquals(expectedFlags4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).flags) - Assert.assertEquals(expectedFlags5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).flags) - Assert.assertEquals(expectedFlags6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).flags) - Assert.assertEquals(expectedFlags7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).flags) - Assert.assertEquals(expectedFlags8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).flags) - } - - @Test - fun testParsingSize() { - Assert.assertEquals(expectedSize1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).size) - Assert.assertEquals(expectedSize2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).size) - Assert.assertEquals(expectedSize3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).size) - Assert.assertEquals(expectedSize4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).size) - Assert.assertEquals(expectedSize5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).size) - Assert.assertEquals(expectedSize6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).size) - Assert.assertEquals(expectedSize7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).size) - Assert.assertEquals(expectedSize8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).size) - } - - @Test - fun testParsingOffset() { - Assert.assertEquals(expectedTimeOffset1, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket1)).timeOffset) - Assert.assertEquals(expectedTimeOffset2, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket2)).timeOffset) - Assert.assertEquals(expectedTimeOffset3, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket3)).timeOffset) - Assert.assertEquals(expectedTimeOffset4, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket4)).timeOffset) - Assert.assertEquals(expectedTimeOffset5, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket5)).timeOffset) - Assert.assertEquals(expectedTimeOffset6, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket6)).timeOffset) - Assert.assertEquals(expectedTimeOffset7, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket7)).timeOffset) - Assert.assertEquals(expectedTimeOffset8, CgmMeasurementCharacteristic(mockBTCharacteristic(testPacket8)).timeOffset) - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt deleted file mode 100644 index 8dae962..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionRunTimeTest.kt +++ /dev/null @@ -1,52 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test - -class CgmSessionRunTimeTest : BaseTest(){ - /** - * Test Packet 1 - * Normal case without CRC - */ - private val testPacket1 = byteArrayOf(0x01, 0x02) - private val hasCrc1 = false - private val expectedParseResult1 = true - private val expectedSessionRunTime1 = 0x0201 - - /** - * Test Packet 2 - * Normal case with CRC - */ - private val testPacket2 = byteArrayOf(0x01, 0x02, 0x72, 0xca.toByte()) - private val hasCrc2 = true - private val expectedParseResult2 = true - private val expectedSessionRunTime2 = 0x0201 - - - /** - * Test Packet 2 - * Normal case with failed CRC - */ - private val testPacket3 = byteArrayOf(0x01, 0x02, 0x72, 0xcb.toByte()) - private val hasCrc3 = true - private val expectedParseResult3 = false - private val expectedSessionRunTime3 = null - - - @Test - fun testParseSuccessfully(){ - Assert.assertEquals(expectedParseResult1, CgmSessionRunTime(mockBTCharacteristic(testPacket1),hasCrc1).successfulParsing) - Assert.assertEquals(expectedParseResult2, CgmSessionRunTime(mockBTCharacteristic(testPacket2),hasCrc2).successfulParsing) - Assert.assertEquals(expectedParseResult3, CgmSessionRunTime(mockBTCharacteristic(testPacket3),hasCrc3).successfulParsing) - } - - @Test - fun testSessionRunTime(){ - Assert.assertEquals(expectedSessionRunTime1, CgmSessionRunTime(mockBTCharacteristic(testPacket1),hasCrc1).sessionRunTime) - Assert.assertEquals(expectedSessionRunTime2, CgmSessionRunTime(mockBTCharacteristic(testPacket2),hasCrc2).sessionRunTime) - Assert.assertEquals(expectedSessionRunTime3, CgmSessionRunTime(mockBTCharacteristic(testPacket3),hasCrc3).sessionRunTime) - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt deleted file mode 100644 index 85f7de4..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmSessionStartTimeTest.kt +++ /dev/null @@ -1,141 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.sessionstarttime.DstOffset -import org.ehealthinnovation.jdrfandroidbleparser.utility.BluetoothDateTime -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test - -class CgmSessionStartTimeTest: BaseTest(){ - /** - * Packet 1 - * Standard time, no dst no crc - */ - private val testPacket1 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00, 0x00) - private val expectedParseResult1 = true - private val expectedTime1 = BluetoothDateTime(2018,6,6,14,53,14) - private val expectedDst1 = DstOffset.STANDARD_TIME - private val expectedTimeZone1 = 0 - - /** - * Packet 2 - * Maximum negative timezone , no dst no Crc - */ - private val testPacket2 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0xD0.toByte(), 0x00) - private val expectedParseResult2 = true - private val expectedTime2 = BluetoothDateTime(2018,6,6,14,53,14) - private val expectedDst2 = DstOffset.STANDARD_TIME - private val expectedTimeZone2 = -48 - - /** - * Packet 3 - * Max positive timezone, no dst, no crc - */ - private val testPacket3 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x38.toByte(), 0x00) - private val expectedParseResult3 = true - private val expectedTime3 = BluetoothDateTime(2018,6,6,14,53,14) - private val expectedDst3 = DstOffset.STANDARD_TIME - private val expectedTimeZone3 = 56 - - /** - * Packet 4 - * standard unknown timezone, no dst, no crc - */ - private val testPacket4 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x80.toByte(), 0x00) - private val expectedParseResult4 = true - private val expectedTime4 = BluetoothDateTime(2018,6,6,14,53,14) - private val expectedDst4 = DstOffset.STANDARD_TIME - private val expectedTimeZone4 = -128 - - /** - * Packet 5 - * Standard Timezone, one hour dst, no crc - */ - private val testPacket5 = byteArrayOf(0xe2.toByte(), 0x07, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) - private val expectedParseResult5 = true - private val expectedTime5 = BluetoothDateTime(2018,6,6,14,53,14) - private val expectedDst5 = DstOffset.DAYLIGHT_TIME - private val expectedTimeZone5 = 0 - - /** - * Packet 6 - * Uknown Year, Standard Timezone, one hour dst, no crc - */ - private val testPacket6 = byteArrayOf(0.toByte(), 0, 0x06, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) - private val expectedParseResult6 = true - private val expectedTime6 = BluetoothDateTime(0,6,6,14,53,14) - private val expectedDst6 = DstOffset.DAYLIGHT_TIME - private val expectedTimeZone6 = 0 - - /** - * Packet 7 - * Unknown month, standard time, one hour dst, no crc - */ - private val testPacket7 = byteArrayOf(0xe2.toByte(), 0x07, 0x00, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) - private val expectedParseResult7 = true - private val expectedTime7 = BluetoothDateTime(2018,0,6,14,53,14) - private val expectedDst7 = DstOffset.DAYLIGHT_TIME - private val expectedTimeZone7 = 0 - - /** - * Packet 8 - * Unknown Day, standard time, one hour dst, no crc - */ - - private val testPacket8 = byteArrayOf(0xe2.toByte(), 0x07, 0x00, 0x06, 0x0e, 0x35, 0x0e, 0x00.toByte(), 0x04) - private val expectedParseResult8 = true - private val expectedTime8 = BluetoothDateTime(2018,0,6,14,53,14) - private val expectedDst8 = DstOffset.DAYLIGHT_TIME - private val expectedTimeZone8 = 0 - - @Test - fun testParseSuccessfully(){ - Assert.assertEquals(expectedParseResult1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).successfulParsing) - Assert.assertEquals(expectedParseResult2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).successfulParsing) - Assert.assertEquals(expectedParseResult3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).successfulParsing) - Assert.assertEquals(expectedParseResult4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).successfulParsing) - Assert.assertEquals(expectedParseResult5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).successfulParsing) - Assert.assertEquals(expectedParseResult6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).successfulParsing) - Assert.assertEquals(expectedParseResult7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).successfulParsing) - Assert.assertEquals(expectedParseResult8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).successfulParsing) - - } - - @Test - fun testParseDate(){ - Assert.assertEquals(expectedTime1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).sessionStartTime) - Assert.assertEquals(expectedTime2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).sessionStartTime) - Assert.assertEquals(expectedTime3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).sessionStartTime) - Assert.assertEquals(expectedTime4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).sessionStartTime) - Assert.assertEquals(expectedTime5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).sessionStartTime) - Assert.assertEquals(expectedTime6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).sessionStartTime) - Assert.assertEquals(expectedTime7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).sessionStartTime) - Assert.assertEquals(expectedTime8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).sessionStartTime) - } - - @Test - fun testParseDst(){ - Assert.assertEquals(expectedDst1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).dstOffset) - Assert.assertEquals(expectedDst2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).dstOffset) - Assert.assertEquals(expectedDst3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).dstOffset) - Assert.assertEquals(expectedDst4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).dstOffset) - Assert.assertEquals(expectedDst5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).dstOffset) - Assert.assertEquals(expectedDst6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).dstOffset) - Assert.assertEquals(expectedDst7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).dstOffset) - Assert.assertEquals(expectedDst8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).dstOffset) - } - - @Test - fun testParseTimeZone(){ - Assert.assertEquals(expectedTimeZone1, CgmSessionStartTime(mockBTCharacteristic(testPacket1)).timeZone) - Assert.assertEquals(expectedTimeZone2, CgmSessionStartTime(mockBTCharacteristic(testPacket2)).timeZone) - Assert.assertEquals(expectedTimeZone3, CgmSessionStartTime(mockBTCharacteristic(testPacket3)).timeZone) - Assert.assertEquals(expectedTimeZone4, CgmSessionStartTime(mockBTCharacteristic(testPacket4)).timeZone) - Assert.assertEquals(expectedTimeZone5, CgmSessionStartTime(mockBTCharacteristic(testPacket5)).timeZone) - Assert.assertEquals(expectedTimeZone6, CgmSessionStartTime(mockBTCharacteristic(testPacket6)).timeZone) - Assert.assertEquals(expectedTimeZone7, CgmSessionStartTime(mockBTCharacteristic(testPacket7)).timeZone) - Assert.assertEquals(expectedTimeZone8, CgmSessionStartTime(mockBTCharacteristic(testPacket8)).timeZone) - - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt deleted file mode 100644 index f6282e8..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/cgm/characteristic/CgmStatusCharacteristicTest.kt +++ /dev/null @@ -1,75 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.cgm.characteristic - -import android.hardware.Sensor -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement.SensorStatusAnnunciation -import org.ehealthinnovation.jdrfandroidbleparser.utility.CrcHelper -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test -import java.util.* - -class CgmStatusCharacteristicTest : BaseTest() { - /** - * Test packet 1 - * Normal test case without crc - */ - private val testPacket1: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01,0x01) - private val expectedParseResult1: Boolean = true - private val expectedTimeOffset1 : Int = 256 - private val expectedFlagSet1 : EnumSet = EnumSet.of( - SensorStatusAnnunciation.SESSION_STOPPED, - SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED - ) - - /** - * Test packet 2 - * Normal failed test case without crc - */ - private val testPacket2: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01) - private val expectedParseResult2: Boolean = false - - /** - * Test packet 3 - * Normal test case (successful) with crc - */ - private val testPacket3: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01,0x01, 0xbe.toByte(), 0x7e) - private val expectedParseResult3: Boolean = true - private val expectedTimeOffset3 : Int = 256 - private val expectedFlagSet3 : EnumSet = EnumSet.of( - SensorStatusAnnunciation.SESSION_STOPPED, - SensorStatusAnnunciation.SENSOR_RESULT_LOWER_THAN_THE_PATIENT_LOW_LEVEL, - SensorStatusAnnunciation.TIME_SYNCHRONIZATION_BETWEEN_SENSOR_AND_COLLECTOR_REQUIRED - ) - - /** - * Test packet 4 - * Normalfaild test case with CRC - */ - private val testPacket4: ByteArray = byteArrayOf(0x00,0x01,0x01,0x01,0x01, 0xbe.toByte(), 0x7d) - private val expectedParseResult4: Boolean = false - - @Test - fun testParseResult(){ - Assert.assertEquals(expectedParseResult1, CgmStatusCharacteristic(mockBTCharacteristic(testPacket1)).successfulParsing) - Assert.assertEquals(expectedParseResult2, CgmStatusCharacteristic(mockBTCharacteristic(testPacket2)).successfulParsing) - Assert.assertEquals(expectedParseResult3, CgmStatusCharacteristic(mockBTCharacteristic(testPacket3), true).successfulParsing) - Assert.assertEquals(expectedParseResult4, CgmStatusCharacteristic(mockBTCharacteristic(testPacket4), true).successfulParsing) - } - - @Test - fun testTimeOffset(){ - Assert.assertEquals(expectedTimeOffset1, CgmStatusCharacteristic(mockBTCharacteristic(testPacket1)).timeOffset) - Assert.assertEquals(expectedTimeOffset3, CgmStatusCharacteristic(mockBTCharacteristic(testPacket3)).timeOffset) - - } - - @Test - fun testStatusFlag(){ - Assert.assertEquals(expectedFlagSet1, CgmStatusCharacteristic(mockBTCharacteristic(testPacket1)).cgmStatus) - Assert.assertEquals(expectedFlagSet3, CgmStatusCharacteristic(mockBTCharacteristic(testPacket3)).cgmStatus) - } - - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt deleted file mode 100644 index 722186f..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/feature/FlagsTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.feature.Flags -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test -import java.util.* - -class FlagsTest : BaseTest(){ - - @Test - fun testEach() { - enumValues().forEach { - val parseFlags = Flags.parseFlags(it.bit) - Assert.assertTrue(parseFlags.contains(it)) - } - } - - @Test - fun testCombinations() { - val setFlags: EnumSet = EnumSet.noneOf(Flags::class.java) - var currentMask = 0 - enumValues().forEach { - setFlags.add(it) - currentMask = currentMask.or(it.bit) - val parseFlags = Flags.parseFlags(currentMask) - setFlags.forEach { - Assert.assertTrue(parseFlags.contains(it)) - } - } - } - -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt deleted file mode 100644 index 06f80f9..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/FlagsTest.kt +++ /dev/null @@ -1,32 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test -import java.util.* - -class FlagsTest : BaseTest(){ - - @Test - fun testEach() { - enumValues().forEach { - val parseFlags = Flags.parseFlags(it.bit) - Assert.assertTrue(parseFlags.contains(it)) - } - } - - @Test - fun testCombinations() { - val setFlags: EnumSet = EnumSet.noneOf(Flags::class.java) - var currentMask = 0 - enumValues().forEach { - setFlags.add(it) - currentMask = currentMask.or(it.bit) - val parseFlags = Flags.parseFlags(currentMask) - setFlags.forEach { - Assert.assertTrue(parseFlags.contains(it)) - } - } - } -} \ No newline at end of file diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt deleted file mode 100644 index 7478b0f..0000000 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/encodedvalue/cgm/measurement/SensorStatusAnnunciationTest.kt +++ /dev/null @@ -1,31 +0,0 @@ -package org.ehealthinnovation.jdrfandroidbleparser.encodedvalue.cgm.measurement - -import org.ehealthinnovation.jdrfandroidbleparser.BaseTest -import org.junit.Assert -import org.junit.Assert.* -import org.junit.Test -import java.util.* - -class SensorStatusAnnunciationTest : BaseTest(){ - @Test - fun testEach() { - enumValues().forEach { - val parseFlags = SensorStatusAnnunciation.parseFlags(it.bit) - Assert.assertTrue(parseFlags.contains(it)) - } - } - - @Test - fun testCombinations() { - val setFlags: EnumSet = EnumSet.noneOf(SensorStatusAnnunciation::class.java) - var currentMask = 0 - enumValues().forEach { - setFlags.add(it) - currentMask = currentMask.or(it.bit) - val parseFlags = SensorStatusAnnunciation.parseFlags(currentMask) - setFlags.forEach { - Assert.assertTrue(parseFlags.contains(it)) - } - } - } -} \ No newline at end of file From cd780954a27bdc65babcb3f555a39a418dbcaa7c Mon Sep 17 00:00:00 2001 From: Harry Qiu Date: Fri, 21 Sep 2018 11:24:58 -0400 Subject: [PATCH 11/11] add appending crc and tests --- .../compoundcharacteristic/RACP.kt | 3 + .../common/BaseCharacteristic.kt | 22 ++- .../compoundcharacteristic/RACPTest.kt | 176 ++++++++++++++++++ 3 files changed, 196 insertions(+), 5 deletions(-) diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt index cacd73e..aee7074 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACP.kt @@ -227,6 +227,9 @@ class RACP : BaseCharacteristic, Composable { Log.e(tag, "unknown opcode") } } + if(hasCrc){ + attachCrc() + } } return rawData } diff --git a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt index fbe0148..3958399 100644 --- a/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt +++ b/jdrfandroidbleparser/src/main/java/org/ehealthinnovation/jdrfandroidbleparser/common/BaseCharacteristic.kt @@ -101,6 +101,23 @@ abstract class BaseCharacteristic(val uuid: Int) { return CrcHelper.testCcittCrc16(data, data.size) } + /** + * This function append the CRC to the end of the packet. + * @param data The raw data of the message byte sequence + * @return the resulting [ByteArray] with the CRC attached. + */ + protected fun attachCrc(data: ByteArray? = null) : ByteArray { + data?.let { + return CrcHelper.attachCcittCrc16ToPacket(data, data.size) + } + val cRc = CrcHelper.calculateCcittCrc16(rawData, rawData.size).toInt() + if(putIntValue(cRc, BluetoothGattCharacteristic.FORMAT_UINT16)) { + return rawData + }else{ + throw IllegalStateException("Unable to append CRC") + } + } + /** * Returns the stored [String] value of this characteristic. * @@ -194,11 +211,6 @@ abstract class BaseCharacteristic(val uuid: Int) { "characteristic is initiated with the composing constructor") } - - - - - /** * Increments the current read index by the appropriate amount for the format type passed in. * diff --git a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt index a2f10fd..50b5613 100644 --- a/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt +++ b/jdrfandroidbleparser/src/test/java/org/ehealthinnovation/jdrfandroidbleparser/bgm/characteristic/compoundcharacteristic/RACPTest.kt @@ -443,6 +443,149 @@ class RACPTest : BaseTest() { expectedResponseCode = null ) + /** + * packet21 + * general response successful with crc + */ + racpTestVectors[21] = RacpTestVector( + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x01, -22, 64), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.SUCCESS, + hasCrc = true + ) + + /** + * Packet22 + * Opcode not supported has CRC + */ + racpTestVectors[2] = RacpTestVector( + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x02, 113, 114), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.OP_CODE_NOT_SUPPORTED, + hasCrc = true) + + /** + * Packet23 + * Invalid Operator + */ + racpTestVectors[23] = RacpTestVector( + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x03, -8, 99), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.INVALID_OPERATOR, + hasCrc = true + ) + /** + + * Packet24 + * Operator not supported has CRC + */ + racpTestVectors[24] = RacpTestVector( + + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x04, 71, 23), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.OPERATOR_NOT_SUPPORTED, + hasCrc = true + ) + + /** + + * Packet25 + * General response successful has CRC + */ + racpTestVectors[25] = RacpTestVector( + + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x05, -50, 6), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.INVALID_OPERAND, + hasCrc = true + ) + /** + + * Packet26 + * No record found has CRC + */ + racpTestVectors[26] = RacpTestVector( + + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x06, 85, 52), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.NO_RECORDS_FOUND, + hasCrc = true + ) + /** + + * Packet27 + * Abort unsuccessful has CRC + */ + racpTestVectors[27] = RacpTestVector( + + testPacket = byteArrayOf(0x06, 0x00, 0x01, 0x07, -36, 37), + expectedParsingResult = true, + expectedOpcode = Opcode.RESPONSE_CODE, + expectedOperator = Operator.NULL, + expectedFilter = null, + expectedMinimumSequenceNumber = null, + expectedMaximumSequenceNumber = null, + expectedMinimumUserFacingTime = null, + expectedMaximumUserFacingTime = null, + expectedNumberOfRecord = null, + expectedRequestOpcode = Opcode.REPORT_STORED_RECORDS, + expectedResponseCode = ResponseCode.ABORT_UNSUCCESSFUL, + hasCrc = true + ) } @@ -578,4 +721,37 @@ class RACPTest : BaseTest() { } System.out.printf("Total cases: ${racpTestVectors.size} Cases skipped: $skipCount\n") } + + @Test + fun testAppendingCrc() { + System.out.printf("testAppendingCrC in RACP\n") + var testRacp: RACP + var skipCount = 0 + + for (testVector in racpTestVectors) { + System.out.printf("testing racpTestVector ${testVector.key}\n") + if (testVector.value.expectedParsingResult == false) { + System.out.printf("This case is expected to failed in parsing, so cant be composed backwards.\n") + skipCount++ + continue + } + testRacp = RACP(mockBTCharacteristic(ByteArray(0)), testVector.value.hasCrc, isComposing = true) + testRacp.operator = testVector.value.expectedOperator + testRacp.opcode = testVector.value.expectedOpcode + testRacp.filterType = testVector.value.expectedFilter + testRacp.minimumFilterValueUserFacingTime = testVector.value.expectedMinimumUserFacingTime + testRacp.minimumFilterValueSequenceNumber = testVector.value.expectedMinimumSequenceNumber + testRacp.maximumFilterValueUserFacingTime = testVector.value.expectedMaximumUserFacingTime + testRacp.maximumFilterValueSequenceNumber = testVector.value.expectedMaximumSequenceNumber + testRacp.requestOpcode = testVector.value.expectedRequestOpcode + testRacp.responseCode = testVector.value.expectedResponseCode + testRacp.hasCrc = testVector.value.hasCrc + testRacp.numberOfRecordResponse = testVector.value.expectedNumberOfRecord + val composedPacket = testRacp.composeCharacteristic(testVector.value.hasCrc) + System.out.printf("composed: " + composedPacket.contentToString() + "\n") + System.out.printf("test packet: " + testVector.value.testPacket.contentToString() + "\n") + Assert.assertTrue(testVector.value.testPacket.contentEquals(composedPacket)) + } + System.out.printf("Total cases: ${racpTestVectors.size} Cases skipped: $skipCount\n") + } } \ No newline at end of file