blob: b38d3cc823305833583630732725031171689ff8 [file] [log] [blame]
// Copyright 2023 The Pigweed Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
#include "pw_bluetooth_sapphire/internal/host/transport/emboss_control_packets.h"
#include <pw_bluetooth/hci_android.emb.h>
#include "pw_bluetooth_sapphire/internal/host/common/packet_view.h"
#include "pw_bluetooth_sapphire/internal/host/hci-spec/vendor_protocol.h"
namespace bt::hci {
EmbossCommandPacket::EmbossCommandPacket(hci_spec::OpCode opcode,
size_t packet_size)
: DynamicPacket(packet_size) {
BT_ASSERT_MSG(
packet_size >=
pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes(),
"command packet size must be at least 3 bytes to accomodate header");
auto header = view<pw::bluetooth::emboss::CommandHeaderWriter>();
header.opcode().BackingStorage().WriteUInt(opcode);
header.parameter_total_size().Write(
packet_size -
pw::bluetooth::emboss::CommandHeader::IntrinsicSizeInBytes());
}
hci_spec::OpCode EmbossCommandPacket::opcode() const {
return header_view().opcode().BackingStorage().ReadUInt();
}
uint8_t EmbossCommandPacket::ogf() const {
return header_view().opcode().ogf().Read();
}
uint16_t EmbossCommandPacket::ocf() const {
return header_view().opcode().ocf().Read();
}
pw::bluetooth::emboss::CommandHeaderView EmbossCommandPacket::header_view()
const {
return view<pw::bluetooth::emboss::CommandHeaderView>();
}
EmbossEventPacket::EmbossEventPacket(size_t packet_size)
: DynamicPacket(packet_size) {
BT_ASSERT_MSG(
packet_size >= pw::bluetooth::emboss::EventHeader::IntrinsicSizeInBytes(),
"event packet size must be at least 2 bytes to accomodate header");
}
hci_spec::EventCode EmbossEventPacket::event_code() const {
return view<pw::bluetooth::emboss::EventHeaderView>().event_code().Read();
}
std::optional<pw::bluetooth::emboss::StatusCode> EmbossEventPacket::StatusCode()
const {
switch (event_code()) {
case hci_spec::kCommandCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::SimpleCommandCompleteEventView>();
case hci_spec ::kCommandStatusEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::CommandStatusEventView>();
case hci_spec::kConnectionCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::ConnectionCompleteEventView>();
case hci_spec::kDisconnectionCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::DisconnectionCompleteEventView>();
case hci_spec::kReadRemoteVersionInfoCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::ReadRemoteVersionInfoCompleteEventView>();
case hci_spec::kReadRemoteSupportedFeaturesCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::
ReadRemoteSupportedFeaturesCompleteEventView>();
case hci_spec::kReadRemoteExtendedFeaturesCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::ReadRemoteExtendedFeaturesCompleteEventView>();
case hci_spec::kRemoteNameRequestCompleteEventCode: {
// Tests expect that a kPacketMalformed status is returned for incomplete
// events, even if they contain the status field.
pw::bluetooth::emboss::RemoteNameRequestCompleteEventView event_view(
data().data(), size());
if (!event_view.IsComplete()) {
return std::nullopt;
}
return event_view.status().UncheckedRead();
}
case hci_spec::kEncryptionChangeEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::EncryptionChangeEventV1View>();
case hci_spec::kEncryptionKeyRefreshCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::EncryptionKeyRefreshCompleteEventView>();
case hci_spec::kRoleChangeEventCode:
return StatusCodeFromView<pw::bluetooth::emboss::RoleChangeEventView>();
case hci_spec::kSynchronousConnectionCompleteEventCode:
return StatusCodeFromView<
pw::bluetooth::emboss::SynchronousConnectionCompleteEventView>();
case hci_spec::kVendorDebugEventCode: {
hci_spec::EventCode subevent_code =
view<pw::bluetooth::emboss::VendorDebugEventView>()
.subevent_code()
.Read();
switch (subevent_code) {
case hci_spec::vendor::android::kLEMultiAdvtStateChangeSubeventCode: {
return StatusCodeFromView<pw::bluetooth::vendor::android_hci::
LEMultiAdvtStateChangeSubeventView>();
}
default: {
BT_PANIC("Emboss vendor subevent (%#.2x) not implemented",
subevent_code);
break;
}
}
break;
}
case hci_spec::kLEMetaEventCode: {
hci_spec::EventCode subevent_code =
view<pw::bluetooth::emboss::LEMetaEventView>().subevent_code().Read();
switch (subevent_code) {
case hci_spec::kLEConnectionCompleteSubeventCode: {
return StatusCodeFromView<
pw::bluetooth::emboss::LEConnectionCompleteSubeventView>();
}
case hci_spec::kLEConnectionUpdateCompleteSubeventCode: {
return StatusCodeFromView<
pw::bluetooth::emboss::LEConnectionUpdateCompleteSubeventView>();
}
case hci_spec::kLEReadRemoteFeaturesCompleteSubeventCode: {
return StatusCodeFromView<
pw::bluetooth::emboss::
LEReadRemoteFeaturesCompleteSubeventView>();
}
default: {
BT_PANIC("Emboss LE meta subevent (%#.2x) not implemented",
subevent_code);
break;
}
}
break;
}
default: {
BT_PANIC("Emboss event (%#.2x) not implemented", event_code());
break;
}
}
return std::nullopt;
}
hci::Result<> EmbossEventPacket::ToResult() const {
std::optional<pw::bluetooth::emboss::StatusCode> maybe_status_code =
StatusCode();
if (!maybe_status_code.has_value()) {
return bt::ToResult(HostError::kPacketMalformed);
}
return bt::ToResult(*maybe_status_code);
}
} // namespace bt::hci