Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 553c471e authored by Charlie Boutier's avatar Charlie Boutier
Browse files

Pandora: Add ResetBluetooth to Host

Bug: 243412561
Test: atest pts-bot:SM/CEN/KDU/BI-01-C -v
Change-Id: I8d1f03beb60779415b88d271350a359a7324eb61
parent 49ac0baa
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -66,7 +66,7 @@ class IUT:
        # Note: we don't keep a single gRPC channel instance in the IUT class
        # Note: we don't keep a single gRPC channel instance in the IUT class
        # because reset is allowed to close the gRPC server.
        # because reset is allowed to close the gRPC server.
        with grpc.insecure_channel(f'localhost:{self.port}') as channel:
        with grpc.insecure_channel(f'localhost:{self.port}') as channel:
            self._retry(Host(channel).Reset)(wait_for_ready=True)
            self._retry(Host(channel).HardReset)(wait_for_ready=True)


    def __exit__(self, exc_type, exc_value, exc_traceback):
    def __exit__(self, exc_type, exc_value, exc_traceback):
        self._a2dp = None
        self._a2dp = None
+8 −5
Original line number Original line Diff line number Diff line
@@ -11,13 +11,16 @@ import "google/protobuf/empty.proto";
// At startup, the Host must be in BR/EDR connectable mode
// At startup, the Host must be in BR/EDR connectable mode
// (see GAP connectability modes)
// (see GAP connectability modes)
service Host {
service Host {
  // Reset the host.
  // Hard reset the host.
  // **After** responding to this command, the GRPC server should loose
  // **After** responding to this command, the gRPC server should loose
  // all its state.
  // all its state.
  // This is comparable to a process restart or an hardware reset.
  // This is comparable to a process restart or an hardware reset.
  // The GRPC server might take some time to be available after
  // The gRPC server might take some time to be available after
  // this command.
  // this command.
  rpc Reset(google.protobuf.Empty) returns (google.protobuf.Empty);
  rpc HardReset(google.protobuf.Empty) returns (google.protobuf.Empty);
  // Soft reset the host by performing an HCI reset. Previous bonds must
  // not be removed and the gRPC server must not be restarted.
  rpc SoftReset(google.protobuf.Empty) returns (google.protobuf.Empty);
  // Read the local Bluetooth device address.
  // Read the local Bluetooth device address.
  // This should return the same value as a Read BD_ADDR HCI command.
  // This should return the same value as a Read BD_ADDR HCI command.
  rpc ReadLocalAddress(google.protobuf.Empty) returns (ReadLocalAddressResponse);
  rpc ReadLocalAddress(google.protobuf.Empty) returns (ReadLocalAddressResponse);
@@ -56,7 +59,7 @@ message ReadLocalAddressResponse {
// A Token representing an ACL connection.
// A Token representing an ACL connection.
// It's acquired via a Connect on the Host service.
// It's acquired via a Connect on the Host service.
message Connection {
message Connection {
  // Opaque value filled by the GRPC server, must not
  // Opaque value filled by the gRPC server, must not
  // be modified nor crafted.
  // be modified nor crafted.
  bytes cookie = 1;
  bytes cookie = 1;
}
}
+44 −30
Original line number Original line Diff line number Diff line
@@ -35,17 +35,17 @@ import io.grpc.stub.StreamObserver
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancel
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.delay
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import kotlinx.coroutines.launch
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.channels.trySendBlocking
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.runBlocking
import pandora.HostGrpc.HostImplBase
import pandora.HostGrpc.HostImplBase
import pandora.HostProto.*
import pandora.HostProto.*
@@ -80,16 +80,13 @@ class Host(private val context: Context, private val server: Server) : HostImplB
    scope.cancel()
    scope.cancel()
  }
  }


  override fun reset(request: Empty, responseObserver: StreamObserver<Empty>) {
  private suspend fun rebootBluetooth() {
    grpcUnary<Empty>(scope, responseObserver) {
    Log.i(TAG, "rebootBluetooth")
        Log.i(TAG, "reset")

        bluetoothAdapter.clearBluetooth()


    val stateFlow =
    val stateFlow =
          flow
      flow.filter { it.getAction() == BluetoothAdapter.ACTION_STATE_CHANGED }.map {
            .filter { it.getAction() == BluetoothAdapter.ACTION_STATE_CHANGED }
        it.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR)
            .map { it.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR) }
      }


    if (bluetoothAdapter.isEnabled) {
    if (bluetoothAdapter.isEnabled) {
      bluetoothAdapter.disable()
      bluetoothAdapter.disable()
@@ -101,6 +98,15 @@ class Host(private val context: Context, private val server: Server) : HostImplB


    bluetoothAdapter.enable()
    bluetoothAdapter.enable()
    stateFlow.filter { it == BluetoothAdapter.STATE_ON }.first()
    stateFlow.filter { it == BluetoothAdapter.STATE_ON }.first()
  }

  override fun hardReset(request: Empty, responseObserver: StreamObserver<Empty>) {
    grpcUnary<Empty>(scope, responseObserver) {
      Log.i(TAG, "hardReset")

      bluetoothAdapter.clearBluetooth()

      rebootBluetooth()


      // The last expression is the return value.
      // The last expression is the return value.
      Empty.getDefaultInstance()
      Empty.getDefaultInstance()
@@ -111,6 +117,16 @@ class Host(private val context: Context, private val server: Server) : HostImplB
      }
      }
  }
  }


  override fun softReset(request: Empty, responseObserver: StreamObserver<Empty>) {
    grpcUnary<Empty>(scope, responseObserver) {
      Log.i(TAG, "softReset")

      rebootBluetooth()

      Empty.getDefaultInstance()
    }
  }

  override fun readLocalAddress(
  override fun readLocalAddress(
    request: Empty,
    request: Empty,
    responseObserver: StreamObserver<ReadLocalAddressResponse>
    responseObserver: StreamObserver<ReadLocalAddressResponse>
@@ -279,9 +295,7 @@ class Host(private val context: Context, private val server: Server) : HostImplB
      GattInstance(device!!, TRANSPORT_LE, context).waitForState(BluetoothProfile.STATE_CONNECTED)
      GattInstance(device!!, TRANSPORT_LE, context).waitForState(BluetoothProfile.STATE_CONNECTED)
      ConnectLEResponse.newBuilder()
      ConnectLEResponse.newBuilder()
        .setConnection(
        .setConnection(
          Connection.newBuilder()
          Connection.newBuilder().setCookie(ByteString.copyFromUtf8(device.address)).build()
            .setCookie(ByteString.copyFromUtf8(device.address))
            .build()
        )
        )
        .build()
        .build()
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -30,7 +30,7 @@ class ExampleTest(base_test.BaseTestClass):
        self.ref = self.pandora_devices[1]
        self.ref = self.pandora_devices[1]


    def setup_test(self):
    def setup_test(self):
        self.dut.host.Reset()
        self.dut.host.HardReset()
        # TODO: wait for server
        # TODO: wait for server
        time.sleep(3)
        time.sleep(3)