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

Commit 13d0b7c4 authored by Michal Belusiak's avatar Michal Belusiak
Browse files

le_periodic_sync_manager: Handle command statuses

If commands are not executed successfully, we have to
recover from that state by inform upper layer and
advance the request (remove the current).

Bug: 330492580
Bug: 331167629
Test: atest PeriodicSyncManagerTest --host
Change-Id: Id3cdb143d832d6b01d126fcd48f2000c6533c306
parent 91c728ab
Loading
Loading
Loading
Loading
+74 −6
Original line number Original line Diff line number Diff line
@@ -145,7 +145,10 @@ class PeriodicSyncManager {
      log::warn("[PSync]: Sync state is pending");
      log::warn("[PSync]: Sync state is pending");
      le_scanning_interface_->EnqueueCommand(
      le_scanning_interface_->EnqueueCommand(
          hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(),
          hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(),
          handler_->BindOnceOn(this, &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus));
          handler_->BindOnceOn(
              this,
              &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus<
                  LePeriodicAdvertisingCreateSyncCancelCompleteView>));
    } else if (periodic_sync->sync_state == PERIODIC_SYNC_STATE_IDLE) {
    } else if (periodic_sync->sync_state == PERIODIC_SYNC_STATE_IDLE) {
      log::debug("[PSync]: Removing Sync request from queue");
      log::debug("[PSync]: Removing Sync request from queue");
      CleanUpRequest(adv_sid, address);
      CleanUpRequest(adv_sid, address);
@@ -207,9 +210,62 @@ class PeriodicSyncManager {
            check_complete<LeSetDefaultPeriodicAdvertisingSyncTransferParametersCompleteView>));
            check_complete<LeSetDefaultPeriodicAdvertisingSyncTransferParametersCompleteView>));
  }
  }


  void HandlePeriodicAdvertisingCreateSyncStatus(CommandStatusView) {}
  template <class View>
  void HandlePeriodicAdvertisingCreateSyncStatus(CommandStatusView view) {
    if (!IS_FLAG_ENABLED(leaudio_broadcast_assistant_handle_command_statuses)) {
      return;
    }
    ASSERT(view.IsValid());
    auto status_view = View::Create(view);
    ASSERT(status_view.IsValid());
    auto status = status_view.GetStatus();
    if (status != ErrorCode::SUCCESS) {
      auto& request = pending_sync_requests_.front();
      request.sync_timeout_alarm.Cancel();
      log::warn(
          "Got a Command status {}, status {}, SID={:04X}, bd_addr={}",
          OpCodeText(view.GetCommandOpCode()),
          ErrorCodeText(status),
          request.advertiser_sid,
          ADDRESS_TO_LOGGABLE_CSTR(request.address_with_type));

      uint8_t adv_sid = request.advertiser_sid;
      AddressWithType address_with_type = request.address_with_type;
      auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, adv_sid);
      callbacks_->OnPeriodicSyncStarted(
          sync->request_id,
          (uint8_t)status,
          0,
          sync->advertiser_sid,
          request.address_with_type,
          0,
          0);
      periodic_syncs_.erase(sync);
      AdvanceRequest();
    }
  }


  void HandlePeriodicAdvertisingCreateSyncCancelStatus(CommandCompleteView) {}
  template <class View>
  void HandlePeriodicAdvertisingCreateSyncCancelStatus(CommandCompleteView view) {
    if (!IS_FLAG_ENABLED(leaudio_broadcast_assistant_handle_command_statuses)) {
      return;
    }
    ASSERT(view.IsValid());
    auto status_view = View::Create(view);
    ASSERT(status_view.IsValid());
    auto status = status_view.GetStatus();
    if (status != ErrorCode::SUCCESS) {
      auto& request = pending_sync_requests_.front();
      request.sync_timeout_alarm.Cancel();
      log::warn(
          "Got a Command complete {}, status {}, SID={:04X}, bd_addr={}",
          OpCodeText(view.GetCommandOpCode()),
          ErrorCodeText(status),
          request.advertiser_sid,
          ADDRESS_TO_LOGGABLE_CSTR(request.address_with_type));
      AdvanceRequest();
    }
  }


  template <class View>
  template <class View>
  void HandlePeriodicAdvertisingSyncTransferComplete(uint16_t connection_handle, CommandCompleteView view) {
  void HandlePeriodicAdvertisingSyncTransferComplete(uint16_t connection_handle, CommandCompleteView view) {
@@ -401,7 +457,10 @@ class PeriodicSyncManager {
    auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, adv_sid);
    auto sync = GetSyncFromAddressWithTypeAndSid(address_with_type, adv_sid);
    le_scanning_interface_->EnqueueCommand(
    le_scanning_interface_->EnqueueCommand(
        hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(),
        hci::LePeriodicAdvertisingCreateSyncCancelBuilder::Create(),
        handler_->BindOnceOn(this, &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus));
        handler_->BindOnceOn(
            this,
            &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncCancelStatus<
                LePeriodicAdvertisingCreateSyncCancelCompleteView>));
    int status = static_cast<int>(ErrorCode::ADVERTISING_TIMEOUT);
    int status = static_cast<int>(ErrorCode::ADVERTISING_TIMEOUT);
    callbacks_->OnPeriodicSyncStarted(
    callbacks_->OnPeriodicSyncStarted(
        sync->request_id, status, 0, sync->advertiser_sid, request.address_with_type, 0, 0);
        sync->request_id, status, 0, sync->advertiser_sid, request.address_with_type, 0, 0);
@@ -501,8 +560,17 @@ class PeriodicSyncManager {
        static_cast<AdvertisingAddressType>(address_with_type.GetAddressType());
        static_cast<AdvertisingAddressType>(address_with_type.GetAddressType());
    le_scanning_interface_->EnqueueCommand(
    le_scanning_interface_->EnqueueCommand(
        hci::LePeriodicAdvertisingCreateSyncBuilder::Create(
        hci::LePeriodicAdvertisingCreateSyncBuilder::Create(
            options, sid, advertisingAddressType, address_with_type.GetAddress(), skip, timeout, sync_cte_type),
            options,
        handler_->BindOnceOn(this, &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncStatus));
            sid,
            advertisingAddressType,
            address_with_type.GetAddress(),
            skip,
            timeout,
            sync_cte_type),
        handler_->BindOnceOn(
            this,
            &PeriodicSyncManager::HandlePeriodicAdvertisingCreateSyncStatus<
                LePeriodicAdvertisingCreateSyncStatusView>));
  }
  }


  void HandleNextRequest() {
  void HandleNextRequest() {
+178 −0
Original line number Original line Diff line number Diff line
@@ -634,6 +634,184 @@ TEST_F_WITH_FLAGS(
  sync_handler();
  sync_handler();
}
}


TEST_F_WITH_FLAGS(
    PeriodicSyncManagerTest,
    handle_advertising_sync_established_after_create_command_error_test,
    REQUIRES_FLAGS_ENABLED(
        ACONFIG_FLAG(TEST_BT, leaudio_broadcast_assistant_handle_command_statuses))) {
  uint16_t sync_handle = 0x12;
  Address address;
  Address::FromString("00:11:22:33:44:55", address);
  AddressWithType address_with_type = AddressWithType(address, AddressType::PUBLIC_DEVICE_ADDRESS);

  // First request which will finish with error
  int request_id_1 = 0x01;
  uint8_t advertiser_sid_1 = 0x02;
  PeriodicSyncStates request{
      .request_id = request_id_1,
      .advertiser_sid = advertiser_sid_1,
      .address_with_type = address_with_type,
      .sync_handle = sync_handle,
      .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
  };
  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
  periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
  auto packet =
      test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
  auto temp_view =
      LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
  ASSERT_TRUE(temp_view.IsValid());

  EXPECT_CALL(
      mock_callbacks_,
      OnPeriodicSyncStarted(
          request_id_1,
          static_cast<uint8_t>(ErrorCode::MEMORY_CAPACITY_EXCEEDED),
          _,
          advertiser_sid_1,
          _,
          _,
          _))
      .Times(1);

  // Get command status
  test_le_scanning_interface_->CommandStatusCallback(
      LePeriodicAdvertisingCreateSyncStatusBuilder::Create(
          ErrorCode::MEMORY_CAPACITY_EXCEEDED, 0x00));

  // Second request
  int request_id_2 = 0x02;
  uint8_t advertiser_sid_2 = 0x03;
  request.request_id = request_id_2;
  request.advertiser_sid = advertiser_sid_2;
  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
  periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
  packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
  temp_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
  ASSERT_TRUE(temp_view.IsValid());

  // Get command status
  test_le_scanning_interface_->CommandStatusCallback(
      LePeriodicAdvertisingCreateSyncStatusBuilder::Create(ErrorCode::SUCCESS, 0x00));

  EXPECT_CALL(
      mock_callbacks_,
      OnPeriodicSyncStarted(
          request_id_2, static_cast<uint8_t>(ErrorCode::SUCCESS), _, advertiser_sid_2, _, _, _))
      .Times(1);

  // Get LePeriodicAdvertisingSyncEstablished
  auto builder = LePeriodicAdvertisingSyncEstablishedBuilder::Create(
      ErrorCode::SUCCESS,
      sync_handle,
      advertiser_sid_2,
      address_with_type.GetAddressType(),
      address_with_type.GetAddress(),
      SecondaryPhyType::LE_1M,
      0xFF,
      ClockAccuracy::PPM_250);
  auto event_view = LePeriodicAdvertisingSyncEstablishedView::Create(
      LeMetaEventView::Create(EventView::Create(GetPacketView(std::move(builder)))));
  periodic_sync_manager_->HandleLePeriodicAdvertisingSyncEstablished(event_view);

  sync_handler();
}

TEST_F_WITH_FLAGS(
    PeriodicSyncManagerTest,
    handle_advertising_sync_established_after_cancel_command_error_test,
    REQUIRES_FLAGS_ENABLED(
        ACONFIG_FLAG(TEST_BT, leaudio_broadcast_assistant_handle_command_statuses))) {
  uint16_t sync_handle = 0x12;
  Address address;
  Address::FromString("00:11:22:33:44:55", address);
  AddressWithType address_with_type = AddressWithType(address, AddressType::PUBLIC_DEVICE_ADDRESS);

  // First request which will finish with timeout error
  uint8_t advertiser_sid_1 = 0x02;
  int request_id_1 = 0x01;
  PeriodicSyncStates request{
      .request_id = request_id_1,
      .advertiser_sid = advertiser_sid_1,
      .address_with_type = address_with_type,
      .sync_handle = sync_handle,
      .sync_state = PeriodicSyncState::PERIODIC_SYNC_STATE_IDLE,
  };
  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
  periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
  auto packet =
      test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
  auto temp_view =
      LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
  ASSERT_TRUE(temp_view.IsValid());

  // Get command status
  test_le_scanning_interface_->CommandStatusCallback(
      LePeriodicAdvertisingCreateSyncStatusBuilder::Create(ErrorCode::SUCCESS, 0x00));

  EXPECT_CALL(
      mock_callbacks_,
      OnPeriodicSyncStarted(
          request_id_1,
          static_cast<uint8_t>(ErrorCode::ADVERTISING_TIMEOUT),
          _,
          advertiser_sid_1,
          _,
          _,
          _))
      .Times(1);

  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
  periodic_sync_manager_->OnStartSyncTimeout();
  packet =
      test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL);
  auto temp_view2 =
      LePeriodicAdvertisingCreateSyncCancelView::Create(LeScanningCommandView::Create(packet));
  ASSERT_TRUE(temp_view2.IsValid());

  // Get command status
  test_le_scanning_interface_->CommandCompleteCallback(
      LePeriodicAdvertisingCreateSyncCancelCompleteBuilder::Create(
          0x00, ErrorCode::COMMAND_DISALLOWED));

  // Second request
  int request_id_2 = 0x02;
  uint8_t advertiser_sid_2 = 0x03;
  request.request_id = request_id_2;
  request.advertiser_sid = advertiser_sid_2;
  ASSERT_NO_FATAL_FAILURE(test_le_scanning_interface_->SetCommandFuture());
  periodic_sync_manager_->StartSync(request, 0x04, 0x0A);
  packet = test_le_scanning_interface_->GetCommand(OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC);
  temp_view = LePeriodicAdvertisingCreateSyncView::Create(LeScanningCommandView::Create(packet));
  ASSERT_TRUE(temp_view.IsValid());

  // Get command status
  test_le_scanning_interface_->CommandStatusCallback(
      LePeriodicAdvertisingCreateSyncStatusBuilder::Create(ErrorCode::SUCCESS, 0x00));

  EXPECT_CALL(
      mock_callbacks_,
      OnPeriodicSyncStarted(
          request_id_2, static_cast<uint8_t>(ErrorCode::SUCCESS), _, advertiser_sid_2, _, _, _))
      .Times(1);

  // Get LePeriodicAdvertisingSyncEstablished
  auto builder2 = LePeriodicAdvertisingSyncEstablishedBuilder::Create(
      ErrorCode::SUCCESS,
      sync_handle,
      advertiser_sid_2,
      address_with_type.GetAddressType(),
      address_with_type.GetAddress(),
      SecondaryPhyType::LE_1M,
      0xFF,
      ClockAccuracy::PPM_250);
  auto event_view = LePeriodicAdvertisingSyncEstablishedView::Create(
      LeMetaEventView::Create(EventView::Create(GetPacketView(std::move(builder2)))));
  periodic_sync_manager_->HandleLePeriodicAdvertisingSyncEstablished(event_view);

  sync_handler();
}

TEST_F(PeriodicSyncManagerTest, handle_periodic_advertising_report_test) {
TEST_F(PeriodicSyncManagerTest, handle_periodic_advertising_report_test) {
  uint16_t sync_handle = 0x12;
  uint16_t sync_handle = 0x12;
  uint8_t advertiser_sid = 0x02;
  uint8_t advertiser_sid = 0x02;