Loading system/stack/btm/btm_ble_multi_adv.cc +58 −8 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ extern void btm_gen_resolvable_private_addr( base::Callback<void(uint8_t[8])> cb); extern fixed_queue_t* btu_general_alarm_queue; constexpr int ADV_DATA_LEN_MAX = 251; struct AdvertisingInstance { uint8_t inst_id; bool in_use; Loading Loading @@ -586,14 +588,60 @@ class BleAdvertisingManagerImpl } VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size()); if (is_scan_rsp) { GetHciInterface()->SetScanResponseData(inst_id, 0x03, 0x01, data.size(), data.data(), cb); } else { GetHciInterface()->SetAdvertisingData(inst_id, 0x03, 0x01, data.size(), data.data(), cb); DivideAndSendData( inst_id, data, cb, base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender, base::Unretained(this), is_scan_rsp)); } void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id, uint8_t operation, uint8_t length, uint8_t* data, MultiAdvCb cb) { if (is_scan_rsp) GetHciInterface()->SetScanResponseData(inst_id, operation, 0x01, length, data, cb); else GetHciInterface()->SetAdvertisingData(inst_id, operation, 0x01, length, data, cb); } using DataSender = base::Callback<void( uint8_t /*inst_id*/, uint8_t /* operation */, uint8_t /* length */, uint8_t* /* data */, MultiAdvCb /* done */)>; void DivideAndSendData(int inst_id, std::vector<uint8_t> data, MultiAdvCb done_cb, DataSender sender) { DivideAndSendDataRecursively(true, inst_id, std::move(data), 0, std::move(done_cb), std::move(sender), 0); } static void DivideAndSendDataRecursively(bool isFirst, int inst_id, std::vector<uint8_t> data, int offset, MultiAdvCb done_cb, DataSender sender, uint8_t status) { constexpr uint8_t INTERMEDIATE = 0x00; // Intermediate fragment of fragmented data constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data int dataSize = (int)data.size(); if (status != 0 || (!isFirst && offset == dataSize)) { /* if we got error writing data, or reached the end of data */ done_cb.Run(status); return; } bool moreThanOnePacket = dataSize - offset > ADV_DATA_LEN_MAX; uint8_t operation = isFirst ? moreThanOnePacket ? FIRST : COMPLETE : moreThanOnePacket ? INTERMEDIATE : LAST; int length = moreThanOnePacket ? ADV_DATA_LEN_MAX : dataSize - offset; int newOffset = offset + length; sender.Run( inst_id, operation, length, data.data() + offset, Bind(&BleAdvertisingManagerImpl::DivideAndSendDataRecursively, false, inst_id, std::move(data), newOffset, std::move(done_cb), sender)); } void SetPeriodicAdvertisingParameters(uint8_t inst_id, Loading @@ -612,8 +660,10 @@ class BleAdvertisingManagerImpl VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size()); GetHciInterface()->SetPeriodicAdvertisingData(inst_id, 0x03, data.size(), data.data(), cb); DivideAndSendData( inst_id, data, cb, base::Bind(&BleAdvertiserHciInterface::SetPeriodicAdvertisingData, base::Unretained(GetHciInterface()))); } void SetPeriodicAdvertisingEnable(uint8_t inst_id, uint8_t enable, Loading system/stack/test/ble_advertiser_test.cc +146 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,12 @@ fixed_queue_t* btu_general_alarm_queue = nullptr; namespace { constexpr uint8_t INTERMEDIATE = 0x00; // Intermediate fragment of fragmented data constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data class AdvertiserHciMock : public BleAdvertiserHciInterface { public: AdvertiserHciMock() = default; Loading Loading @@ -467,3 +473,143 @@ TEST_F(BleAdvertisingManagerTest, test_start_advertising_set_params_failed) { // Expect the whole flow to fail right away EXPECT_EQ(BTM_BLE_MULTI_ADV_FAILURE, start_advertising_status); } TEST_F(BleAdvertisingManagerTest, test_data_sender) { // prepare test input vector const int max_data_size = 1650; std::vector<uint8_t> data(max_data_size); for (int i = 0; i < max_data_size; i++) data[i] = i; BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind( &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); int advertiser_id = reg_inst_id; status_cb set_data_cb; EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _)) .Times(5) .WillRepeatedly(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 144, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 7; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(503); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _)) .Times(1) .WillRepeatedly(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 1, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 3; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(502); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 2; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(501); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 250, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 2; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(251); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, COMPLETE, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); set_data_cb.Run(0x00); ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(120); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, COMPLETE, _, 120, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); set_data_cb.Run(0x00); ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(0); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, COMPLETE, _, 0, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); set_data_cb.Run(0x00); ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); } Loading
system/stack/btm/btm_ble_multi_adv.cc +58 −8 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ extern void btm_gen_resolvable_private_addr( base::Callback<void(uint8_t[8])> cb); extern fixed_queue_t* btu_general_alarm_queue; constexpr int ADV_DATA_LEN_MAX = 251; struct AdvertisingInstance { uint8_t inst_id; bool in_use; Loading Loading @@ -586,14 +588,60 @@ class BleAdvertisingManagerImpl } VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size()); if (is_scan_rsp) { GetHciInterface()->SetScanResponseData(inst_id, 0x03, 0x01, data.size(), data.data(), cb); } else { GetHciInterface()->SetAdvertisingData(inst_id, 0x03, 0x01, data.size(), data.data(), cb); DivideAndSendData( inst_id, data, cb, base::Bind(&BleAdvertisingManagerImpl::SetDataAdvDataSender, base::Unretained(this), is_scan_rsp)); } void SetDataAdvDataSender(uint8_t is_scan_rsp, uint8_t inst_id, uint8_t operation, uint8_t length, uint8_t* data, MultiAdvCb cb) { if (is_scan_rsp) GetHciInterface()->SetScanResponseData(inst_id, operation, 0x01, length, data, cb); else GetHciInterface()->SetAdvertisingData(inst_id, operation, 0x01, length, data, cb); } using DataSender = base::Callback<void( uint8_t /*inst_id*/, uint8_t /* operation */, uint8_t /* length */, uint8_t* /* data */, MultiAdvCb /* done */)>; void DivideAndSendData(int inst_id, std::vector<uint8_t> data, MultiAdvCb done_cb, DataSender sender) { DivideAndSendDataRecursively(true, inst_id, std::move(data), 0, std::move(done_cb), std::move(sender), 0); } static void DivideAndSendDataRecursively(bool isFirst, int inst_id, std::vector<uint8_t> data, int offset, MultiAdvCb done_cb, DataSender sender, uint8_t status) { constexpr uint8_t INTERMEDIATE = 0x00; // Intermediate fragment of fragmented data constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data int dataSize = (int)data.size(); if (status != 0 || (!isFirst && offset == dataSize)) { /* if we got error writing data, or reached the end of data */ done_cb.Run(status); return; } bool moreThanOnePacket = dataSize - offset > ADV_DATA_LEN_MAX; uint8_t operation = isFirst ? moreThanOnePacket ? FIRST : COMPLETE : moreThanOnePacket ? INTERMEDIATE : LAST; int length = moreThanOnePacket ? ADV_DATA_LEN_MAX : dataSize - offset; int newOffset = offset + length; sender.Run( inst_id, operation, length, data.data() + offset, Bind(&BleAdvertisingManagerImpl::DivideAndSendDataRecursively, false, inst_id, std::move(data), newOffset, std::move(done_cb), sender)); } void SetPeriodicAdvertisingParameters(uint8_t inst_id, Loading @@ -612,8 +660,10 @@ class BleAdvertisingManagerImpl VLOG(1) << "data is: " << base::HexEncode(data.data(), data.size()); GetHciInterface()->SetPeriodicAdvertisingData(inst_id, 0x03, data.size(), data.data(), cb); DivideAndSendData( inst_id, data, cb, base::Bind(&BleAdvertiserHciInterface::SetPeriodicAdvertisingData, base::Unretained(GetHciInterface()))); } void SetPeriodicAdvertisingEnable(uint8_t inst_id, uint8_t enable, Loading
system/stack/test/ble_advertiser_test.cc +146 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,12 @@ fixed_queue_t* btu_general_alarm_queue = nullptr; namespace { constexpr uint8_t INTERMEDIATE = 0x00; // Intermediate fragment of fragmented data constexpr uint8_t FIRST = 0x01; // First fragment of fragmented data constexpr uint8_t LAST = 0x02; // Last fragment of fragmented data constexpr uint8_t COMPLETE = 0x03; // Complete extended advertising data class AdvertiserHciMock : public BleAdvertiserHciInterface { public: AdvertiserHciMock() = default; Loading Loading @@ -467,3 +473,143 @@ TEST_F(BleAdvertisingManagerTest, test_start_advertising_set_params_failed) { // Expect the whole flow to fail right away EXPECT_EQ(BTM_BLE_MULTI_ADV_FAILURE, start_advertising_status); } TEST_F(BleAdvertisingManagerTest, test_data_sender) { // prepare test input vector const int max_data_size = 1650; std::vector<uint8_t> data(max_data_size); for (int i = 0; i < max_data_size; i++) data[i] = i; BleAdvertisingManager::Get()->RegisterAdvertiser(base::Bind( &BleAdvertisingManagerTest::RegistrationCb, base::Unretained(this))); EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, reg_status); int advertiser_id = reg_inst_id; status_cb set_data_cb; EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _)) .Times(5) .WillRepeatedly(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 144, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 7; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(503); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, INTERMEDIATE, _, 251, _, _)) .Times(1) .WillRepeatedly(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 1, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 3; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(502); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 2; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(501); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, FIRST, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, LAST, _, 250, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); for (int i = 0; i < 2; i++) { set_data_cb.Run(0x00); } ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(251); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, COMPLETE, _, 251, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); set_data_cb.Run(0x00); ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(120); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, COMPLETE, _, 120, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); set_data_cb.Run(0x00); ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); // ***************** Try again with different data size ********************* data.resize(0); EXPECT_CALL(*hci_mock, SetAdvertisingData(advertiser_id, COMPLETE, _, 0, _, _)) .Times(1) .WillOnce(SaveArg<5>(&set_data_cb)); BleAdvertisingManager::Get()->SetData( advertiser_id, false, data, base::Bind(&BleAdvertisingManagerTest::SetDataCb, base::Unretained(this))); set_data_cb.Run(0x00); ::testing::Mock::VerifyAndClearExpectations(hci_mock.get()); // Expect the whole flow to succeed EXPECT_EQ(BTM_BLE_MULTI_ADV_SUCCESS, set_data_status); }