Casimir: Implement Listen mode discovery for NFC-A/ISO-DEP

Bug: 297993136
Test: manual
Change-Id: Ic37973e481e55ced4c162ca834fa50ea9e4960a1
diff --git a/tools/casimir/src/controller.rs b/tools/casimir/src/controller.rs
index e9b27cc..0843148 100644
--- a/tools/casimir/src/controller.rs
+++ b/tools/casimir/src/controller.rs
@@ -63,7 +63,12 @@
         rf_protocol: rf::Protocol,
     },
     ListenSleep,
-    ListenActive,
+    ListenActive {
+        id: u16,
+        rf_interface: nci::RfInterfaceType,
+        rf_technology: rf::Technology,
+        rf_protocol: rf::Protocol,
+    },
     WaitForHostSelect,
     WaitForSelectResponse {
         id: u16,
@@ -269,7 +274,7 @@
         for parameter in cmd.get_parameters().iter() {
             match parameter.id {
                 nci::ConfigParameterId::Rfu(_) => invalid_parameters.push(parameter.id),
-                // TODO:
+                // TODO(henrichataing):
                 // [NCI] 5.2.1 State RFST_IDLE
                 // Unless otherwise specified, discovery related configuration
                 // defined in Sections 6.1, 6.2, 6.3 and 7.1 SHALL only be set
@@ -590,11 +595,11 @@
             (RfState::PollActive { .. }, Discover) => (nci::Status::Ok, RfState::Discovery),
             (RfState::ListenSleep, IdleMode) => (nci::Status::Ok, RfState::Idle),
             (RfState::ListenSleep, _) => (nci::Status::SemanticError, RfState::ListenSleep),
-            (RfState::ListenActive, IdleMode) => (nci::Status::Ok, RfState::Idle),
-            (RfState::ListenActive, SleepMode | SleepAfMode) => {
+            (RfState::ListenActive { .. }, IdleMode) => (nci::Status::Ok, RfState::Idle),
+            (RfState::ListenActive { .. }, SleepMode | SleepAfMode) => {
                 (nci::Status::Ok, RfState::ListenSleep)
             }
-            (RfState::ListenActive, Discover) => (nci::Status::Ok, RfState::Discovery),
+            (RfState::ListenActive { .. }, Discover) => (nci::Status::Ok, RfState::Discovery),
             (RfState::WaitForHostSelect, IdleMode) => (nci::Status::Ok, RfState::Idle),
             (RfState::WaitForHostSelect, _) => {
                 (nci::Status::SemanticError, RfState::WaitForHostSelect)
@@ -700,6 +705,13 @@
                 rf_protocol: rf::Protocol::IsoDep,
                 rf_interface: nci::RfInterfaceType::IsoDep,
                 ..
+            }
+            | RfState::ListenActive {
+                id,
+                rf_technology,
+                rf_protocol: rf::Protocol::IsoDep,
+                rf_interface: nci::RfInterfaceType::IsoDep,
+                ..
             } => {
                 self.send_rf(rf::DataBuilder {
                     receiver: id,
@@ -721,12 +733,12 @@
                 )
                 .await
             }
-            RfState::PollActive { rf_protocol, rf_interface, .. } => unimplemented!(
+            RfState::PollActive { rf_protocol, rf_interface, .. }
+            | RfState::ListenActive { rf_protocol, rf_interface, .. } => unimplemented!(
                 "unsupported combination of RF protocol {:?} and interface {:?}",
                 rf_protocol,
                 rf_interface
             ),
-            RfState::ListenActive => unimplemented!("unsupported data in active listen mode"),
             _ => {
                 println!("  > ignored RF data packet while not in active listen or poll mode");
                 Ok(())
@@ -762,23 +774,32 @@
             return Ok(());
         }
 
-        match cmd.get_technology() {
-            rf::Technology::NfcA => {
-                // Configured for T4AT tag emulation.
-                let int_protocol = 0x01;
-                self.send_rf(rf::NfcAPollResponseBuilder {
-                    protocol: rf::Protocol::Undetermined,
-                    receiver: cmd.get_sender(),
-                    sender: self.id,
-                    nfcid1: self.nfcid1(),
-                    int_protocol,
-                })
-                .await?;
+        let technology = cmd.get_technology();
+        if state.discover_configuration.iter().any(|config| {
+            matches!(
+                (config.technology_and_mode, technology),
+                (nci::RfTechnologyAndMode::NfcAPassiveListenMode, rf::Technology::NfcA)
+                    | (nci::RfTechnologyAndMode::NfcBPassiveListenMode, rf::Technology::NfcB)
+                    | (nci::RfTechnologyAndMode::NfcFPassiveListenMode, rf::Technology::NfcF)
+            )
+        }) {
+            match technology {
+                rf::Technology::NfcA => {
+                    // Configured for T4AT tag emulation.
+                    let int_protocol = 0x01;
+                    self.send_rf(rf::NfcAPollResponseBuilder {
+                        protocol: rf::Protocol::Undetermined,
+                        receiver: cmd.get_sender(),
+                        sender: self.id,
+                        nfcid1: self.nfcid1(),
+                        int_protocol,
+                    })
+                    .await?
+                }
+                rf::Technology::NfcB => todo!(),
+                rf::Technology::NfcF => todo!(),
+                _ => (),
             }
-
-            rf::Technology::NfcB => todo!(),
-            rf::Technology::NfcF => todo!(),
-            rf::Technology::NfcV => todo!(),
         }
 
         Ok(())
@@ -827,9 +848,57 @@
         Ok(())
     }
 
-    async fn t4at_select_command(&self, _cmd: rf::T4ATSelectCommand) -> Result<()> {
+    async fn t4at_select_command(&self, cmd: rf::T4ATSelectCommand) -> Result<()> {
         println!("+ t4at_select_command()");
 
+        let mut state = self.state.lock().await;
+        if state.rf_state != RfState::Discovery {
+            return Ok(());
+        }
+
+        // TODO(henrichataing): validate that the protocol and technology are
+        // valid for the current discovery settings.
+
+        // TODO(henrichataing): use listen mode routing table to decide which
+        // interface should be used for the activating device.
+
+        state.rf_state = RfState::ListenActive {
+            id: cmd.get_sender(),
+            rf_technology: rf::Technology::NfcA,
+            rf_protocol: rf::Protocol::IsoDep,
+            rf_interface: nci::RfInterfaceType::IsoDep,
+        };
+
+        self.send_rf(rf::T4ATSelectResponseBuilder {
+            receiver: cmd.get_sender(),
+            sender: self.id,
+            // [DIGITAL] 14.6.2 RATS Response (Answer To Select)
+            // TODO(henrichataing): this value is just a valid default;
+            // construct the RATS response from global capabilities.
+            rats_response: vec![0x2, 0x0],
+        })
+        .await?;
+
+        self.send_control(nci::RfIntfActivatedNotificationBuilder {
+            rf_discovery_id: 0,
+            rf_interface: nci::RfInterfaceType::IsoDep,
+            rf_protocol: nci::RfProtocolType::IsoDep,
+            activation_rf_technology_and_mode: nci::RfTechnologyAndMode::NfcAPassiveListenMode,
+            max_data_packet_payload_size: MAX_DATA_PACKET_PAYLOAD_SIZE,
+            initial_number_of_credits: 1,
+            // No parameters are currently defined for NFC-A Listen Mode.
+            rf_technology_specific_parameters: vec![],
+            data_exchange_rf_technology_and_mode: nci::RfTechnologyAndMode::NfcAPassiveListenMode,
+            data_exchange_transmit_bit_rate: nci::BitRate::BitRate106KbitS,
+            data_exchange_receive_bit_rate: nci::BitRate::BitRate106KbitS,
+            activation_parameters: nci::NfcAIsoDepListenModeActivationParametersBuilder {
+                param: cmd.get_param(),
+            }
+            .build()
+            .to_vec(),
+        })
+        .await?;
+
         Ok(())
     }
 
@@ -894,20 +963,28 @@
                     id, rf_technology, rf_protocol: rf::Protocol::IsoDep, ..
                 },
                 rf::Protocol::IsoDep,
+            )
+            | (
+                RfState::ListenActive {
+                    id, rf_technology, rf_protocol: rf::Protocol::IsoDep, ..
+                },
+                rf::Protocol::IsoDep,
             ) if data.get_sender() == id && data.get_technology() == rf_technology => {
                 self.send_data(nci::DataPacketBuilder {
                     mt: nci::MessageType::Data,
                     conn_id: STATIC_RF_CONN,
-                    cr: 1, // TODO: credit based control flow
+                    cr: 1, // TODO(henrichataing): credit based control flow
                     payload: Some(bytes::Bytes::copy_from_slice(data.get_data())),
                 })
                 .await
             }
-            (RfState::PollActive { id, .. }, _) if id != data.get_sender() => {
+            (RfState::PollActive { id, .. }, _) | (RfState::ListenActive { id, .. }, _)
+                if id != data.get_sender() =>
+            {
                 println!("  > ignored RF data packet sent from an un-selected device");
                 Ok(())
             }
-            (RfState::PollActive { .. }, _) => {
+            (RfState::PollActive { .. }, _) | (RfState::ListenActive { .. }, _) => {
                 unimplemented!("unsupported combination of technology and protocol")
             }
             (_, _) => {
diff --git a/tools/casimir/src/packets.rs b/tools/casimir/src/packets.rs
index 0cef4fd..4855130 100644
--- a/tools/casimir/src/packets.rs
+++ b/tools/casimir/src/packets.rs
@@ -62,9 +62,9 @@
     }
 }
 
-impl TryFrom<&nci::RfTechnologyAndMode> for rf::Technology {
+impl TryFrom<nci::RfTechnologyAndMode> for rf::Technology {
     type Error = nci::RfTechnologyAndMode;
-    fn try_from(protocol: &nci::RfTechnologyAndMode) -> Result<Self, Self::Error> {
+    fn try_from(protocol: nci::RfTechnologyAndMode) -> Result<Self, Self::Error> {
         Ok(match protocol {
             nci::RfTechnologyAndMode::NfcAPassivePollMode
             | nci::RfTechnologyAndMode::NfcAPassiveListenMode => rf::Technology::NfcA,
@@ -73,7 +73,7 @@
             nci::RfTechnologyAndMode::NfcFPassivePollMode
             | nci::RfTechnologyAndMode::NfcFPassiveListenMode => rf::Technology::NfcF,
             nci::RfTechnologyAndMode::NfcVPassivePollMode => rf::Technology::NfcV,
-            _ => return Err(*protocol),
+            _ => return Err(protocol),
         })
     }
 }