subevent_handlers_.erase(subevent_handlers_.find(event));
}
+ void register_vendor_specific_event(
+ VseSubeventCode vse_subevent_code, ContextualCallback<void(VendorSpecificEventView)> event_handler) {
+ ASSERT_LOG(
+ vendor_specific_event_handlers_.count(vse_subevent_code) == 0,
+ "Can not register a second handler for %02hhx (%s)",
+ vse_subevent_code,
+ VseSubeventCodeText(vse_subevent_code).c_str());
+ vendor_specific_event_handlers_[vse_subevent_code] = event_handler;
+ }
+
+ void unregister_vendor_specific_event(VseSubeventCode vse_subevent_code) {
+ vendor_specific_event_handlers_.erase(vendor_specific_event_handlers_.find(vse_subevent_code));
+ }
+
void on_hci_event(EventView event) {
ASSERT(event.IsValid());
EventCode event_code = event.GetEventCode();
subevent_handlers_[subevent_code].Invoke(meta_event_view);
}
+ void on_vendor_specific_event(EventView event) {
+ VendorSpecificEventView vendor_specific_event_view = VendorSpecificEventView::Create(event);
+ ASSERT(vendor_specific_event_view.IsValid());
+ VseSubeventCode vse_subevent_code = vendor_specific_event_view.GetSubeventCode();
+ if (vendor_specific_event_handlers_.find(vse_subevent_code) == vendor_specific_event_handlers_.end()) {
+ LOG_ERROR(
+ "Unhandled vendor specific event of type 0x%02hhx (%s)",
+ vse_subevent_code,
+ VseSubeventCodeText(vse_subevent_code).c_str());
+ return;
+ }
+ vendor_specific_event_handlers_[vse_subevent_code].Invoke(vendor_specific_event_view);
+ }
+
hal::HciHal* hal_;
HciLayer& module_;
std::map<EventCode, ContextualCallback<void(EventView)>> event_handlers_;
std::map<SubeventCode, ContextualCallback<void(LeMetaEventView)>> subevent_handlers_;
+ std::map<VseSubeventCode, ContextualCallback<void(VendorSpecificEventView)>> vendor_specific_event_handlers_;
OpCode waiting_command_{OpCode::NONE};
uint8_t command_credits_{1}; // Send reset first
Alarm* hci_timeout_alarm_{nullptr};
CallOn(impl_, &impl::unregister_le_event, event);
}
+void HciLayer::RegisterVendorSpecificEventHandler(
+ VseSubeventCode vse_subevent_code, common::ContextualCallback<void(VendorSpecificEventView)> event_handler) {
+ CallOn(impl_, &impl::register_vendor_specific_event, vse_subevent_code, event_handler);
+}
+
+void HciLayer::UnregisterVendorSpecificEventHandler(VseSubeventCode vse_subevent_code) {
+ CallOn(impl_, &impl::unregister_vendor_specific_event, vse_subevent_code);
+}
+
void HciLayer::on_disconnection_complete(EventView event_view) {
auto disconnection_view = DisconnectionCompleteView::Create(event_view);
if (!disconnection_view.IsValid()) {
auto drop_packet = handler->BindOn(impl_, &impl::drop);
RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, drop_packet);
RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, drop_packet);
- RegisterEventHandler(EventCode::VENDOR_SPECIFIC, drop_packet);
+ RegisterEventHandler(EventCode::VENDOR_SPECIFIC, handler->BindOn(impl_, &impl::on_vendor_specific_event));
EnqueueCommand(ResetBuilder::Create(), handler->BindOnce(&fail_if_reset_complete_not_success));
hal->registerIncomingPacketCallback(hal_callbacks_);
#include "hci/hci_layer.h"
#include <gtest/gtest.h>
+
#include <list>
#include <memory>
namespace {
vector<uint8_t> information_request = {
- 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
+ 0xfe,
+ 0x2e,
+ 0x0a,
+ 0x00,
+ 0x06,
+ 0x00,
+ 0x01,
+ 0x00,
+ 0x0a,
+ 0x02,
+ 0x02,
+ 0x00,
+ 0x02,
+ 0x00,
};
// 0x00, 0x01, 0x02, 0x03, ...
vector<uint8_t> counting_bytes;
DependsOnHci() : Module() {}
void SendHciCommandExpectingStatus(std::unique_ptr<CommandBuilder> command) {
- hci_->EnqueueCommand(std::move(command),
- GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandStatusView>));
+ hci_->EnqueueCommand(
+ std::move(command), GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandStatusView>));
}
void SendHciCommandExpectingComplete(std::unique_ptr<CommandBuilder> command) {
- hci_->EnqueueCommand(std::move(command),
- GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
+ hci_->EnqueueCommand(
+ std::move(command), GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
}
void SendSecurityCommandExpectingComplete(std::unique_ptr<SecurityCommandBuilder> command) {
security_interface_ =
hci_->GetSecurityInterface(GetHandler()->BindOn(this, &DependsOnHci::handle_event<EventView>));
}
- hci_->EnqueueCommand(std::move(command),
- GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
+ hci_->EnqueueCommand(
+ std::move(command), GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
}
void SendLeSecurityCommandExpectingComplete(std::unique_ptr<LeSecurityCommandBuilder> command) {
le_security_interface_ =
hci_->GetLeSecurityInterface(GetHandler()->BindOn(this, &DependsOnHci::handle_event<LeMetaEventView>));
}
- hci_->EnqueueCommand(std::move(command),
- GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
+ hci_->EnqueueCommand(
+ std::move(command), GetHandler()->BindOnceOn(this, &DependsOnHci::handle_event<CommandCompleteView>));
}
void SendAclData(std::unique_ptr<AclBuilder> acl) {
return packetview;
}
+ void RegisterVendorSpecificEvent(VseSubeventCode event) {
+ hci_->RegisterVendorSpecificEventHandler(
+ event, GetHandler()->BindOn(this, &DependsOnHci::handle_event<VendorSpecificEventView>));
+ }
+
+ void UnregisterVendorSpecificEvent(VseSubeventCode event) {
+ hci_->UnregisterVendorSpecificEventHandler(event);
+ }
+
void Start() {
hci_ = GetDependency<HciLayer>();
hci_->RegisterEventHandler(
EventCode::CONNECTION_COMPLETE, GetHandler()->BindOn(this, &DependsOnHci::handle_event<EventView>));
- hci_->RegisterLeEventHandler(SubeventCode::CONNECTION_COMPLETE,
- GetHandler()->BindOn(this, &DependsOnHci::handle_event<LeMetaEventView>));
- hci_->GetAclQueueEnd()->RegisterDequeue(GetHandler(),
- common::Bind(&DependsOnHci::handle_acl, common::Unretained(this)));
+ hci_->RegisterLeEventHandler(
+ SubeventCode::CONNECTION_COMPLETE, GetHandler()->BindOn(this, &DependsOnHci::handle_event<LeMetaEventView>));
+ hci_->GetAclQueueEnd()->RegisterDequeue(
+ GetHandler(), common::Bind(&DependsOnHci::handle_acl, common::Unretained(this)));
hci_->GetIsoQueueEnd()->RegisterDequeue(
GetHandler(), common::Bind(&DependsOnHci::handle_iso, common::Unretained(this)));
}
ASSERT_TRUE(LeConnectionCompleteView::Create(LeMetaEventView::Create(EventView::Create(event))).IsValid());
}
+TEST_F(HciTest, vendorSpecificEventRegistration) {
+ auto event_future = upper->GetReceivedEventFuture();
+
+ upper->RegisterVendorSpecificEvent(VseSubeventCode::BQR_EVENT);
+
+ // Send a vendor specific event
+ hal->callbacks->hciEventReceived(GetPacketBytes(BqrLinkQualityEventBuilder::Create(
+ QualityReportId::A2DP_AUDIO_CHOPPY,
+ BqrPacketType::TYPE_2DH1,
+ /* handle */ 0x123,
+ Role::CENTRAL,
+ /* TX_Power_Level */ 0x05,
+ /* RSSI */ 65,
+ /* SNR */ 30,
+ /* Unused_AFH_Channel_Count */ 0,
+ /* AFH_Select_Unideal_Channel_Count */ 0,
+ /* LSTO */ 12,
+ /* Connection_Piconet_Clock */ 42,
+ /* Retransmission_Count */ 1,
+ /* No_RX_Count */ 1,
+ /* NAK_Count */ 1,
+ /* Last_TX_ACK_Timestamp */ 123456,
+ /* Flow_Off_Count */ 78910,
+ /* Last_Flow_On_Timestamp */ 123457,
+ /* Buffer_Overflow_Bytes */ 42,
+ /* Buffer_Underflow_Bytes */ 24,
+ /* Vendor Specific Parameter */ std::make_unique<RawBuilder>())));
+
+ // Wait for the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+
+ auto event = upper->GetReceivedEvent();
+ ASSERT_TRUE(
+ BqrLinkQualityEventView::Create(BqrEventView::Create(VendorSpecificEventView::Create(EventView::Create(event))))
+ .IsValid());
+
+ // Now test if we can unregister the vendor specific event handler
+ event_future = upper->GetReceivedEventFuture();
+
+ upper->UnregisterVendorSpecificEvent(VseSubeventCode::BQR_EVENT);
+
+ hal->callbacks->hciEventReceived(GetPacketBytes(BqrLinkQualityEventBuilder::Create(
+ QualityReportId::A2DP_AUDIO_CHOPPY,
+ BqrPacketType::TYPE_2DH1,
+ /* handle */ 0x123,
+ Role::CENTRAL,
+ /* TX_Power_Level */ 0x05,
+ /* RSSI */ 65,
+ /* SNR */ 30,
+ /* Unused_AFH_Channel_Count */ 0,
+ /* AFH_Select_Unideal_Channel_Count */ 0,
+ /* LSTO */ 12,
+ /* Connection_Piconet_Clock */ 42,
+ /* Retransmission_Count */ 1,
+ /* No_RX_Count */ 1,
+ /* NAK_Count */ 1,
+ /* Last_TX_ACK_Timestamp */ 123456,
+ /* Flow_Off_Count */ 78910,
+ /* Last_Flow_On_Timestamp */ 123457,
+ /* Buffer_Overflow_Bytes */ 42,
+ /* Buffer_Underflow_Bytes */ 24,
+ /* Vendor Specific Parameter */ std::make_unique<RawBuilder>())));
+
+ // Wait for unregistered event should timeout
+ event_status = event_future.wait_for(kTimeout);
+ ASSERT_NE(event_status, std::future_status::ready);
+}
+
+TEST_F(HciTest, vendorSpecificEventUnknown) {
+ auto event_future = upper->GetReceivedEventFuture();
+
+ upper->RegisterVendorSpecificEvent(VseSubeventCode::BQR_EVENT);
+
+ // Send a vendor specific event
+ // Make sure 0xFE is not used for any VSE, if not change this value to an unused one
+ auto raw_builder = std::make_unique<RawBuilder>();
+ raw_builder->AddOctets1(42);
+ hal->callbacks->hciEventReceived(
+ GetPacketBytes(VendorSpecificEventBuilder::Create(static_cast<VseSubeventCode>(0xFE), std::move(raw_builder))));
+
+ // Wait for the event should timeout
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_NE(event_status, std::future_status::ready);
+}
+
TEST_F(HciTest, noOpCredits) {
ASSERT_EQ(0, hal->GetNumSentCommands());