### Connect to Card and Transmit APDU Command Source: https://github.com/bluetech/pcsc-rust/blob/master/README.md This example demonstrates establishing a PC/SC context, listing readers, connecting to the first available card, and sending an APDU command. It handles potential errors during context establishment, reader listing, and card connection. The response from the card is printed to the console. ```rust use pcsc::* fn main() { // Establish a PC/SC context. let ctx = match Context::establish(Scope::User) { Ok(ctx) => ctx, Err(err) => { eprintln!("Failed to establish context: {}", err); std::process::exit(1); } }; // List available readers. let mut readers_buf = [0; 2048]; let mut readers = match ctx.list_readers(&mut readers_buf) { Ok(readers) => readers, Err(err) => { eprintln!("Failed to list readers: {}", err); std::process::exit(1); } }; // Use the first reader. let reader = match readers.next() { Some(reader) => reader, None => { println!("No readers are connected."); return; } }; println!("Using reader: {:?}", reader); // Connect to the card. let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) { Ok(card) => card, Err(Error::NoSmartcard) => { println!("A smartcard is not present in the reader."); return; } Err(err) => { eprintln!("Failed to connect to card: {}", err); std::process::exit(1); } }; // Send an APDU command. let apdu = b"\x00\xa4\x04\x00\x0a\xa0\x00\x00\x00\x62\x03\x01\x0c\x06\x01"; println!("Sending APDU: {:?}", apdu); let mut rapdu_buf = [0; MAX_BUFFER_SIZE]; let rapdu = match card.transmit(apdu, &mut rapdu_buf) { Ok(rapdu) => rapdu, Err(err) => { eprintln!("Failed to transmit APDU command to card: {}", err); std::process::exit(1); } }; println!("APDU response: {:?}", rapdu); } ``` -------------------------------- ### Get and Set Card Reader Attributes Source: https://context7.com/bluetech/pcsc-rust/llms.txt Demonstrates retrieving various reader attributes like ATR, vendor name, and IFD version using both fixed-size buffers and dynamic allocation. ```rust use pcsc::*; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Get ATR string attribute let mut atr_buf = [0; MAX_ATR_SIZE]; match card.get_attribute(Attribute::AtrString, &mut atr_buf) { Ok(atr) => println!("ATR: {:02X?}", atr), Err(err) => eprintln!("Failed to get ATR: {}", err), } // Get vendor name with dynamic buffer allocation match card.get_attribute_len(Attribute::VendorName) { Ok(len) => { let mut buf = vec![0; len]; if let Ok(name) = card.get_attribute(Attribute::VendorName, &mut buf) { println!("Vendor: {}", String::from_utf8_lossy(name)); } } Err(err) => eprintln!("Vendor name not available: {}", err), } // Get IFD version let mut version_buf = [0; 4]; match card.get_attribute(Attribute::VendorIfdVersion, &mut version_buf) { Ok(version) => println!("IFD Version: {:02X?}", version), Err(err) => eprintln!("IFD version not available: {}", err), } // Use owned variant (allocates internally) match card.get_attribute_owned(Attribute::DeviceFriendlyName) { Ok(name) => println!("Device name: {}", String::from_utf8_lossy(&name)), Err(err) => eprintln!("Device name not available: {}", err), } } ``` -------------------------------- ### Card::status2 - Get Card Status Source: https://context7.com/bluetech/pcsc-rust/llms.txt Retrieves the current status of the smart card, including reader names, card state, active protocol, and ATR. The `status2_owned()` method simplifies this process by automatically managing buffer allocations. ```APIDOC ## Card::status2 - Get Card Status ### Description Gets the current status of the card including reader names, card state, active protocol, and ATR. The `status2_owned()` variant handles buffer allocation automatically. ### Method GET ### Endpoint N/A (This is a library function, not a network endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use pcsc::* fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Method 1: Use pre-allocated buffers let (names_len, atr_len) = card.status2_len().expect("failed to get status lengths"); let mut names_buf = vec![0; names_len]; let mut atr_buf = vec![0; atr_len]; let status = card .status2(&mut names_buf, &mut atr_buf) .expect("failed to get status"); println!("Card Status: {:?}", status.status()); println!("Reader names: {:?}", status.reader_names().collect::>()); println!("ATR: {:02X?}", status.atr()); if let Some(protocol) = status.protocol2() { println!("Active protocol: {:?}", protocol); } // Method 2: Use owned variant (simpler) let status_owned = card.status2_owned().expect("failed to get status"); println!("Reader names (owned): {:?}", status_owned.reader_names()); println!("Status (owned): {:?}", status_owned.status()); } ``` ### Response #### Success Response (200) - **status** (CardStatus) - The current state of the card. - **reader_names** (Vec<&str>) - A list of reader names associated with the card. - **atr** (bytes) - The Answer to Reset (ATR) string of the card. - **protocol** (Option) - The active communication protocol, if available. #### Response Example ```json { "status": "Present", "reader_names": ["MyReader1", "MyReader2"], "atr": "[0x3B, 0x80, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00]", "protocol": "T0" } ``` ``` -------------------------------- ### Card::get_attribute / Card::set_attribute - Reader Attributes Source: https://context7.com/bluetech/pcsc-rust/llms.txt Retrieves or modifies attributes of a smart card reader or the card itself. This includes details like the vendor name, Answer to Reset (ATR) string, and device information. The examples demonstrate various methods for fetching attributes, including using pre-allocated buffers, dynamically sized buffers, and owned variants that handle allocation internally. ```APIDOC ## Card::get_attribute / Card::set_attribute - Reader Attributes ### Description Gets or sets attributes of the card reader or card. Common attributes include vendor name, ATR string, and device information. ### Method GET (for `get_attribute`, `get_attribute_len`, `get_attribute_owned`) ### Endpoint N/A (This is a library function, not a network endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use pcsc::* fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Get ATR string attribute let mut atr_buf = [0; MAX_ATR_SIZE]; match card.get_attribute(Attribute::AtrString, &mut atr_buf) { Ok(atr) => println!("ATR: {:02X?}", atr), Err(err) => eprintln!("Failed to get ATR: {}", err), } // Get vendor name with dynamic buffer allocation match card.get_attribute_len(Attribute::VendorName) { Ok(len) => { let mut buf = vec![0; len]; if let Ok(name) = card.get_attribute(Attribute::VendorName, &mut buf) { println!("Vendor: {}", String::from_utf8_lossy(name)); } } Err(err) => eprintln!("Vendor name not available: {}", err), } // Get IFD version let mut version_buf = [0; 4]; match card.get_attribute(Attribute::VendorIfdVersion, &mut version_buf) { Ok(version) => println!("IFD Version: {:02X?}", version), Err(err) => eprintln!("IFD version not available: {}", err), } // Use owned variant (allocates internally) match card.get_attribute_owned(Attribute::DeviceFriendlyName) { Ok(name) => println!("Device name: {}", String::from_utf8_lossy(&name)), Err(err) => eprintln!("Device name not available: {}", err), } } ``` ### Response #### Success Response (200) - **Attribute Data** (bytes) - The requested attribute value. #### Response Example ```json { "ATR": "[0x3B, 0x80, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x01, 0x02, 0x00, 0x00]", "Vendor": "Example Vendor", "IFD Version": "[0x01, 0x00, 0x00, 0x00]", "Device name": "Example Device" } ``` ``` -------------------------------- ### Context::establish Source: https://context7.com/bluetech/pcsc-rust/llms.txt Establishes a new connection to the PC/SC resource manager, which is the required entry point for all subsequent PC/SC operations. ```APIDOC ## Context::establish ### Description Establishes a new connection to the PC/SC resource manager. ### Parameters #### Request Body - **scope** (Scope) - Required - The scope of the context (e.g., Scope::User). ### Response #### Success Response (200) - **Context** (Object) - The established PC/SC context object. ``` -------------------------------- ### Establish PC/SC Context Source: https://context7.com/bluetech/pcsc-rust/llms.txt Initialize a connection to the PC/SC resource manager using a specified scope. ```rust use pcsc::*; fn main() { // Establish a PC/SC context with user scope let ctx = match Context::establish(Scope::User) { Ok(ctx) => ctx, Err(err) => { eprintln!("Failed to establish context: {}", err); std::process::exit(1); } }; // Verify the context is valid if let Err(err) = ctx.is_valid() { eprintln!("Context is not valid: {}", err); std::process::exit(1); } println!("Successfully established PC/SC context"); // Explicit release with error handling (optional - Drop will handle it) ctx.release() .map_err(|(_, err)| err) .expect("failed to release context"); } ``` -------------------------------- ### Perform Complete Smart Card Interaction Source: https://context7.com/bluetech/pcsc-rust/llms.txt A full workflow demonstrating context establishment, reader enumeration, card connection, transaction handling, and APDU communication. ```rust use pcsc::*; fn main() -> Result<(), Box> { // 1. Establish context let ctx = Context::establish(Scope::User)?; println!("Context established"); // 2. List readers let mut readers_buf = [0; 2048]; let readers: Vec<_> = ctx.list_readers(&mut readers_buf)?.collect(); if readers.is_empty() { println!("No readers found"); return Ok(()); } for (i, reader) in readers.iter().enumerate() { println!("Reader {}: {:?}", i, reader); } // 3. Connect to first reader with card let mut card = match ctx.connect(readers[0], ShareMode::Shared, Protocols::ANY) { Ok(card) => card, Err(Error::NoSmartcard) => { println!("No card in reader"); return Ok(()); } Err(e) => return Err(e.into()), }; println!("Connected to card"); // 4. Get card info let status = card.status2_owned()?; println!("Card status: {:?}", status.status()); println!("ATR: {:02X?}", status.atr()); println!("Protocol: {:?}", status.protocol2()); // 5. Begin transaction for exclusive access { let tx = card.transaction()?; println!("Transaction started"); // 6. Send SELECT command let select_mf = [0x00, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00]; // Select MF let mut response = [0u8; MAX_BUFFER_SIZE]; let rapdu = tx.transmit(&select_mf, &mut response)?; let sw = (rapdu[rapdu.len() - 2] as u16) << 8 | rapdu[rapdu.len() - 1] as u16; println!("SELECT MF response: {:02X?}", rapdu); println!("Status word: {:04X}", sw); // 7. Read binary data (if supported) let read_binary = [0x00, 0xB0, 0x00, 0x00, 0x10]; // Read 16 bytes match tx.transmit(&read_binary, &mut response) { Ok(rapdu) => { println!("READ BINARY response: {:02X?}", rapdu); } Err(e) => { println!("READ BINARY failed: {}", e); } } // Transaction automatically ends when tx goes out of scope println!("Transaction ended"); } // 8. Disconnect gracefully card.disconnect(Disposition::ResetCard) .map_err(|(_, e)| e)?; println!("Disconnected from card"); // 9. Release context ctx.release().map_err(|(_, e)| e)?; println!("Context released"); Ok(()) } ``` -------------------------------- ### Monitor Reader State with Context::get_status_change Source: https://context7.com/bluetech/pcsc-rust/llms.txt Blocks execution until a change in reader state occurs, such as card insertion or removal. Use PNP_NOTIFICATION to track hotplugging events. ```rust use pcsc::*; use std::time::Duration; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let mut reader_states = vec![ // Monitor for reader insertions/removals ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE), ]; // Add existing readers to monitor let names = ctx .list_readers(&mut readers_buf) .expect("failed to list readers"); for name in names { println!("Monitoring reader: {:?}", name); reader_states.push(ReaderState::new(name, State::UNAWARE)); } println!("Waiting for state changes (5 second timeout)..."); // Wait for state change with timeout match ctx.get_status_change(Duration::from_secs(5), &mut reader_states) { Ok(()) => { println!("State changed!"); for rs in &reader_states { if rs.name() != PNP_NOTIFICATION() { println!( "Reader: {:?}, State: {:?}, ATR: {:02X?}", rs.name(), rs.event_state(), rs.atr() ); // Check for card presence if rs.event_state().contains(State::PRESENT) { println!(" -> Card is present"); } if rs.event_state().contains(State::EMPTY) { println!(" -> No card in reader"); } } } } Err(Error::Timeout) => { println!("Timeout - no state changes detected"); } Err(err) => { eprintln!("Error: {}", err); } } } ``` -------------------------------- ### Send Direct Reader Control Commands Source: https://context7.com/bluetech/pcsc-rust/llms.txt Use this to communicate directly with the reader driver for features like LED control or firmware updates. Requires a connection with ShareMode::Direct. ```rust use pcsc::*; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); // Connect directly to reader (no card required) let card = ctx .connect(reader, ShareMode::Direct, Protocols::UNDEFINED) .expect("failed to connect to reader"); // Example: Get reader features (CCID escape command) // Control code varies by platform and reader let control_code = ctl_code(3500); // CM_IOCTL_GET_FEATURE_REQUEST let send_buffer: [u8; 0] = []; let mut recv_buffer = [0u8; 256]; match card.control(control_code, &send_buffer, &mut recv_buffer) { Ok(response) => { println!("Control response: {:02X?}", response); } Err(Error::UnsupportedFeature) => { println!("Control command not supported by this reader"); } Err(err) => { eprintln!("Control command failed: {}", err); } } } ``` -------------------------------- ### Connect to Smart Card Source: https://context7.com/bluetech/pcsc-rust/llms.txt Establish a connection to a smart card in a specific reader with defined share modes and protocols. ```rust use pcsc::*; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let mut readers = ctx .list_readers(&mut readers_buf) .expect("failed to list readers"); let reader = match readers.next() { Some(reader) => reader, None => { println!("No readers connected"); return; } }; // Connect to the card with shared access, accepting any protocol let card = match ctx.connect(reader, ShareMode::Shared, Protocols::ANY) { Ok(card) => card, Err(Error::NoSmartcard) => { println!("No smart card present in reader"); return; } Err(Error::SharingViolation) => { println!("Card is in use by another application"); return; } Err(err) => { eprintln!("Failed to connect: {}", err); return; } }; println!("Successfully connected to card"); // Disconnect with specific disposition card.disconnect(Disposition::ResetCard) .map_err(|(_, err)| err) .expect("failed to disconnect"); } ``` -------------------------------- ### Context::connect Source: https://context7.com/bluetech/pcsc-rust/llms.txt Connects to a smart card present in a specific reader using defined share modes and protocol masks. ```APIDOC ## Context::connect ### Description Connects to a smart card in the specified reader. ### Parameters #### Request Body - **reader** (CStr) - Required - The name of the reader to connect to. - **share_mode** (ShareMode) - Required - The sharing mode (e.g., Shared, Exclusive). - **protocol_mask** (Protocols) - Required - The bitmask of acceptable communication protocols. ### Response #### Success Response (200) - **Card** (Object) - The connected smart card object. ``` -------------------------------- ### Context::list_readers Source: https://context7.com/bluetech/pcsc-rust/llms.txt Enumerates all connected card readers available to the established PC/SC context. ```APIDOC ## Context::list_readers ### Description Lists all connected card readers. Returns an iterator over reader names stored in the provided buffer. ### Parameters #### Request Body - **buffer** ([u8]) - Required - A mutable buffer to store the reader names. ### Response #### Success Response (200) - **Readers** (Iterator) - An iterator over the reader names found in the buffer. ``` -------------------------------- ### Card::transmit - Send APDU Commands Source: https://context7.com/bluetech/pcsc-rust/llms.txt This snippet demonstrates how to send an APDU command to a connected smart card and receive its response using the `transmit` method. It includes error handling for insufficient buffer size and general transmission errors, as well as parsing the status words from the response. ```APIDOC ## Card::transmit - Send APDU Commands ### Description Transmits an APDU command to the connected card and receives the response. The receive buffer must be large enough to hold the response; use `MAX_BUFFER_SIZE` for standard APDUs or `MAX_BUFFER_SIZE_EXTENDED` for extended APDUs. ### Method POST (or equivalent for APDU transmission) ### Endpoint `/card/transmit` (Conceptual endpoint for APDU transmission) ### Parameters #### Request Body - **apdu_command** (bytes) - Required - The APDU command to send to the card. - **response_buffer_size** (integer) - Required - The size of the buffer allocated for the response. ### Request Example ```json { "apdu_command": "00A404000A315449432E494341", "response_buffer_size": 2048 } ``` ### Response #### Success Response (200) - **response_data** (bytes) - The data received from the card. - **status_words** (object) - The status words (SW1, SW2) indicating the command execution result. - **sw1** (hex) - The first status word. - **sw2** (hex) - The second status word. #### Response Example ```json { "response_data": "9000", "status_words": { "sw1": "90", "sw2": "00" } } ``` #### Error Response (e.g., 400, 500) - **error** (string) - A message describing the error (e.g., "InsufficientBuffer", "Failed to transmit APDU"). ``` -------------------------------- ### Transmit APDU Command to Card Source: https://context7.com/bluetech/pcsc-rust/llms.txt Sends an APDU command to a connected smart card and retrieves the response. Ensure the response buffer is adequately sized. Handles potential errors like insufficient buffer. ```rust use pcsc::* fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // SELECT command APDU (select application by AID) let select_apdu = b"\x00\xa4\x04\x00\x0a\xa0\x00\x00\x00\x62\x03\x01\x0c\x06\x01"; let mut response_buf = [0; MAX_BUFFER_SIZE]; let response = match card.transmit(select_apdu, &mut response_buf) { Ok(response) => response, Err(Error::InsufficientBuffer) => { eprintln!("Response buffer too small"); return; } Err(err) => { eprintln!("Failed to transmit APDU: {}", err); return; } }; println!("APDU command: {:02X?}", select_apdu); println!("Response: {:02X?}", response); // Parse status words (last 2 bytes) if response.len() >= 2 { let sw1 = response[response.len() - 2]; let sw2 = response[response.len() - 1]; println!("Status: SW1={:02X} SW2={:02X}", sw1, sw2); if sw1 == 0x90 && sw2 == 0x00 { println!("Command successful"); } } } ``` -------------------------------- ### Reconnect to Card Source: https://context7.com/bluetech/pcsc-rust/llms.txt Demonstrates reconnecting to a card, often used for error recovery or resetting the connection state. ```rust use pcsc::*; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let mut card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Attempt some operation let apdu = b"\x00\xa4\x04\x00\x00"; let mut response_buf = [0; MAX_BUFFER_SIZE]; match card.transmit(apdu, &mut response_buf) { Ok(response) => println!("Response: {:02X?}", response), Err(Error::ResetCard) => { println!("Card was reset, reconnecting..."); card.reconnect(ShareMode::Shared, Protocols::ANY, Disposition::LeaveCard) .expect("failed to reconnect"); // Retry the operation let response = card .transmit(apdu, &mut response_buf) .expect("failed to transmit after reconnect"); println!("Response after reconnect: {:02X?}", response); } Err(err) => eprintln!("Error: {}", err), } } ``` -------------------------------- ### Add pcsc to Cargo.toml Source: https://github.com/bluetech/pcsc-rust/blob/master/README.md Include the pcsc crate in your project's dependencies by adding this to your Cargo.toml file. ```toml [dependencies] pcsc = "2" ``` -------------------------------- ### Enumerate Card Readers Source: https://context7.com/bluetech/pcsc-rust/llms.txt Retrieve a list of connected card readers using pre-allocated buffers, exact sizing, or owned variants. ```rust use pcsc::*; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); // Method 1: Use a pre-allocated buffer let mut readers_buf = [0; 2048]; let readers = ctx .list_readers(&mut readers_buf) .expect("failed to list readers"); println!("Connected readers:"); for reader in readers { println!(" {:?}", reader); } // Method 2: Allocate exact buffer size let len = ctx.list_readers_len().expect("failed to get buffer length"); let mut exact_buf = vec![0; len]; let readers = ctx.list_readers(&mut exact_buf).expect("failed to list readers"); for reader in readers { println!("Reader: {}", reader.to_str().unwrap()); } // Method 3: Use owned variant (allocates internally) let owned_readers = ctx.list_readers_owned().expect("failed to list readers"); for reader in &owned_readers { println!("Owned reader: {:?}", reader); } } ``` -------------------------------- ### Card::transaction - Exclusive Card Access Source: https://context7.com/bluetech/pcsc-rust/llms.txt This snippet illustrates how to initiate an exclusive transaction with a smart card. During the transaction, no other process can access the card. Operations performed within the transaction are managed through a `Transaction` object, which ensures exclusive access until it is dropped or explicitly ended. ```APIDOC ## Card::transaction - Exclusive Card Access ### Description Starts an exclusive transaction with the card, preventing other processes from accessing it. All card operations during the transaction are performed through the `Transaction` object. The transaction ends when dropped or explicitly ended. ### Method POST (or equivalent for initiating transaction) ### Endpoint `/card/transaction` (Conceptual endpoint for transaction management) ### Parameters #### Request Body - **card_handle** (string) - Required - Identifier for the card connection. - **disposition** (string) - Optional - The desired state of the card after the transaction (e.g., "LeaveCard", "ResetCard", "UnpowerCard"). Defaults to "LeaveCard". ### Request Example ```json { "card_handle": "connection_id_123", "disposition": "LeaveCard" } ``` ### Response #### Success Response (200) - **transaction_id** (string) - A unique identifier for the initiated transaction. - **message** (string) - Confirmation message (e.g., "Transaction started successfully"). #### Response Example ```json { "transaction_id": "tx_abcde12345", "message": "Transaction started successfully" } ``` ### Operations within Transaction Once a transaction is established, subsequent operations like `transmit` and `status` are performed using the `Transaction` object. #### Example: Transmit APDU within Transaction ```rust let response = tx.transmit(select_apdu, &mut response_buf).expect("failed to transmit APDU"); ``` #### Example: Get Card Status within Transaction ```rust let status = tx.status2(&mut names_buf, &mut atr_buf).expect("failed to get status"); ``` ### Ending a Transaction Transactions can be ended explicitly using the `end` method, specifying the desired card disposition. #### Example: End Transaction ```rust tx.end(Disposition::LeaveCard).map_err(|(_, err)| err).expect("failed to end transaction"); ``` #### Error Response (e.g., 400, 500) - **error** (string) - A message describing the error (e.g., "Failed to begin transaction", "Failed to end transaction"). ``` -------------------------------- ### Card::reconnect - Reconnect to Card Source: https://context7.com/bluetech/pcsc-rust/llms.txt Allows reconnecting to a smart card. This operation can optionally reset the card and is useful for recovering from errors or changing connection parameters like sharing mode and protocol. ```APIDOC ## Card::reconnect - Reconnect to Card ### Description Reconnects to the card, optionally resetting it. Useful for error recovery or changing the connection parameters. ### Method POST (conceptually, as it modifies connection state) ### Endpoint N/A (This is a library function, not a network endpoint) ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```rust use pcsc::* fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let mut card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Attempt some operation let apdu = b"\x00\xa4\x04\x00\x00"; let mut response_buf = [0; MAX_BUFFER_SIZE]; match card.transmit(apdu, &mut response_buf) { Ok(response) => println!("Response: {:02X?}", response), Err(Error::ResetCard) => { println!("Card was reset, reconnecting..."); card.reconnect(ShareMode::Shared, Protocols::ANY, Disposition::LeaveCard) .expect("failed to reconnect"); // Retry the operation let response = card .transmit(apdu, &mut response_buf) .expect("failed to transmit after reconnect"); println!("Response after reconnect: {:02X?}", response); } Err(err) => eprintln!("Error: {}", err), } } ``` ### Response #### Success Response (200) Indicates successful reconnection. The specific return value depends on the subsequent operation attempted after reconnection. #### Response Example ```json { "message": "Successfully reconnected to the card." } ``` ``` -------------------------------- ### Retrieve Card Status Source: https://context7.com/bluetech/pcsc-rust/llms.txt Retrieves card status including reader names, state, and protocol. The status2_owned variant simplifies memory management by handling buffer allocation. ```rust use pcsc::*; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Method 1: Use pre-allocated buffers let (names_len, atr_len) = card.status2_len().expect("failed to get status lengths"); let mut names_buf = vec![0; names_len]; let mut atr_buf = vec![0; atr_len]; let status = card .status2(&mut names_buf, &mut atr_buf) .expect("failed to get status"); println!("Card Status: {:?}", status.status()); println!("Reader names: {:?}", status.reader_names().collect::>()); println!("ATR: {:02X?}", status.atr()); if let Some(protocol) = status.protocol2() { println!("Active protocol: {:?}", protocol); } // Method 2: Use owned variant (simpler) let status_owned = card.status2_owned().expect("failed to get status"); println!("Reader names (owned): {:?}", status_owned.reader_names()); println!("Status (owned): {:?}", status_owned.status()); } ``` -------------------------------- ### Cancel Blocking Operations with Context::cancel Source: https://context7.com/bluetech/pcsc-rust/llms.txt Interrupts a blocking operation on a context from a separate thread. Essential for implementing clean shutdowns or user-triggered cancellations. ```rust use pcsc::*; use std::time::Duration; fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); // Clone context for use in another thread let ctx_cancel = ctx.clone(); // Spawn cancellation thread std::thread::spawn(move || { std::thread::sleep(Duration::from_secs(2)); println!("Cancelling blocking operation..."); ctx_cancel.cancel().expect("failed to cancel"); }); // Set up blocking call let mut reader_states = vec![ReaderState::new(PNP_NOTIFICATION(), State::UNAWARE)]; println!("Entering blocking call (will be cancelled in 2 seconds)..."); match ctx.get_status_change(None, &mut reader_states) { Ok(()) => println!("Blocking call completed normally"), Err(Error::Cancelled) => println!("Operation was cancelled"), Err(Error::Timeout) => println!("Operation timed out"), Err(err) => eprintln!("Error: {}", err), } } ``` -------------------------------- ### Exclusive Card Access Transaction Source: https://context7.com/bluetech/pcsc-rust/llms.txt Initiates an exclusive transaction for card operations, preventing concurrent access. Operations are performed via the `Transaction` object, which ends when dropped or explicitly terminated. ```rust use pcsc::* fn main() { let ctx = Context::establish(Scope::User).expect("failed to establish context"); let mut readers_buf = [0; 2048]; let reader = ctx .list_readers(&mut readers_buf) .expect("failed to list readers") .next() .expect("no readers connected"); let mut card = ctx .connect(reader, ShareMode::Shared, Protocols::ANY) .expect("failed to connect to card"); // Begin exclusive transaction let tx = card.transaction().expect("failed to begin transaction"); // All operations within transaction are exclusive let select_apdu = b"\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41"; let mut response_buf = [0; MAX_BUFFER_SIZE]; let response = tx .transmit(select_apdu, &mut response_buf) .expect("failed to transmit APDU"); println!("Response: {:02X?}", response); // Get card status within transaction let mut names_buf = vec![0; 256]; let mut atr_buf = [0; MAX_ATR_SIZE]; let status = tx .status2(&mut names_buf, &mut atr_buf) .expect("failed to get status"); println!("Card status: {:?}", status.status()); println!("Protocol: {:?}", status.protocol2()); println!("ATR: {:02X?}", status.atr()); // End transaction with specific disposition tx.end(Disposition::LeaveCard) .map_err(|(_, err)| err) .expect("failed to end transaction"); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.