1 // Copyright 2021, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 //! NCI API module 16 17 use crate::{CommandSender, Result}; 18 use bytes::Bytes; 19 use log::debug; 20 use nfc_hal::{HalEvent, HalEventRegistry, HalEventStatus}; 21 use nfc_packets::nci::{self, CommandBuilder, Opcode}; 22 use nfc_packets::nci::{FeatureEnable, PacketBoundaryFlag, ResetType}; 23 use nfc_packets::nci::{InitCommandBuilder, ResetCommandBuilder}; 24 use nfc_packets::nci::{InitResponsePacket, ResponseChild}; 25 use tokio::sync::oneshot; 26 27 /// NCI API object to manage static API data 28 pub struct NciApi { 29 /// Command Sender external interface 30 commands: Option<CommandSender>, 31 /// The NFC response callback 32 callback: Option<fn(u16, &[u8])>, 33 /// HalEventRegistry is used to register for HAL events 34 hal_events: Option<HalEventRegistry>, 35 nfc_data: NfcData, 36 } 37 38 struct NfcData { 39 init_response: Option<InitResponsePacket>, 40 } 41 42 impl NciApi { 43 /// NciApi constructor new() -> NciApi44 pub fn new() -> NciApi { 45 let nfc_data = NfcData { init_response: None }; 46 NciApi { commands: None, callback: None, hal_events: None, nfc_data } 47 } 48 49 /** **************************************************************************** 50 ** 51 ** Function nfc_enable 52 ** 53 ** Description This function enables NFC. Prior to calling NFC_Enable: 54 ** - the NFCC must be powered up, and ready to receive 55 ** commands. 56 ** 57 ** This function opens the NCI transport (if applicable), 58 ** resets the NFC controller, and initializes the NFC 59 ** subsystems. 60 ** 61 ** When the NFC startup procedure is completed, an 62 ** NFC_ENABLE_REVT is returned to the application using the 63 ** tNFC_RESPONSE_CBACK. 64 ** 65 ** Returns tNFC_STATUS 66 ** 67 *******************************************************************************/ 68 /// extern tNFC_STATUS NFC_Enable(tNFC_RESPONSE_CBACK* p_cback); nfc_enable(&mut self, callback: fn(u16, &[u8]))69 pub async fn nfc_enable(&mut self, callback: fn(u16, &[u8])) { 70 let nci = crate::init().await; 71 72 self.commands = Some(nci.commands); 73 self.callback = Some(callback); 74 self.hal_events = Some(nci.hal_events); 75 } 76 /** **************************************************************************** 77 ** 78 ** Function NFC_Disable 79 ** 80 ** Description This function performs clean up routines for shutting down 81 ** NFC and closes the NCI transport (if using dedicated NCI 82 ** transport). 83 ** 84 ** When the NFC shutdown procedure is completed, an 85 ** NFC_DISABLED_REVT is returned to the application using the 86 ** tNFC_RESPONSE_CBACK. 87 ** 88 ** Returns nothing 89 ** 90 *******************************************************************************/ 91 /// extern void NFC_Disable(void); nfc_disable(&mut self)92 pub async fn nfc_disable(&mut self) { 93 let (tx, rx) = oneshot::channel::<HalEventStatus>(); 94 if let Some(mut hr) = self.hal_events.take() { 95 hr.register(HalEvent::CloseComplete, tx).await; 96 97 if let Some(cmd) = self.commands.take() { 98 drop(cmd); 99 } 100 let status = rx.await.unwrap(); 101 debug!("Shutdown complete {:?}.", status); 102 103 if let Some(cb) = self.callback.take() { 104 cb(1, &[]); 105 } 106 } 107 } 108 109 /** **************************************************************************** 110 ** 111 ** Function NFC_Init 112 ** 113 ** Description This function initializes control blocks for NFC 114 ** 115 ** Returns nothing 116 ** 117 *******************************************************************************/ 118 /// extern void NFC_Init(tHAL_NFC_ENTRY* p_hal_entry_tbl); nfc_init(&mut self) -> Result<()>119 pub async fn nfc_init(&mut self) -> Result<()> { 120 let pbf = PacketBoundaryFlag::CompleteOrFinal; 121 if let Some(cmd) = self.commands.as_mut() { 122 let reset = cmd 123 .send_and_notify( 124 ResetCommandBuilder { gid: 0, pbf, reset_type: ResetType::ResetConfig } 125 .build() 126 .into(), 127 ) 128 .await?; 129 let _notification_packet = reset.notification.await?; 130 let init = cmd 131 .send( 132 InitCommandBuilder { gid: 0, pbf, feature_enable: FeatureEnable::Rfu } 133 .build() 134 .into(), 135 ) 136 .await?; 137 if let ResponseChild::InitResponse(irp) = init.specialize() { 138 self.nfc_data.init_response = Some(irp); 139 } 140 } 141 Ok(()) 142 } 143 144 /** ***************************************************************************** 145 ** 146 ** Function NFC_GetLmrtSize 147 ** 148 ** Description Called by application wto query the Listen Mode Routing 149 ** Table size supported by NFCC 150 ** 151 ** Returns Listen Mode Routing Table size 152 ** 153 *******************************************************************************/ 154 /// extern uint16_t NFC_GetLmrtSize(void); nfc_get_lmrt_size(&mut self) -> u16155 pub async fn nfc_get_lmrt_size(&mut self) -> u16 { 156 if let Some(ir) = &self.nfc_data.init_response { 157 ir.get_max_rout_tbls_size() 158 } else { 159 0 160 } 161 } 162 163 /** ***************************************************************************** 164 ** 165 ** Function NFC_SetConfig 166 ** 167 ** Description This function is called to send the configuration parameter 168 ** TLV to NFCC. The response from NFCC is reported by 169 ** tNFC_RESPONSE_CBACK as NFC_SET_CONFIG_REVT. 170 ** 171 ** Parameters tlv_size - the length of p_param_tlvs. 172 ** p_param_tlvs - the parameter ID/Len/Value list 173 ** 174 ** Returns tNFC_STATUS 175 ** 176 *******************************************************************************/ 177 /// extern tNFC_STATUS NFC_SetConfig(uint8_t tlv_size, uint8_t* p_param_tlvs); nfc_set_config(&mut self, param_tlvs: &[u8]) -> Result<u8>178 pub async fn nfc_set_config(&mut self, param_tlvs: &[u8]) -> Result<u8> { 179 let pbf = PacketBoundaryFlag::CompleteOrFinal; 180 if let Some(cmd) = self.commands.as_mut() { 181 let rp = cmd 182 .send( 183 CommandBuilder { 184 gid: 0, 185 pbf, 186 op: Opcode::CoreSetConfig, 187 payload: Some(Bytes::copy_from_slice(param_tlvs)), 188 } 189 .build(), 190 ) 191 .await?; 192 let raw = Bytes::from(rp); 193 if let Some(cb) = self.callback { 194 cb(2, &raw[3..]); 195 } 196 Ok(raw[3]) 197 } else { 198 Ok(nci::Status::NotInitialized as u8) 199 } 200 } 201 202 /** ***************************************************************************** 203 ** 204 ** Function NFC_GetConfig 205 ** 206 ** Description This function is called to retrieve the parameter TLV from 207 ** NFCC. The response from NFCC is reported by 208 ** tNFC_RESPONSE_CBACK as NFC_GET_CONFIG_REVT. 209 ** 210 ** Parameters num_ids - the number of parameter IDs 211 ** p_param_ids - the parameter ID list. 212 ** 213 ** Returns tNFC_STATUS 214 ** 215 *******************************************************************************/ 216 /// extern tNFC_STATUS NFC_GetConfig(uint8_t num_ids, uint8_t* p_param_ids); nfc_get_config(&mut self, param_tlvs: &[u8]) -> Result<u8>217 pub async fn nfc_get_config(&mut self, param_tlvs: &[u8]) -> Result<u8> { 218 let pbf = PacketBoundaryFlag::CompleteOrFinal; 219 if let Some(cmd) = self.commands.as_mut() { 220 let rp = cmd 221 .send( 222 CommandBuilder { 223 gid: 0, 224 pbf, 225 op: Opcode::CoreGetConfig, 226 payload: Some(Bytes::copy_from_slice(param_tlvs)), 227 } 228 .build(), 229 ) 230 .await?; 231 let raw = Bytes::from(rp); 232 if let Some(cb) = self.callback { 233 cb(3, &raw[3..]); 234 } 235 Ok(raw[3]) 236 } else { 237 Ok(nci::Status::NotInitialized as u8) 238 } 239 } 240 } 241 242 impl Default for NciApi { default() -> Self243 fn default() -> Self { 244 Self::new() 245 } 246 } 247