feat: subscribe to demo char changes

This commit is contained in:
Fabian Christoffel
2023-06-20 17:45:27 +02:00
parent 909e85d676
commit 2be1a5d6e9
2 changed files with 127 additions and 11 deletions

View File

@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.punchthrough.blestarterappandroid.ble
package com.example.sensortestingapp
import android.annotation.SuppressLint
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothProfile
import android.content.Context
import android.util.Log
@@ -28,6 +28,8 @@ import java.util.UUID
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentLinkedQueue
val CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805F9B34FB")
private const val GATT_MIN_MTU_SIZE = 23
/** Maximum BLE MTU size as defined in gatt_api.h. */
@@ -59,6 +61,14 @@ data class ReadChar(
val charId: UUID
) : BleOperationType()
data class SetNotification(
override val device: BluetoothDevice,
val serviceId: UUID,
val charId: UUID,
val enable: Boolean
) : BleOperationType()
data class DiscoverServicesRequest(
override val device: BluetoothDevice,
) : BleOperationType()
@@ -70,6 +80,12 @@ open class BleListener {
characteristic: BluetoothGattCharacteristic
) {
}
open fun onCharChange(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
}
}
@@ -173,6 +189,15 @@ object ConnectionManager {
enqueueOperation(ReadChar(device, service, char))
}
fun enableNotification(device: BluetoothDevice, service: UUID, char: UUID) {
enqueueOperation(SetNotification(device, service, char, true))
}
fun disableNotification(device: BluetoothDevice, service: UUID, char: UUID) {
enqueueOperation(SetNotification(device, service, char, false))
}
// - Beginning of PRIVATE functions
@Synchronized
@@ -235,6 +260,7 @@ object ConnectionManager {
return
}
when (operation) {
is Disconnect -> with(operation) {
Log.w("ConnectionManager", "Disconnecting from ${device.address}")
@@ -256,12 +282,67 @@ object ConnectionManager {
if (characteristic?.isReadable() == true) {
gatt.readCharacteristic(characteristic)
} else {
Log.e("ConnectionManager", "Char $charId (${serviceId}) is not readable!")
signalEndOfOperation()
}
}
is SetNotification -> with(operation) {
val characteristic = gatt.getService(serviceId)?.getCharacteristic(charId);
if (characteristic == null) {
Log.e("ConnectionManager", "Char $charId (${serviceId}) not found!")
signalEndOfOperation()
return
}
val descriptor = characteristic.getDescriptor(CCC_DESCRIPTOR_UUID)
if (!characteristic.isNotifiable() && !characteristic.isIndicatable()) {
Log.e(
"ConnectionManager", "Char ${characteristic.uuid} (service: $serviceId)" +
" doesn't support notifications/indications"
)
signalEndOfOperation()
return
}
val payload: ByteArray
if (enable) {
if (!gatt.setCharacteristicNotification(characteristic, true)) {
Log.e(
"ConnectionManager", "setCharacteristicNotification to true " +
"failed for ${characteristic.uuid} (service: $serviceId)"
)
signalEndOfOperation()
return
}
payload =
if (characteristic.isIndicatable())
BluetoothGattDescriptor.ENABLE_INDICATION_VALUE
else BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
} else {
if (!gatt.setCharacteristicNotification(characteristic, false)) {
Log.e(
"ConnectionManager", "setCharacteristicNotification to false " +
"failed for ${characteristic.uuid} (service: $serviceId)"
)
signalEndOfOperation()
return
}
payload = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE
}
gatt.let { gatt ->
descriptor.value = payload
gatt.writeDescriptor(descriptor)
}
}
// necessary because of IDE type inference bug
// https://youtrack.jetbrains.com/issue/KTIJ-20749/Exhaustive-when-check-does-not-take-into-account-the-values-excluded-by-previous-if-conditions
is Connect -> {
Log.e("ConnectionManager", "Shouldn't get here")
}
@@ -365,11 +446,33 @@ object ConnectionManager {
}
}
if (pendingOperation is ReadChar) {
val op = pendingOperation
if (op is ReadChar && op.charId == characteristic.uuid && op.serviceId == characteristic.service.uuid) {
signalEndOfOperation()
}
}
override fun onDescriptorWrite(
gatt: BluetoothGatt,
descriptor: BluetoothGattDescriptor,
status: Int
) {
val op = pendingOperation
if (op is SetNotification &&
descriptor.uuid == CCC_DESCRIPTOR_UUID
&& op.charId == descriptor.characteristic.uuid && op.serviceId == descriptor.characteristic.service.uuid
) {
signalEndOfOperation()
}
}
override fun onCharacteristicChanged(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
notifyListeners { listener -> listener.onCharChange(gatt, characteristic) }
}
}

View File

@@ -28,8 +28,6 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SimpleItemAnimator
import com.example.sensortestingapp.databinding.ActivityMainBinding
import com.punchthrough.blestarterappandroid.ble.BleListener
import com.punchthrough.blestarterappandroid.ble.ConnectionManager
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.UUID
@@ -138,21 +136,36 @@ class MainActivity : AppCompatActivity() {
ConnectionManager.connect(scanResult.device, applicationContext)
ConnectionManager.requestMtu(scanResult.device, Int.MAX_VALUE)
ConnectionManager.discoverServices(scanResult.device)
ConnectionManager.readChar(scanResult.device, DEMO_SERVICE_UUID, DEMO_CHAR_UUID)
//ConnectionManager.readChar(scanResult.device, DEMO_SERVICE_UUID, DEMO_CHAR_UUID)
ConnectionManager.enableNotification(
scanResult.device,
DEMO_SERVICE_UUID,
DEMO_CHAR_UUID
)
}
}
private val bleListener = object : BleListener() {
fun logDemoPayload(characteristic: BluetoothGattCharacteristic) {
if (characteristic.service.uuid == DEMO_SERVICE_UUID && characteristic.uuid == DEMO_CHAR_UUID) {
val payload = decodeDemoPayload(characteristic.value)
Log.i("BleListener", "Demo char received: $payload")
}
}
override fun onSuccessfulCharRead(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
logDemoPayload(characteristic)
}
if (characteristic.service.uuid == DEMO_SERVICE_UUID && characteristic.uuid == DEMO_CHAR_UUID) {
val payload = decodeDemoPayload(characteristic.value)
Log.i("BleListener", "Demo char received: $payload")
}
override fun onCharChange(
gatt: BluetoothGatt,
characteristic: BluetoothGattCharacteristic
) {
logDemoPayload(characteristic)
}
}