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, LogicalConnectionsRegistry, Result}; 18 use bytes::Bytes; 19 use log::{debug, error}; 20 use nfc_hal::{HalEvent, HalEventRegistry, HalEventStatus}; 21 use nfc_packets::nci::RfMappingConfiguration; 22 use nfc_packets::nci::{self, CommandBuilder, DataPacket, Opcode}; 23 use nfc_packets::nci::{ConnCloseCommandBuilder, ConnCreateCommandBuilder}; 24 use nfc_packets::nci::{DestParam, DestParamTypes, DestTypes}; 25 use nfc_packets::nci::{FeatureEnable, PacketBoundaryFlag, ResetType}; 26 use nfc_packets::nci::{InitCommandBuilder, ResetCommandBuilder}; 27 use nfc_packets::nci::{InitResponse, ResponseChild}; 28 use pdl_runtime::Packet; 29 use tokio::sync::oneshot; 30 31 type ConnCallback = fn(u8, u16, &[u8]); 32 33 struct NfcData { 34 init_response: Option<InitResponse>, 35 rf_callback: Option<ConnCallback>, 36 hci_callback: Option<ConnCallback>, 37 } 38 39 type RespCallback = fn(u16, &[u8]); 40 41 /// NCI API object to manage static API data 42 pub struct NciApi { 43 /// Command Sender external interface 44 commands: Option<CommandSender>, 45 /// Interface to Logical Connections Registry 46 connections: Option<LogicalConnectionsRegistry>, 47 /// The NFC response callback 48 callback: Option<RespCallback>, 49 /// HalEventRegistry is used to register for HAL events 50 hal_events: Option<HalEventRegistry>, 51 nfc_data: NfcData, 52 } 53 54 impl NciApi { 55 /// NciApi constructor new() -> NciApi56 pub fn new() -> NciApi { 57 let nfc_data = NfcData { init_response: None, rf_callback: None, hci_callback: None }; 58 NciApi { commands: None, connections: None, callback: None, hal_events: None, nfc_data } 59 } 60 61 /** **************************************************************************** 62 ** 63 ** Function nfc_enable 64 ** 65 ** Description This function enables NFC. Prior to calling NFC_Enable: 66 ** - the NFCC must be powered up, and ready to receive 67 ** commands. 68 ** 69 ** This function opens the NCI transport (if applicable), 70 ** resets the NFC controller, and initializes the NFC 71 ** subsystems. 72 ** 73 ** When the NFC startup procedure is completed, an 74 ** NFC_ENABLE_REVT is returned to the application using the 75 ** tNFC_RESPONSE_CBACK. 76 ** 77 ** Returns tNFC_STATUS 78 ** 79 *******************************************************************************/ 80 /// extern tNFC_STATUS NFC_Enable(tNFC_RESPONSE_CBACK* p_cback); nfc_enable(&mut self, callback: RespCallback)81 pub async fn nfc_enable(&mut self, callback: RespCallback) { 82 let nci = crate::init().await; 83 84 self.commands = Some(nci.commands); 85 self.connections = Some(nci.connections); 86 self.callback = Some(callback); 87 self.hal_events = Some(nci.hal_events); 88 } 89 /** **************************************************************************** 90 ** 91 ** Function NFC_Disable 92 ** 93 ** Description This function performs clean up routines for shutting down 94 ** NFC and closes the NCI transport (if using dedicated NCI 95 ** transport). 96 ** 97 ** When the NFC shutdown procedure is completed, an 98 ** NFC_DISABLED_REVT is returned to the application using the 99 ** tNFC_RESPONSE_CBACK. 100 ** 101 ** Returns nothing 102 ** 103 *******************************************************************************/ 104 /// extern void NFC_Disable(void); nfc_disable(&mut self)105 pub async fn nfc_disable(&mut self) { 106 let (tx, rx) = oneshot::channel::<HalEventStatus>(); 107 if let Some(mut event) = self.hal_events.take() { 108 event.register(HalEvent::CloseComplete, tx).await; 109 110 if let Some(cmd) = self.commands.take() { 111 drop(cmd); 112 } 113 if let Some(conn) = self.connections.take() { 114 drop(conn); 115 } 116 let status = rx.await.unwrap(); 117 debug!("Shutdown complete {:?}.", status); 118 119 if let Some(cb) = self.callback.take() { 120 cb(1, &[]); 121 } 122 } 123 } 124 125 /** **************************************************************************** 126 ** 127 ** Function NFC_Init 128 ** 129 ** Description This function initializes control blocks for NFC 130 ** 131 ** Returns nothing 132 ** 133 *******************************************************************************/ 134 /// extern void NFC_Init(tHAL_NFC_ENTRY* p_hal_entry_tbl); nfc_init(&mut self) -> Result<()>135 pub async fn nfc_init(&mut self) -> Result<()> { 136 let pbf = PacketBoundaryFlag::CompleteOrFinal; 137 if let Some(cmd) = self.commands.as_mut() { 138 let reset = cmd 139 .send_and_notify( 140 ResetCommandBuilder { gid: 0, pbf, reset_type: ResetType::ResetConfig } 141 .build() 142 .into(), 143 ) 144 .await?; 145 let _notification_packet = reset.notification.await?; 146 let init = cmd 147 .send( 148 InitCommandBuilder { gid: 0, pbf, feature_enable: FeatureEnable::Rfu } 149 .build() 150 .into(), 151 ) 152 .await?; 153 if let ResponseChild::InitResponse(irp) = init.specialize() { 154 if let Some(conn) = self.connections.as_mut() { 155 // Open static RF connection 156 // TODO: use channels instead of callcacks here 157 // the data can be tranlated to c-callback at the shim level 158 conn.open(0, self.nfc_data.rf_callback, 0, 0).await; 159 // Open static HCI connection 160 conn.open( 161 1, /* TODO: link constants to the c header */ 162 self.nfc_data.hci_callback, 163 irp.get_max_data_payload(), 164 irp.get_num_of_credits(), 165 ) 166 .await; 167 } 168 self.nfc_data.init_response = Some(irp); 169 } 170 } 171 Ok(()) 172 } 173 174 /** ***************************************************************************** 175 ** 176 ** Function NFC_GetLmrtSize 177 ** 178 ** Description Called by application wto query the Listen Mode Routing 179 ** Table size supported by NFCC 180 ** 181 ** Returns Listen Mode Routing Table size 182 ** 183 *******************************************************************************/ 184 /// extern uint16_t NFC_GetLmrtSize(void); nfc_get_lmrt_size(&mut self) -> u16185 pub async fn nfc_get_lmrt_size(&mut self) -> u16 { 186 if let Some(ir) = &self.nfc_data.init_response { 187 ir.get_max_rout_tbls_size() 188 } else { 189 0 190 } 191 } 192 193 /** ***************************************************************************** 194 ** 195 ** Function NFC_SetConfig 196 ** 197 ** Description This function is called to send the configuration parameter 198 ** TLV to NFCC. The response from NFCC is reported by 199 ** tNFC_RESPONSE_CBACK as NFC_SET_CONFIG_REVT. 200 ** 201 ** Parameters tlv_size - the length of p_param_tlvs. 202 ** p_param_tlvs - the parameter ID/Len/Value list 203 ** 204 ** Returns tNFC_STATUS 205 ** 206 *******************************************************************************/ 207 /// extern tNFC_STATUS NFC_SetConfig(uint8_t tlv_size, uint8_t* p_param_tlvs); nfc_set_config(&mut self, param_tlvs: &[u8]) -> Result<u8>208 pub async fn nfc_set_config(&mut self, param_tlvs: &[u8]) -> Result<u8> { 209 let pbf = PacketBoundaryFlag::CompleteOrFinal; 210 if let Some(cmd) = self.commands.as_mut() { 211 let raw = cmd 212 .send( 213 CommandBuilder { 214 gid: 0, 215 pbf, 216 op: Opcode::CoreSetConfig, 217 payload: Some(Bytes::copy_from_slice(param_tlvs)), 218 } 219 .build(), 220 ) 221 .await? 222 .encode_to_bytes()?; 223 if let Some(cb) = self.callback { 224 cb(2, &raw[3..]); 225 } 226 Ok(raw[3]) 227 } else { 228 Ok(nci::Status::NotInitialized as u8) 229 } 230 } 231 232 /** ***************************************************************************** 233 ** 234 ** Function NFC_GetConfig 235 ** 236 ** Description This function is called to retrieve the parameter TLV from 237 ** NFCC. The response from NFCC is reported by 238 ** tNFC_RESPONSE_CBACK as NFC_GET_CONFIG_REVT. 239 ** 240 ** Parameters num_ids - the number of parameter IDs 241 ** p_param_ids - the parameter ID list. 242 ** 243 ** Returns tNFC_STATUS 244 ** 245 *******************************************************************************/ 246 /// extern tNFC_STATUS NFC_GetConfig(uint8_t num_ids, uint8_t* p_param_ids); nfc_get_config(&mut self, param_tlvs: &[u8]) -> Result<u8>247 pub async fn nfc_get_config(&mut self, param_tlvs: &[u8]) -> Result<u8> { 248 let pbf = PacketBoundaryFlag::CompleteOrFinal; 249 if let Some(cmd) = self.commands.as_mut() { 250 let raw = cmd 251 .send( 252 CommandBuilder { 253 gid: 0, 254 pbf, 255 op: Opcode::CoreGetConfig, 256 payload: Some(Bytes::copy_from_slice(param_tlvs)), 257 } 258 .build(), 259 ) 260 .await? 261 .encode_to_bytes()?; 262 if let Some(cb) = self.callback { 263 cb(3, &raw[3..]); 264 } 265 Ok(raw[3]) 266 } else { 267 Ok(nci::Status::NotInitialized as u8) 268 } 269 } 270 /** **************************************************************************** 271 ** 272 ** Function NFC_ConnCreate 273 ** 274 ** Description This function is called to create a logical connection with 275 ** NFCC for data exchange. 276 ** The response from NFCC is reported in tNFC_CONN_CBACK 277 ** as NFC_CONN_CREATE_CEVT. 278 ** 279 ** Parameters dest_type - the destination type 280 ** id - the NFCEE ID or RF Discovery ID . 281 ** protocol - the protocol 282 ** p_cback - the data callback function to receive data from 283 ** NFCC 284 ** 285 ** Returns tNFC_STATUS 286 ** 287 *******************************************************************************/ 288 //extern tNFC_STATUS NFC_ConnCreate(uint8_t dest_type, uint8_t id, 289 // uint8_t protocol, tNFC_CONN_CBACK* p_cback); nfc_conn_create( &mut self, dest_type: u8, id: u8, protocol: u8, callback: ConnCallback, ) -> Result<u8>290 pub async fn nfc_conn_create( 291 &mut self, 292 dest_type: u8, 293 id: u8, 294 protocol: u8, 295 callback: ConnCallback, 296 ) -> Result<u8> { 297 let pbf = PacketBoundaryFlag::CompleteOrFinal; 298 let mut destparams: Vec<DestParam> = vec![]; 299 let dt = DestTypes::try_from(dest_type).unwrap(); 300 match dt { 301 DestTypes::NfccLpbk => (), 302 DestTypes::Remote => { 303 let parameter = vec![id, protocol]; 304 destparams.push(DestParam { ptype: DestParamTypes::RfDisc, parameter }); 305 } 306 DestTypes::Nfcee => { 307 let parameter: Vec<u8> = vec![id, protocol]; 308 destparams.push(DestParam { ptype: DestParamTypes::Nfcee, parameter }); 309 } 310 _ => return Ok(nci::Status::InvalidParam as u8), 311 } 312 if let Some(cmd) = self.commands.as_mut() { 313 let rp = cmd 314 .send(ConnCreateCommandBuilder { gid: 0, pbf, dt, destparams }.build().into()) 315 .await?; 316 if let ResponseChild::ConnCreateResponse(ccrp) = rp.specialize() { 317 let status = ccrp.get_status(); 318 if status == nci::Status::Ok { 319 if let Some(conn) = self.connections.as_mut() { 320 conn.open( 321 ccrp.get_conn_id(), 322 Some(callback), 323 ccrp.get_mpps(), 324 ccrp.get_ncreds(), 325 ) 326 .await; 327 let conn_create_evt = 328 [status as u8, dest_type, id, ccrp.get_mpps(), ccrp.get_ncreds()]; 329 callback(ccrp.get_conn_id(), 0, &conn_create_evt[..]); 330 } else { 331 return Ok(nci::Status::NotInitialized as u8); 332 } 333 } 334 Ok(status as u8) 335 } else { 336 Ok(nci::Status::Failed as u8) 337 } 338 } else { 339 Ok(nci::Status::NotInitialized as u8) 340 } 341 } 342 343 /** **************************************************************************** 344 ** 345 ** Function NFC_ConnClose 346 ** 347 ** Description This function is called to close a logical connection with 348 ** NFCC. 349 ** The response from NFCC is reported in tNFC_CONN_CBACK 350 ** as NFC_CONN_CLOSE_CEVT. 351 ** 352 ** Parameters conn_id - the connection id. 353 ** 354 ** Returns tNFC_STATUS 355 ** 356 *******************************************************************************/ 357 //extern tNFC_STATUS NFC_ConnClose(uint8_t conn_id); nfc_conn_close(&mut self, conn_id: u8) -> Result<u8>358 pub async fn nfc_conn_close(&mut self, conn_id: u8) -> Result<u8> { 359 let pbf = PacketBoundaryFlag::CompleteOrFinal; 360 if let Some(conn) = self.connections.as_mut() { 361 if let Some(cb) = conn.close(conn_id).await { 362 if let Some(cmd) = self.commands.as_mut() { 363 let rp = cmd 364 .send(ConnCloseCommandBuilder { gid: 0, pbf, conn_id }.build().into()) 365 .await?; 366 if let ResponseChild::ConnCloseResponse(ccrp) = rp.specialize() { 367 let status = ccrp.get_status() as u8; 368 let conn_close_evt = [status]; 369 cb(conn_id, 1, &conn_close_evt[..]); 370 return Ok(status); 371 } else { 372 return Ok(nci::Status::Failed as u8); 373 } 374 } 375 } else { 376 return Ok(nci::Status::InvalidParam as u8); 377 } 378 } 379 Ok(nci::Status::NotInitialized as u8) 380 } 381 382 /** ***************************************************************************** 383 ** 384 ** Function NFC_SetStaticRfCback 385 ** 386 ** Description This function is called to update the data callback function 387 ** to receive the data for the given connection id. 388 ** 389 ** Parameters p_cback - the connection callback function 390 ** 391 ** Returns Nothing 392 ** 393 *******************************************************************************/ 394 //extern void NFC_SetStaticRfCback(tNFC_CONN_CBACK* p_cback); nfc_set_static_rf_callback(&mut self, callback: ConnCallback)395 pub async fn nfc_set_static_rf_callback(&mut self, callback: ConnCallback) { 396 self.nfc_data.rf_callback = Some(callback); 397 if let Some(conn) = self.connections.as_mut() { 398 conn.set_static_callback(0, Some(callback)).await; 399 } 400 } 401 402 /** ***************************************************************************** 403 ** 404 ** Function NFC_SetStaticHciCback 405 ** 406 ** Description This function to update the data callback function 407 ** to receive the data for the static Hci connection id. 408 ** 409 ** Parameters p_cback - the connection callback function 410 ** 411 ** Returns Nothing 412 ** 413 *******************************************************************************/ 414 //extern void NFC_SetStaticHciCback(tNFC_CONN_CBACK* p_cback); nfc_set_static_hci_callback(&mut self, callback: ConnCallback)415 pub async fn nfc_set_static_hci_callback(&mut self, callback: ConnCallback) { 416 self.nfc_data.hci_callback = Some(callback); 417 if let Some(conn) = self.connections.as_mut() { 418 conn.set_static_callback(1, Some(callback)).await; 419 } 420 } 421 422 /******************************************************************************* 423 ** 424 ** Function NFC_SetReassemblyFlag 425 ** 426 ** Description This function is called to set if nfc will reassemble 427 ** nci packet as much as its buffer can hold or it should not 428 ** reassemble but forward the fragmented nci packet to layer 429 ** above. If nci data pkt is fragmented, nfc may send multiple 430 ** NFC_DATA_CEVT with status NFC_STATUS_CONTINUE before sending 431 ** NFC_DATA_CEVT with status NFC_STATUS_OK based on reassembly 432 ** configuration and reassembly buffer size 433 ** 434 ** Parameters reassembly - flag to indicate if nfc may reassemble or not 435 ** 436 ** Returns Nothing 437 ** 438 *******************************************************************************/ 439 //extern void NFC_SetReassemblyFlag(bool reassembly); 440 441 /** **************************************************************************** 442 ** 443 ** Function NFC_SendData 444 ** 445 ** Description This function is called to send the given data packet 446 ** to the connection identified by the given connection id. 447 ** 448 ** Parameters conn_id - the connection id. 449 ** p_data - the data packet 450 ** 451 ** Returns tNFC_STATUS 452 ** 453 *******************************************************************************/ 454 //extern tNFC_STATUS NFC_SendData(uint8_t conn_id, NFC_HDR* p_data); nfc_send_data(&mut self, conn_id: u8, data: &[u8]) -> Result<u8>455 pub async fn nfc_send_data(&mut self, conn_id: u8, data: &[u8]) -> Result<u8> { 456 if let Some(conn) = self.connections.as_mut() { 457 match DataPacket::parse(data) { 458 Ok(pkt) => { 459 conn.send_packet(conn_id, pkt).await; 460 return Ok(nci::Status::Ok as u8); 461 } 462 Err(e) => { 463 error!("Data packet is invalid:{:?}", e); 464 return Ok(nci::Status::InvalidParam as u8); 465 } 466 } 467 } 468 Ok(nci::Status::NotInitialized as u8) 469 } 470 471 /** **************************************************************************** 472 ** 473 ** Function NFC_FlushData 474 ** 475 ** Description This function is called to discard the tx data queue of 476 ** the given connection id. 477 ** 478 ** Parameters conn_id - the connection id. 479 ** 480 ** Returns tNFC_STATUS 481 ** 482 *******************************************************************************/ 483 //extern tNFC_STATUS NFC_FlushData(uint8_t conn_id); nfc_flush_data(&mut self, conn_id: u8) -> Result<u8>484 pub async fn nfc_flush_data(&mut self, conn_id: u8) -> Result<u8> { 485 if let Some(conn) = self.connections.as_mut() { 486 if conn.flush_data(conn_id).await { 487 Ok(nci::Status::Ok as u8) 488 } else { 489 Ok(nci::Status::Failed as u8) 490 } 491 } else { 492 Ok(nci::Status::NotInitialized as u8) 493 } 494 } 495 496 /** **************************************************************************** 497 ** 498 ** Function NFC_DiscoveryMap 499 ** 500 ** Description This function is called to set the discovery interface 501 ** mapping. The response from NFCC is reported by 502 ** tNFC_DISCOVER_CBACK as. NFC_MAP_DEVT. 503 ** 504 ** Parameters num - the number of items in p_params. 505 ** p_maps - the discovery interface mappings 506 ** p_cback - the discovery callback function 507 ** 508 ** Returns tNFC_STATUS 509 ** 510 *******************************************************************************/ 511 // extern tNFC_STATUS NFC_DiscoveryMap(uint8_t num, tNFC_DISCOVER_MAPS* p_maps, 512 // tNFC_DISCOVER_CBACK* p_cback); nfc_discovery_map(&mut self, _maps: Vec<RfMappingConfiguration>) -> Result<u8>513 pub async fn nfc_discovery_map(&mut self, _maps: Vec<RfMappingConfiguration>) -> Result<u8> { 514 Ok(0) 515 } 516 517 /******************************************************************************* 518 ** 519 ** Function NFC_DiscoveryStart 520 ** 521 ** Description This function is called to start Polling and/or Listening. 522 ** The response from NFCC is reported by tNFC_DISCOVER_CBACK 523 ** as NFC_START_DEVT. The notification from NFCC is reported by 524 ** tNFC_DISCOVER_CBACK as NFC_RESULT_DEVT. 525 ** 526 ** Parameters num_params - the number of items in p_params. 527 ** p_params - the discovery parameters 528 ** p_cback - the discovery callback function 529 ** 530 ** Returns tNFC_STATUS 531 ** 532 *******************************************************************************/ 533 // extern tNFC_STATUS NFC_DiscoveryStart(uint8_t num_params, 534 // tNFC_DISCOVER_PARAMS* p_params, 535 // tNFC_DISCOVER_CBACK* p_cback); 536 537 /******************************************************************************* 538 ** 539 ** Function NFC_DiscoverySelect 540 ** 541 ** Description If tNFC_DISCOVER_CBACK reports status=NFC_MULTIPLE_PROT, 542 ** the application needs to use this function to select the 543 ** the logical endpoint to continue. The response from NFCC is 544 ** reported by tNFC_DISCOVER_CBACK as NFC_SELECT_DEVT. 545 ** 546 ** Parameters rf_disc_id - The ID identifies the remote device. 547 ** protocol - the logical endpoint on the remote device 548 ** rf_interface - the RF interface to communicate with NFCC 549 ** 550 ** Returns tNFC_STATUS 551 ** 552 *******************************************************************************/ 553 // extern tNFC_STATUS NFC_DiscoverySelect(uint8_t rf_disc_id, uint8_t protocol, 554 // uint8_t rf_interface); 555 } 556 557 impl Default for NciApi { default() -> Self558 fn default() -> Self { 559 Self::new() 560 } 561 } 562