out_file << "// @generated rust packets from " << input_file.filename().string() << "\n\n";
generate_rust_packet_preamble(out_file);
+ if (input_filename == "hci_packets") {
+ out_file << "pub trait CommandExpectations { "
+ << "type ResponseType;"
+ << "fn _to_response_type(pkt: EventPacket) -> Self::ResponseType;"
+ << "}";
+
+ for (const auto& packet_def : decls.packet_defs_queue_) {
+ auto packet = packet_def.second;
+ if (!packet->HasAncestorNamed("Command")) {
+ continue;
+ }
+ auto constraint = packet->parent_constraints_.find("op_code");
+ if (constraint == packet->parent_constraints_.end()) {
+ continue;
+ }
+ auto opcode = std::get<std::string>(constraint->second);
+ for (const auto& other_packet_def : decls.packet_defs_queue_) {
+ auto other_packet = other_packet_def.second;
+ bool command_status = other_packet->HasAncestorNamed("CommandStatus");
+ bool command_complete = other_packet->HasAncestorNamed("CommandComplete");
+ if (!command_status && !command_complete) {
+ continue;
+ }
+ auto other_constraint = other_packet->parent_constraints_.find("command_op_code");
+ if (other_constraint == other_packet->parent_constraints_.end()) {
+ continue;
+ }
+
+ auto other_opcode = std::get<std::string>(other_constraint->second);
+ if (opcode == other_opcode) {
+ packet->complement_ = other_packet;
+ break;
+ }
+ }
+ }
+ }
for (const auto& e : decls.type_defs_queue_) {
if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
}
void PacketDef::GenRustAccessStructImpls(std::ostream& s) const {
+ if (complement_ != nullptr) {
+ auto complement_root = complement_->GetRootDef();
+ auto complement_root_accessor = util::CamelCaseToUnderScore(complement_root->name_);
+ s << "impl CommandExpectations for " << name_ << "Packet {";
+ s << " type ResponseType = " << complement_->name_ << "Packet;";
+ s << " fn _to_response_type(pkt: EventPacket) -> Self::ResponseType { ";
+ s << complement_->name_ << "Packet::new(pkt." << complement_root_accessor << ".clone())";
+ s << " }";
+ s << "}";
+ }
+
s << "impl " << name_ << "Packet {";
if (parent_ == nullptr) {
s << "pub fn parse(bytes: &[u8]) -> Result<Self> { ";
use bt_common::time::Alarm;
use bt_hal::HalExports;
-use bt_packets::hci::CommandCompleteChild::ResetComplete;
use bt_packets::hci::EventChild::{
CommandComplete, CommandStatus, LeMetaEvent, MaxSlotsChange, PageScanRepetitionModeChange,
VendorSpecificEvent,
};
use bt_packets::hci::{
- AclPacket, CommandCompletePacket, CommandPacket, CommandStatusPacket, ErrorCode, EventCode,
- EventPacket, LeMetaEventPacket, OpCode, ResetBuilder, SubeventCode,
+ AclPacket, CommandExpectations, CommandPacket, ErrorCode, EventCode, EventPacket,
+ LeMetaEventPacket, OpCode, ResetBuilder, SubeventCode,
};
use error::Result;
use gddi::{module, provides, Stoppable};
acl_rx: hal_exports.acl_rx,
};
- match exports
- .enqueue_command_with_complete(ResetBuilder {}.build())
- .await
- .specialize()
- {
- ResetComplete(evt) if *evt.get_status() == ErrorCode::Success => {}
- _ => panic!("reset did not complete successfully"),
- }
+ assert!(
+ *exports.send(ResetBuilder {}.build()).await.get_status() == ErrorCode::Success,
+ "reset did not complete successfully"
+ );
exports
}
}
impl HciExports {
- async fn send(&mut self, cmd: CommandPacket) -> Result<EventPacket> {
+ async fn send_raw(&mut self, cmd: CommandPacket) -> Result<EventPacket> {
let (tx, rx) = oneshot::channel::<EventPacket>();
self.cmd_tx.send(Command { cmd, fut: tx }).await?;
let event = rx.await?;
Ok(event)
}
- /// Enqueue an HCI command expecting a command complete
- /// response from the controller
- pub async fn enqueue_command_with_complete<T: Into<CommandPacket>>(
+ /// Send a command to the controller, getting an expected response back
+ pub async fn send<T: Into<CommandPacket> + CommandExpectations>(
&mut self,
cmd: T,
- ) -> CommandCompletePacket {
- match self.send(cmd.into()).await.unwrap().specialize() {
- CommandComplete(evt) => evt,
- _ => panic!("Expected command complete, got status instead"),
- }
- }
-
- /// Enqueue an HCI command expecting a status response
- /// from the controller
- pub async fn enqueue_command_with_status<T: Into<CommandPacket>>(&mut self, cmd: T) -> CommandStatusPacket {
- match self.send(cmd.into()).await.unwrap().specialize() {
- CommandStatus(evt) => evt,
- _ => panic!("Expected command status, got complete instead"),
- }
+ ) -> T::ResponseType {
+ T::_to_response_type(self.send_raw(cmd.into()).await.unwrap())
}
/// Indicate interest in specific HCI events