This commit is contained in:
Gilles Boccon-Gibod
2024-09-24 17:15:53 -07:00
parent 55f99e6887
commit c91695c23a
6 changed files with 150 additions and 115 deletions

View File

@@ -1109,7 +1109,7 @@ class Central(Connection.Listener):
transport, transport,
peripheral_address, peripheral_address,
classic, classic,
role_factory, scenario_factory,
mode_factory, mode_factory,
connection_interval, connection_interval,
phy, phy,
@@ -1122,7 +1122,7 @@ class Central(Connection.Listener):
self.transport = transport self.transport = transport
self.peripheral_address = peripheral_address self.peripheral_address = peripheral_address
self.classic = classic self.classic = classic
self.role_factory = role_factory self.scenario_factory = scenario_factory
self.mode_factory = mode_factory self.mode_factory = mode_factory
self.authenticate = authenticate self.authenticate = authenticate
self.encrypt = encrypt or authenticate self.encrypt = encrypt or authenticate
@@ -1175,7 +1175,7 @@ class Central(Connection.Listener):
DEFAULT_CENTRAL_NAME, central_address, hci_source, hci_sink DEFAULT_CENTRAL_NAME, central_address, hci_source, hci_sink
) )
mode = self.mode_factory(self.device) mode = self.mode_factory(self.device)
role = self.role_factory(mode) scenario = self.scenario_factory(mode)
self.device.classic_enabled = self.classic self.device.classic_enabled = self.classic
# Set up a pairing config factory with minimal requirements. # Set up a pairing config factory with minimal requirements.
@@ -1256,7 +1256,7 @@ class Central(Connection.Listener):
await mode.on_connection(self.connection) await mode.on_connection(self.connection)
await role.run() await scenario.run()
await asyncio.sleep(DEFAULT_LINGER_TIME) await asyncio.sleep(DEFAULT_LINGER_TIME)
await self.connection.disconnect() await self.connection.disconnect()
@@ -1287,7 +1287,7 @@ class Peripheral(Device.Listener, Connection.Listener):
def __init__( def __init__(
self, self,
transport, transport,
role_factory, scenario_factory,
mode_factory, mode_factory,
classic, classic,
extended_data_length, extended_data_length,
@@ -1295,11 +1295,11 @@ class Peripheral(Device.Listener, Connection.Listener):
): ):
self.transport = transport self.transport = transport
self.classic = classic self.classic = classic
self.role_factory = role_factory self.scenario_factory = scenario_factory
self.mode_factory = mode_factory self.mode_factory = mode_factory
self.extended_data_length = extended_data_length self.extended_data_length = extended_data_length
self.role_switch = role_switch self.role_switch = role_switch
self.role = None self.scenario = None
self.mode = None self.mode = None
self.device = None self.device = None
self.connection = None self.connection = None
@@ -1319,7 +1319,7 @@ class Peripheral(Device.Listener, Connection.Listener):
) )
self.device.listener = self self.device.listener = self
self.mode = self.mode_factory(self.device) self.mode = self.mode_factory(self.device)
self.role = self.role_factory(self.mode) self.scenario = self.scenario_factory(self.mode)
self.device.classic_enabled = self.classic self.device.classic_enabled = self.classic
# Set up a pairing config factory with minimal requirements. # Set up a pairing config factory with minimal requirements.
@@ -1356,7 +1356,7 @@ class Peripheral(Device.Listener, Connection.Listener):
print_connection(self.connection) print_connection(self.connection)
await self.mode.on_connection(self.connection) await self.mode.on_connection(self.connection)
await self.role.run() await self.scenario.run()
await asyncio.sleep(DEFAULT_LINGER_TIME) await asyncio.sleep(DEFAULT_LINGER_TIME)
def on_connection(self, connection): def on_connection(self, connection):
@@ -1385,7 +1385,7 @@ class Peripheral(Device.Listener, Connection.Listener):
def on_disconnection(self, reason): def on_disconnection(self, reason):
logging.info(color(f'!!! Disconnection: reason={reason}', 'red')) logging.info(color(f'!!! Disconnection: reason={reason}', 'red'))
self.connection = None self.connection = None
self.role.reset() self.scenario.reset()
if self.classic: if self.classic:
AsyncRunner.spawn(self.device.set_discoverable(True)) AsyncRunner.spawn(self.device.set_discoverable(True))
@@ -1467,13 +1467,13 @@ def create_mode_factory(ctx, default_mode):
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
def create_role_factory(ctx, default_role): def create_scenario_factory(ctx, default_scenario):
role = ctx.obj['role'] scenario = ctx.obj['scenario']
if role is None: if scenario is None:
role = default_role scenarion = default_scenario
def create_role(packet_io): def create_scenario(packet_io):
if role == 'sender': if scenario == 'send':
return Sender( return Sender(
packet_io, packet_io,
start_delay=ctx.obj['start_delay'], start_delay=ctx.obj['start_delay'],
@@ -1484,10 +1484,10 @@ def create_role_factory(ctx, default_role):
packet_count=ctx.obj['packet_count'], packet_count=ctx.obj['packet_count'],
) )
if role == 'receiver': if scenario == 'receive':
return Receiver(packet_io, ctx.obj['linger']) return Receiver(packet_io, ctx.obj['linger'])
if role == 'ping': if scenario == 'ping':
return Ping( return Ping(
packet_io, packet_io,
start_delay=ctx.obj['start_delay'], start_delay=ctx.obj['start_delay'],
@@ -1498,12 +1498,12 @@ def create_role_factory(ctx, default_role):
packet_count=ctx.obj['packet_count'], packet_count=ctx.obj['packet_count'],
) )
if role == 'pong': if scenario == 'pong':
return Pong(packet_io, ctx.obj['linger']) return Pong(packet_io, ctx.obj['linger'])
raise ValueError('invalid role') raise ValueError('invalid scenario')
return create_role return create_scenario
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -1511,7 +1511,7 @@ def create_role_factory(ctx, default_role):
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@click.group() @click.group()
@click.option('--device-config', metavar='FILENAME', help='Device configuration file') @click.option('--device-config', metavar='FILENAME', help='Device configuration file')
@click.option('--role', type=click.Choice(['sender', 'receiver', 'ping', 'pong'])) @click.option('--scenario', type=click.Choice(['send', 'receive', 'ping', 'pong']))
@click.option( @click.option(
'--mode', '--mode',
type=click.Choice( type=click.Choice(
@@ -1606,7 +1606,7 @@ def create_role_factory(ctx, default_role):
metavar='SIZE', metavar='SIZE',
type=click.IntRange(8, 8192), type=click.IntRange(8, 8192),
default=500, default=500,
help='Packet size (client or ping role)', help='Packet size (send or ping scenario)',
) )
@click.option( @click.option(
'--packet-count', '--packet-count',
@@ -1614,7 +1614,7 @@ def create_role_factory(ctx, default_role):
metavar='COUNT', metavar='COUNT',
type=int, type=int,
default=10, default=10,
help='Packet count (client or ping role)', help='Packet count (send or ping scenario)',
) )
@click.option( @click.option(
'--start-delay', '--start-delay',
@@ -1622,7 +1622,7 @@ def create_role_factory(ctx, default_role):
metavar='SECONDS', metavar='SECONDS',
type=int, type=int,
default=1, default=1,
help='Start delay (client or ping role)', help='Start delay (send or ping scenario)',
) )
@click.option( @click.option(
'--repeat', '--repeat',
@@ -1630,7 +1630,7 @@ def create_role_factory(ctx, default_role):
type=int, type=int,
default=0, default=0,
help=( help=(
'Repeat the run N times (client and ping roles)' 'Repeat the run N times (send and ping scenario)'
'(0, which is the fault, to run just once) ' '(0, which is the fault, to run just once) '
), ),
) )
@@ -1654,13 +1654,13 @@ def create_role_factory(ctx, default_role):
@click.option( @click.option(
'--linger', '--linger',
is_flag=True, is_flag=True,
help="Don't exit at the end of a run (server and pong roles)", help="Don't exit at the end of a run (receive and pong scenarios)",
) )
@click.pass_context @click.pass_context
def bench( def bench(
ctx, ctx,
device_config, device_config,
role, scenario,
mode, mode,
att_mtu, att_mtu,
extended_data_length, extended_data_length,
@@ -1686,7 +1686,7 @@ def bench(
): ):
ctx.ensure_object(dict) ctx.ensure_object(dict)
ctx.obj['device_config'] = device_config ctx.obj['device_config'] = device_config
ctx.obj['role'] = role ctx.obj['scenario'] = scenario
ctx.obj['mode'] = mode ctx.obj['mode'] = mode
ctx.obj['att_mtu'] = att_mtu ctx.obj['att_mtu'] = att_mtu
ctx.obj['rfcomm_channel'] = rfcomm_channel ctx.obj['rfcomm_channel'] = rfcomm_channel
@@ -1740,7 +1740,7 @@ def central(
ctx, transport, peripheral_address, connection_interval, phy, authenticate, encrypt ctx, transport, peripheral_address, connection_interval, phy, authenticate, encrypt
): ):
"""Run as a central (initiates the connection)""" """Run as a central (initiates the connection)"""
role_factory = create_role_factory(ctx, 'sender') scenario_factory = create_scenario_factory(ctx, 'send')
mode_factory = create_mode_factory(ctx, 'gatt-client') mode_factory = create_mode_factory(ctx, 'gatt-client')
classic = ctx.obj['classic'] classic = ctx.obj['classic']
@@ -1749,7 +1749,7 @@ def central(
transport, transport,
peripheral_address, peripheral_address,
classic, classic,
role_factory, scenario_factory,
mode_factory, mode_factory,
connection_interval, connection_interval,
phy, phy,
@@ -1767,13 +1767,13 @@ def central(
@click.pass_context @click.pass_context
def peripheral(ctx, transport): def peripheral(ctx, transport):
"""Run as a peripheral (waits for a connection)""" """Run as a peripheral (waits for a connection)"""
role_factory = create_role_factory(ctx, 'receiver') scenario_factory = create_scenario_factory(ctx, 'receive')
mode_factory = create_mode_factory(ctx, 'gatt-server') mode_factory = create_mode_factory(ctx, 'gatt-server')
async def run_peripheral(): async def run_peripheral():
await Peripheral( await Peripheral(
transport, transport,
role_factory, scenario_factory,
mode_factory, mode_factory,
ctx.obj['classic'], ctx.obj['classic'],
ctx.obj['extended_data_length'], ctx.obj['extended_data_length'],

View File

@@ -11,32 +11,44 @@ Usage: bumble-bench [OPTIONS] COMMAND [ARGS]...
Options: Options:
--device-config FILENAME Device configuration file --device-config FILENAME Device configuration file
--role [sender|receiver|ping|pong] --scenario [send|receive|ping|pong]
--mode [gatt-client|gatt-server|l2cap-client|l2cap-server|rfcomm-client|rfcomm-server] --mode [gatt-client|gatt-server|l2cap-client|l2cap-server|rfcomm-client|rfcomm-server]
--att-mtu MTU GATT MTU (gatt-client mode) [23<=x<=517] --att-mtu MTU GATT MTU (gatt-client mode) [23<=x<=517]
--extended-data-length TEXT Request a data length upon connection, --extended-data-length TEXT Request a data length upon connection,
specified as tx_octets/tx_time specified as tx_octets/tx_time
--rfcomm-channel INTEGER RFComm channel to use --role-switch [central|peripheral]
Request role switch upon connection (central
or peripheral)
--rfcomm-channel INTEGER RFComm channel to use (specify 0 for channel
discovery via SDP)
--rfcomm-uuid TEXT RFComm service UUID to use (ignored if --rfcomm-uuid TEXT RFComm service UUID to use (ignored if
--rfcomm-channel is not 0) --rfcomm-channel is not 0)
--rfcomm-l2cap-mtu INTEGER RFComm L2CAP MTU
--rfcomm-max-frame-size INTEGER
RFComm maximum frame size
--rfcomm-initial-credits INTEGER
RFComm initial credits
--rfcomm-max-credits INTEGER RFComm max credits
--rfcomm-credits-threshold INTEGER
RFComm credits threshold
--l2cap-psm INTEGER L2CAP PSM to use --l2cap-psm INTEGER L2CAP PSM to use
--l2cap-mtu INTEGER L2CAP MTU to use --l2cap-mtu INTEGER L2CAP MTU to use
--l2cap-mps INTEGER L2CAP MPS to use --l2cap-mps INTEGER L2CAP MPS to use
--l2cap-max-credits INTEGER L2CAP maximum number of credits allowed for --l2cap-max-credits INTEGER L2CAP maximum number of credits allowed for
the peer the peer
-s, --packet-size SIZE Packet size (client or ping role) -s, --packet-size SIZE Packet size (send or ping scenario)
[8<=x<=4096] [8<=x<=8192]
-c, --packet-count COUNT Packet count (client or ping role) -c, --packet-count COUNT Packet count (send or ping scenario)
-sd, --start-delay SECONDS Start delay (client or ping role) -sd, --start-delay SECONDS Start delay (send or ping scenario)
--repeat N Repeat the run N times (client and ping --repeat N Repeat the run N times (send and ping
roles)(0, which is the fault, to run just scenario)(0, which is the fault, to run just
once) once)
--repeat-delay SECONDS Delay, in seconds, between repeats --repeat-delay SECONDS Delay, in seconds, between repeats
--pace MILLISECONDS Wait N milliseconds between packets (0, --pace MILLISECONDS Wait N milliseconds between packets (0,
which is the fault, to send as fast as which is the fault, to send as fast as
possible) possible)
--linger Don't exit at the end of a run (server and --linger Don't exit at the end of a run (receive and
pong roles) pong scenarios)
--help Show this message and exit. --help Show this message and exit.
Commands: Commands:
@@ -82,7 +94,7 @@ Device 1 mode | Device 2 mode
Device 1 role | Device 2 role Device 1 role | Device 2 role
--------------|-------------- --------------|--------------
``sender`` | ``receiver`` ``send`` | ``receive``
``ping`` | ``pong`` ``ping`` | ``pong``
@@ -137,12 +149,12 @@ the other on `usb:1`, and two consoles/terminals. We will run a command in each.
!!! example "Ping/Pong Latency" !!! example "Ping/Pong Latency"
In the first console/terminal: In the first console/terminal:
``` ```
$ bumble-bench --role pong peripheral usb:0 $ bumble-bench --scenario pong peripheral usb:0
``` ```
In the second console/terminal: In the second console/terminal:
``` ```
$ bumble-bench --role ping central usb:1 $ bumble-bench --scenario ping central usb:1
``` ```
!!! example "Reversed modes with GATT and custom connection interval" !!! example "Reversed modes with GATT and custom connection interval"
@@ -170,10 +182,10 @@ the other on `usb:1`, and two consoles/terminals. We will run a command in each.
!!! example "Reversed roles with L2CAP" !!! example "Reversed roles with L2CAP"
In the first console/terminal: In the first console/terminal:
``` ```
$ bumble-bench --mode l2cap-client --role sender peripheral usb:0 $ bumble-bench --mode l2cap-client --scenario send peripheral usb:0
``` ```
In the second console/terminal: In the second console/terminal:
``` ```
$ bumble-bench --mode l2cap-server --role receiver central usb:1 $ bumble-bench --mode l2cap-server --scenario receive central usb:1
``` ```

View File

@@ -17,86 +17,113 @@ package com.github.google.bumble.btbench;
import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager; import android.bluetooth.BluetoothManager;
import android.content.Context; import android.content.Context;
import android.renderscript.RSInvalidStateException;
import android.util.Log;
import com.google.android.mobly.snippet.Snippet; import com.google.android.mobly.snippet.Snippet;
import com.google.android.mobly.snippet.rpc.Rpc; import com.google.android.mobly.snippet.rpc.Rpc;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
public class AutomationSnippet implements Snippet { public class AutomationSnippet implements Snippet {
private static final String TAG = "btbench.snippet"; private static final String TAG = "btbench.snippet";
private final BluetoothAdapter mBluetoothAdapter; private final BluetoothAdapter mBluetoothAdapter;
private AppViewModel rfcommServerModel; private final Context mContext;
private RfcommServer rfcommServer;
private AppViewModel l2capServerModel;
private L2capServer l2capServer;
public AutomationSnippet() { public AutomationSnippet() {
Context context = ApplicationProvider.getApplicationContext(); mContext = ApplicationProvider.getApplicationContext();
BluetoothManager bluetoothManager = context.getSystemService(BluetoothManager.class); BluetoothManager bluetoothManager = mContext.getSystemService(BluetoothManager.class);
mBluetoothAdapter = bluetoothManager.getAdapter(); mBluetoothAdapter = bluetoothManager.getAdapter();
if (mBluetoothAdapter == null) { if (mBluetoothAdapter == null) {
throw new RuntimeException("bluetooth not supported"); throw new RuntimeException("bluetooth not supported");
} }
} }
private static JSONObject throughputStats(AppViewModel model) throws JSONException { private void runScenario(AppViewModel model, String mode, String scenario) {
Mode runner;
switch (mode) {
case "rfcomm-client":
runner = new RfcommClient(model, mBluetoothAdapter, (PacketIO packetIO) -> createIoClient(model, scenario, packetIO));
break;
case "rfcomm-server":
runner = new RfcommServer(model, mBluetoothAdapter, (PacketIO packetIO) -> createIoClient(model, scenario, packetIO));
break;
case "l2cap-client":
runner = new L2capClient(model, mBluetoothAdapter, mContext, (PacketIO packetIO) -> createIoClient(model, scenario, packetIO));
break;
case "l2cap-server":
runner = new L2capServer(model, mBluetoothAdapter, (PacketIO packetIO) -> createIoClient(model, scenario, packetIO));
break;
default:
return;
}
runner.run(true);
}
private IoClient createIoClient(AppViewModel model, String scenario, PacketIO packetIO) {
switch (scenario) {
case "send":
return new Sender(model, packetIO);
case "receive":
return new Receiver(model, packetIO);
case "ping":
return new Pinger(model, packetIO);
case "pong":
return new Ponger(model, packetIO);
default:
return null;
}
}
private static JSONObject resultFromModel(AppViewModel model) throws JSONException {
JSONObject result = new JSONObject(); JSONObject result = new JSONObject();
JSONObject stats = new JSONObject(); JSONObject stats = new JSONObject();
result.put("stats", stats); result.put("stats", stats);
JSONObject throughputStats = new JSONObject(); JSONObject throughputStats = new JSONObject();
stats.put("throughput", throughputStats); stats.put("throughput", throughputStats);
throughputStats.put("average", model.getThroughput()); throughputStats.put("average", model.getThroughput());
JSONObject rttStats = new JSONObject();
stats.put("rtt", rttStats);
rttStats.put("compound", model.getStats());
return result; return result;
} }
@Rpc(description = "Run an RFComm client throughput test") @Rpc(description = "Run a scenario in RFComm Client mode")
public JSONObject runRfcommClient(String peerBluetoothAddress, int packetCount, int packetSize) throws JSONException { public JSONObject runRfcommClient(String scenario, String peerBluetoothAddress, int packetCount, int packetSize, int packetInterval) throws JSONException {
assert(mBluetoothAdapter != null); assert (mBluetoothAdapter != null);
AppViewModel model = new AppViewModel(); AppViewModel model = new AppViewModel();
model.setPeerBluetoothAddress(peerBluetoothAddress); model.setPeerBluetoothAddress(peerBluetoothAddress);
model.setSenderPacketCount(packetCount); model.setSenderPacketCount(packetCount);
model.setSenderPacketSize(packetSize); model.setSenderPacketSize(packetSize);
model.setSenderPacketInterval(packetInterval);
//RfcommClient rfCommClient = new RfcommClient(model, mBluetoothAdapter); runScenario(model, "rfcomm-client", scenario);
//rfCommClient.run(true); return resultFromModel(model);
return throughputStats(model);
} }
@Rpc(description = "Run an L2CAP client throughput test") @Rpc(description = "Run a scenario in L2CAP Client mode")
public JSONObject runL2capClient(String peerBluetoothAddress, int psm, boolean use_2m_phy, int packetCount, int packetSize) throws JSONException { public JSONObject runL2capClient(String scenario, String peerBluetoothAddress, int psm, boolean use_2m_phy, int packetCount, int packetSize, int packetInterval) throws JSONException {
assert(mBluetoothAdapter != null); assert (mBluetoothAdapter != null);
AppViewModel model = new AppViewModel(); AppViewModel model = new AppViewModel();
model.setPeerBluetoothAddress(peerBluetoothAddress); model.setPeerBluetoothAddress(peerBluetoothAddress);
model.setL2capPsm(psm); model.setL2capPsm(psm);
model.setUse2mPhy(use_2m_phy); model.setUse2mPhy(use_2m_phy);
model.setSenderPacketCount(packetCount); model.setSenderPacketCount(packetCount);
model.setSenderPacketSize(packetSize); model.setSenderPacketSize(packetSize);
model.setSenderPacketInterval(packetInterval);
Context context = ApplicationProvider.getApplicationContext(); runScenario(model, "l2cap-client", scenario);
//L2capClient l2capClient = new L2capClient(model, mBluetoothAdapter, context); return resultFromModel(model);
//l2capClient.run(true);
return throughputStats(model);
}
@Rpc(description = "Run an RFComm server")
public JSONObject runRfcommServer() throws JSONException {
assert(mBluetoothAdapter != null);
if (rfcommServerModel != null) {
rfcommServerModel.abort();
rfcommServerModel = null;
rfcommServer = null;
}
rfcommServerModel = new AppViewModel();
//rfcommServer = new RfcommServer(rfcommServerModel, mBluetoothAdapter);
//rfcommServer.run(true);
return new JSONObject();
} }
@Override @Override

View File

@@ -168,12 +168,25 @@ class MainActivity : ComponentActivity() {
appViewModel.senderPacketInterval = packetInterval appViewModel.senderPacketInterval = packetInterval
} }
appViewModel.updateSenderPacketSizeSlider() appViewModel.updateSenderPacketSizeSlider()
intent.getStringExtra("scenario")?.let {
when (it) {
"send" -> appViewModel.scenario = SEND_SCENARIO
"receive" -> appViewModel.scenario = RECEIVE_SCENARIO
"ping" -> appViewModel.scenario = PING_SCENARIO
"pong" -> appViewModel.scenario = PONG_SCENARIO
}
}
intent.getStringExtra("mode")?.let {
when (it) {
"rfcomm-client" -> appViewModel.mode = RFCOMM_CLIENT_MODE
"rfcomm-server" -> appViewModel.mode = RFCOMM_SERVER_MODE
"l2cap-client" -> appViewModel.mode = L2CAP_CLIENT_MODE
"l2cap-server" -> appViewModel.mode = L2CAP_SERVER_MODE
}
}
intent.getStringExtra("autostart")?.let { intent.getStringExtra("autostart")?.let {
when (it) { when (it) {
"rfcomm-client" -> runRfcommClient() "run-scenario" -> runScenario()
"rfcomm-server" -> runRfcommServer()
"l2cap-client" -> runL2capClient()
"l2cap-server" -> runL2capServer()
"scan-start" -> runScan(true) "scan-start" -> runScan(true)
"stop-start" -> runScan(false) "stop-start" -> runScan(false)
} }
@@ -200,6 +213,11 @@ class MainActivity : ComponentActivity() {
runner.run(false) runner.run(false)
} }
private fun runScan(startScan: Boolean) {
val scan = bluetoothAdapter?.let { Scan(it) }
scan?.run(startScan)
}
private fun createIoClient(packetIo: PacketIO): IoClient { private fun createIoClient(packetIo: PacketIO): IoClient {
return when (appViewModel.scenario) { return when (appViewModel.scenario) {
SEND_SCENARIO -> Sender(appViewModel, packetIo) SEND_SCENARIO -> Sender(appViewModel, packetIo)
@@ -210,30 +228,6 @@ class MainActivity : ComponentActivity() {
} }
} }
private fun runRfcommClient() {
// val rfcommClient = bluetoothAdapter?.let { RfcommClient(appViewModel, it) }
// rfcommClient?.run()
}
private fun runRfcommServer() {
// val rfcommServer = bluetoothAdapter?.let { RfcommServer(appViewModel, it) }
// rfcommServer?.run()
}
private fun runL2capClient() {
// val l2capClient = bluetoothAdapter?.let { L2capClient(appViewModel, it, baseContext) }
// l2capClient?.run()
}
private fun runL2capServer() {
// val l2capServer = bluetoothAdapter?.let { L2capServer(appViewModel, it) }
// l2capServer?.run()
}
private fun runScan(startScan: Boolean) {
val scan = bluetoothAdapter?.let { Scan(it) }
scan?.run(startScan)
}
@SuppressLint("MissingPermission") @SuppressLint("MissingPermission")
fun becomeDiscoverable() { fun becomeDiscoverable() {

View File

@@ -64,6 +64,7 @@ class SocketClient(
try { try {
ioClient.run() ioClient.run()
socket.close()
} catch (error: IOException) { } catch (error: IOException) {
Log.info("run ended abruptly") Log.info("run ended abruptly")
} }

View File

@@ -23,6 +23,7 @@ public class HciProxy {
HciHal hciHal = HciHal.create(new HciHalCallback() { HciHal hciHal = HciHal.create(new HciHalCallback() {
@Override @Override
public void onPacket(HciPacket.Type type, byte[] packet) { public void onPacket(HciPacket.Type type, byte[] packet) {
Log.d(TAG, String.format("CONTROLLER->HOST: type=%s, size=%d", type, packet.length));
mServer.sendPacket(type, packet); mServer.sendPacket(type, packet);
switch (type) { switch (type) {
@@ -83,7 +84,7 @@ public class HciProxy {
@Override @Override
public void onPacket(HciPacket.Type type, byte[] packet) { public void onPacket(HciPacket.Type type, byte[] packet) {
Log.d(TAG, String.format("onPacket: type=%s, size=%d", type, packet.length)); Log.d(TAG, String.format("HOST->CONTROLLER: type=%s, size=%d", type, packet.length));
hciHal.sendPacket(type, packet); hciHal.sendPacket(type, packet);
switch (type) { switch (type) {