Skip to content

Commit

Permalink
First cross-layer callback working
Browse files Browse the repository at this point in the history
  • Loading branch information
kdewald committed Apr 11, 2024
1 parent 105af86 commit 410d6a4
Show file tree
Hide file tree
Showing 10 changed files with 461 additions and 202 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import org.simpleble.examples.android.views.ConnectContent
import org.simpleble.examples.android.views.ListAdaptersContent
import org.simpleble.examples.android.views.ScanContent

Expand Down Expand Up @@ -109,184 +110,6 @@ fun ExampleView() {
// ---------------------------- Composable functions ----------------------------


// ---------------------------- Composable functions ----------------------------

data class PeripheralInfo(
val identifier: String,
val address: String,
val rssi: Int,
val isConnectable: Boolean,
val txPower: Int,
val addressType: String,
val services: List<ServiceInfo>,
val manufacturerData: Map<Int, List<Byte>>,
// This is for connect
val mtu: Int = 0,
val connect: () -> Unit = {},
val disconnect: () -> Unit = {}
)

data class ServiceInfo(
val uuid: String,
val data: ByteArray,
val characteristics: List<CharacteristicInfo> = emptyList()
)

data class CharacteristicInfo(
val uuid: String,
val capabilities: List<String> = emptyList(),
val descriptors: List<DescriptorInfo> = emptyList()
)

data class DescriptorInfo(
val uuid: String
)

@Composable
fun ConnectContent() {
var scanResults by remember { mutableStateOf(emptyList<PeripheralInfo>()) }
var isScanning by remember { mutableStateOf(false) }
var selectedDevice by remember { mutableStateOf<PeripheralInfo?>(null) }
var isConnected by remember { mutableStateOf(false) }
var mtu by remember { mutableStateOf(0) }

//val adapter = SimpleBLE.getAdapter()

LaunchedEffect(Unit) {
// adapter.setCallbackOnScanFound { peripheral ->
// scanResults = scanResults + PeripheralInfo(
// identifier = peripheral.identifier,
// address = peripheral.address
// )
// }
// adapter.setCallbackOnScanStart {
// println("Scan started.")
// isScanning = true
// }
// adapter.setCallbackOnScanStop {
// println("Scan stopped.")
// isScanning = false
// }
}

Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(
onClick = {
if (!isScanning) {
scanResults = emptyList()
//adapter.scanFor(5000)
}
},
modifier = Modifier.padding(16.dp)
) {
Text(text = if (isScanning) "Scanning..." else "Start Scan")
}

if (scanResults.isNotEmpty()) {
Text(
text = "The following devices were found:",
style = MaterialTheme.typography.h6,
modifier = Modifier.padding(16.dp)
)

LazyColumn(
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(16.dp)
) {
items(scanResults.withIndex().toList()) { (index, peripheral) ->
Text(
text = "[$index] ${peripheral.identifier} [${peripheral.address}]",
style = MaterialTheme.typography.body1,
modifier = Modifier
.padding(8.dp)
.clickable {
selectedDevice = peripheral
}
)
}
}
} else {
Text(
text = "No devices found.",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)
}

selectedDevice?.let { peripheral ->
Text(
text = "Connecting to ${peripheral.identifier} [${peripheral.address}]",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

Button(
onClick = {
if (!isConnected) {
peripheral.connect()
isConnected = true
mtu = peripheral.mtu
} else {
peripheral.disconnect()
isConnected = false
mtu = 0
}
},
modifier = Modifier.padding(16.dp)
) {
Text(text = if (isConnected) "Disconnect" else "Connect")
}

if (isConnected) {
Text(
text = "Successfully connected.",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

Text(
text = "MTU: $mtu",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

peripheral.services.forEach { service ->
Text(
text = "Service: ${service.uuid}",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

service.characteristics.forEach { characteristic ->
Text(
text = "Characteristic: ${characteristic.uuid}",
style = MaterialTheme.typography.body2,
modifier = Modifier.padding(start = 32.dp)
)

Text(
text = "Capabilities: ${characteristic.capabilities.joinToString(", ")}",
style = MaterialTheme.typography.body2,
modifier = Modifier.padding(start = 32.dp)
)

characteristic.descriptors.forEach { descriptor ->
Text(
text = "Descriptor: ${descriptor.uuid}",
style = MaterialTheme.typography.body2,
modifier = Modifier.padding(start = 48.dp)
)
}
}
}
}
}
}
}

@Composable
fun ReadContent() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
package org.simpleble.examples.android.views

import android.util.Log
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.simpleble.android.Adapter
import org.simpleble.android.BluetoothUUID
import org.simpleble.android.Peripheral


@Composable
fun ConnectContent() {
val adapter = Adapter.getAdapters()[0]
var scanResults by remember { mutableStateOf(emptyList<Peripheral>()) }
var isScanning by remember { mutableStateOf(false) }
var selectedDevice by remember { mutableStateOf<Peripheral?>(null) }
var isConnected by remember { mutableStateOf(false) }
var mtu by remember { mutableStateOf(0) }

//val adapter = SimpleBLE.getAdapter()

LaunchedEffect(Unit) {
CoroutineScope(Dispatchers.Main).launch {
adapter.onScanActive.collect {
Log.d("SimpleBLE", "Scan active: $it")
isScanning = it
}
}

CoroutineScope(Dispatchers.Main).launch {
adapter.onScanFound.collect {
Log.d("SimpleBLE", "Found device: ${it.identifier} [${it.address}] ${it.rssi} dBm")
scanResults = scanResults + it
}
}
}

Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Button(
onClick = {
if (!isScanning) {
CoroutineScope(Dispatchers.Main).launch {
scanResults = emptyList()
adapter.scanFor(5000)
}
}
},
modifier = Modifier.padding(16.dp)
) {
Text(text = if (isScanning) "Scanning..." else "Start Scan")
}

if (scanResults.isNotEmpty()) {
Text(
text = "The following devices were found:",
style = MaterialTheme.typography.h6,
modifier = Modifier.padding(16.dp)
)

LazyColumn(
modifier = Modifier.fillMaxWidth(),
contentPadding = PaddingValues(16.dp)
) {
items(scanResults.withIndex().toList()) { (index, peripheral) ->
Text(
text = "[$index] ${peripheral.identifier} [${peripheral.address}]",
style = MaterialTheme.typography.body1,
modifier = Modifier
.padding(8.dp)
.clickable {
selectedDevice = peripheral
}
)
}
}
} else {
Text(
text = "No devices found.",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)
}

selectedDevice?.let { peripheral ->
Text(
text = "Connecting to ${peripheral.identifier} [${peripheral.address}]",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

Button(
onClick = {
CoroutineScope(Dispatchers.Main).launch {
peripheral.connect()
peripheral.notify(BluetoothUUID("0000180f-0000-1000-8000-00805f9b34fb"), BluetoothUUID("00002a19-0000-1000-8000-00805f9b34fb")).collect {
Log.d("SimpleBLE", "Received notification: ${it.joinToString("")}")
}
}
// if (!isConnected) {
// peripheral.connect()
// isConnected = true
// mtu = peripheral.mtu
// } else {
// peripheral.disconnect()
// isConnected = false
// mtu = 0
// }
},
modifier = Modifier.padding(16.dp)
) {
Text(text = if (isConnected) "Disconnect" else "Connect")
}

if (isConnected) {
Text(
text = "Successfully connected.",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

Text(
text = "MTU: ${peripheral.mtu}",
style = MaterialTheme.typography.body1,
modifier = Modifier.padding(16.dp)
)

// peripheral.services.forEach { service ->
// Text(
// text = "Service: ${service.uuid}",
// style = MaterialTheme.typography.body1,
// modifier = Modifier.padding(16.dp)
// )
//
// service.characteristics.forEach { characteristic ->
// Text(
// text = "Characteristic: ${characteristic.uuid}",
// style = MaterialTheme.typography.body2,
// modifier = Modifier.padding(start = 32.dp)
// )
//
// Text(
// text = "Capabilities: ${characteristic.capabilities.joinToString(", ")}",
// style = MaterialTheme.typography.body2,
// modifier = Modifier.padding(start = 32.dp)
// )
//
// characteristic.descriptors.forEach { descriptor ->
// Text(
// text = "Descriptor: ${descriptor.uuid}",
// style = MaterialTheme.typography.body2,
// modifier = Modifier.padding(start = 48.dp)
// )
// }
// }
// }
}
}
}
}
10 changes: 9 additions & 1 deletion simpleble/src/backends/plain/PeripheralBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,15 @@ void PeripheralBase::write_command(BluetoothUUID const& service, BluetoothUUID c
ByteArray const& data) {}

void PeripheralBase::notify(BluetoothUUID const& service, BluetoothUUID const& characteristic,
std::function<void(ByteArray payload)> callback) {}
std::function<void(ByteArray payload)> callback) {
if (callback) {
task_runner_.dispatch([callback]() {
callback("Hello from notify");
return 1s;
}, 1s);

}
}

void PeripheralBase::indicate(BluetoothUUID const& service, BluetoothUUID const& characteristic,
std::function<void(ByteArray payload)> callback) {}
Expand Down
Loading

0 comments on commit 410d6a4

Please sign in to comment.