OSDN Git Service

rusty-gd: drastically simplify command sending
authorZach Johnson <zachoverflow@google.com>
Sun, 13 Dec 2020 09:59:43 +0000 (01:59 -0800)
committerZach Johnson <zachoverflow@google.com>
Fri, 18 Dec 2020 19:33:57 +0000 (11:33 -0800)
include a trait during generation that knows how to
convert the event responses to the correct matching type

Bug: 171749953
Tag: #gd-refactor
Test: gd/cert/run --rhost SimpleHalTest
Change-Id: Icf96ce20c0b2311e94e5198c1cc4038f78683771

gd/packet/parser/gen_rust.cc
gd/packet/parser/packet_def.cc
gd/packet/parser/parent_def.cc
gd/packet/parser/parent_def.h
gd/rust/hci/src/facade.rs
gd/rust/hci/src/lib.rs

index d9bb89a..20c2bb3 100644 (file)
@@ -74,6 +74,42 @@ bool generate_rust_source_one_file(
   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) {
index 57894e0..480561a 100644 (file)
@@ -945,6 +945,17 @@ void PacketDef::GenRustStructImpls(std::ostream& s) const {
 }
 
 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> { ";
index b4d1140..b54fb1f 100644 (file)
@@ -510,3 +510,14 @@ std::map<std::string, std::variant<int64_t, std::string>> ParentDef::GetAllConst
   }
   return res;
 }
+
+bool ParentDef::HasAncestorNamed(std::string name) const {
+  auto parent = parent_;
+  while (parent != nullptr) {
+    if (parent->name_ == name) {
+      return true;
+    }
+    parent = parent->parent_;
+  }
+  return false;
+}
index bcad5a0..8667d3c 100644 (file)
@@ -63,6 +63,8 @@ class ParentDef : public TypeDef {
 
   const ParentDef* GetRootDef() const;
 
+  bool HasAncestorNamed(std::string name) const;
+
   std::map<std::string, std::variant<int64_t, std::string>> GetAllConstraints() const;
 
   std::vector<const ParentDef*> GetAncestors() const;
@@ -71,6 +73,8 @@ class ParentDef : public TypeDef {
 
   ParentDef* parent_{nullptr};
 
+  ParentDef* complement_{nullptr};
+
   std::vector<ParentDef*> children_;
 
   std::map<std::string, std::variant<int64_t, std::string>> parent_constraints_;
index 67977d6..6e515cf 100644 (file)
@@ -58,8 +58,8 @@ impl HciLayerFacade for HciLayerFacadeService {
     ) {
         self.rt.block_on(
             self.hci_exports
-                .enqueue_command_with_complete(hci::CommandPacket::parse(&data.take_payload()).unwrap()),
-        );
+                .send_raw(hci::CommandPacket::parse(&data.take_payload()).unwrap()),
+        ).unwrap();
         sink.success(Empty::default());
     }
 
@@ -71,8 +71,8 @@ impl HciLayerFacade for HciLayerFacadeService {
     ) {
         self.rt.block_on(
             self.hci_exports
-                .enqueue_command_with_complete(hci::CommandPacket::parse(&data.take_payload()).unwrap()),
-        );
+                .send_raw(hci::CommandPacket::parse(&data.take_payload()).unwrap()),
+        ).unwrap();
         sink.success(Empty::default());
     }
 
index f472f22..31537e2 100644 (file)
@@ -8,14 +8,13 @@ pub mod facade;
 
 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};
@@ -59,14 +58,10 @@ async fn provide_hci(hal_exports: HalExports, rt: Arc<Runtime>) -> HciExports {
         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
 }
@@ -99,32 +94,19 @@ pub struct HciExports {
 }
 
 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