uem_reader/commands/
cards.rs

1//! General commands to interact with RFID tags
2
3#![allow(dead_code)]
4
5pub mod mifare;
6
7use crate::reader::*;
8use crate::commands::cards::mifare::*;
9use crate::errors::*;
10use crate::card::*;
11
12#[derive(Debug, Clone, Copy)]
13/// Card activation parameters
14/// 
15/// This structure can be used to both activate cards 
16/// of type ISO14443A and ISO14443B
17pub struct UemActivateParameters {
18    // standard: UemCardStandard,
19    /// Required [baudrate](UemCardBaudrates) of card -> reader channel
20    pub baudrate_card_reader: UemCardBaudrates,
21    /// Required [baudrate](UemCardBaudrates) of reader -> card channel
22    pub baudrate_reader_card: UemCardBaudrates,
23    /// Time in milliseconds to turn radio off before
24    /// requesting next card.
25    pub radio_off_period: u8,
26    /// After a radio field has been turned on,
27    /// it is necessary to give cards little time
28    /// to fully power up. Set in milliseconds.
29    pub pause_after_radio_on: u8,
30    /// Enables cards to be automatically switched to 
31    /// T=CL protocol (ISO14443-4)
32    pub switch_to_tcl: bool,
33    /// If switched to T=CL, then which card identifier
34    /// (CID) to use
35    pub tcl_cid: u8,
36    /// For cards of type ISO14443B - 
37    /// application family identifier
38    pub btype_afi: u8,
39    /// For cards of type ISO14443B - 
40    /// request extended answer to query data
41    pub btype_use_ext_atqb: bool,
42    /// For cards of type ISO14443B - 
43    /// number of time slots to use
44    pub btype_time_slots: u8,
45}
46
47impl Default for UemActivateParameters {
48    fn default() -> UemActivateParameters {
49        UemActivateParameters {
50            // standard: UemCardStandard::Iso14443a,
51            baudrate_card_reader: UemCardBaudrates::Baud106kbps,
52            baudrate_reader_card: UemCardBaudrates::Baud106kbps,
53            radio_off_period: 10,
54            pause_after_radio_on: 10,
55            switch_to_tcl: false,
56            tcl_cid: 0x00,
57            btype_afi: 0x00,
58            btype_use_ext_atqb: false,
59            btype_time_slots: 1,
60        }
61    }
62}
63
64/// Structure for commands to interact
65/// with cards
66pub struct UemCommandsCards<'a> {
67    reader: &'a UemReader,
68}
69
70/// Accessing cards related commands group
71pub trait UemCommandsCardsTrait {
72    fn cards(&mut self) -> UemCommandsCards;
73}
74
75impl<'a> UemCommandsCardsMifareTrait for UemCommandsCards<'a> {   
76    fn mifare(&mut self) -> UemCommandsCardsMifare {
77        UemCommandsCardsMifare::new(self.as_reader())
78    }
79}
80
81impl<'a> UemCommandsCards<'a> {
82    pub(crate) fn new(rd: &'a UemReader) -> Self {
83        UemCommandsCards {reader: rd}
84    }
85
86    pub(crate) fn as_reader(&self) -> &'a UemReader {
87        self.reader
88    }
89
90    /// Activation of type ISO14443A card
91    /// 
92    /// # Arguments
93    ///
94    /// * `parameters` - A reference to a set of [parameters](UemActivateParameters) to tweak activation,
95    /// 
96    /// # Returns
97    /// 
98    /// `Ok(())` on success, otherwise returns an error.
99    /// 
100    /// # Example
101    /// ```ignore
102    /// let card = uem_reader.commands().cards().activate_a(&UemActivateParameters{
103    ///     // switch_to_tcl: true, // Can be used to set T=CL protocol after activation
104    ///     ..Default::default()
105    /// });
106    /// ```
107    pub fn activate_a(&mut self, parameters: &UemActivateParameters) -> UemResultCardA {
108        let mut raw_reader = self.reader.lock().unwrap();
109        let mut type_baud: u8 = 0x00;
110        type_baud |= (parameters.baudrate_card_reader as u8) << 2;
111        type_baud |= parameters.baudrate_reader_card as u8;
112        let mut rf_reset: u8 = 0x00;
113        rf_reset |= (parameters.radio_off_period & 0x0F) << 4;
114        rf_reset |= parameters.pause_after_radio_on & 0x0F;
115        let mut disable_tcl_cid: u8 = 0x00;
116        disable_tcl_cid |= (!parameters.switch_to_tcl as u8) << 7;
117        disable_tcl_cid |= parameters.tcl_cid & 0x0F;
118
119        let res = raw_reader.send(&vec![0x75, 
120            type_baud, 
121            rf_reset, 
122            disable_tcl_cid])?;
123        
124        if res.len() < 8 {
125            return Err(UemError::ReaderIncorrectResponse);
126        }
127
128        let atq = res[0..2].to_vec();
129        let sak: u8 = res[2];
130        let uid_len = res[3];
131        let uid = res[4 .. 4 + uid_len as usize].to_vec();
132       
133        if res.len() == 4 + uid_len as usize {
134            return Ok(UemCardIso14443A{atq, sak, uid, ats: vec![]});
135        }
136
137        let ats_len = res[4 + uid_len as usize];
138        let ats = res[4 + uid_len as usize .. 4 + (uid_len + ats_len) as usize].to_vec();
139
140        Ok(UemCardIso14443A{atq, sak, uid, ats})
141    }
142
143    /// Activation of type ISO14443B card
144    /// 
145    /// # Arguments
146    ///
147    /// * `parameters` - A set of [parameters](UemActivateParameters) to tweak activation,
148    /// 
149    /// # Returns
150    /// 
151    /// `Ok(())` on success, otherwise returns an error.
152    /// 
153    /// # Example
154    /// ```ignore
155    /// let card = uem_reader.commands().cards().activate_b(&UemActivateParameters{
156    ///     // switch_to_tcl: true, // Can be used to set T=CL protocol after activation
157    ///     ..Default::default()
158    /// });
159    /// if card.is_err() {
160    ///     uem_reader.close();
161    ///     return;
162    /// }
163    /// let card = card.unwrap();
164    /// ```
165    pub fn activate_b(&mut self, parameters: &UemActivateParameters) -> UemResultCardB {
166        let mut raw_reader = self.reader.lock().unwrap();
167        let mut type_baud: u8 = 0b_0001_0000;
168        type_baud |= (parameters.baudrate_card_reader as u8) << 2;
169        type_baud |= parameters.baudrate_reader_card as u8;
170        let mut rf_reset: u8 = 0x00;
171        rf_reset |= (parameters.radio_off_period & 0x0F) << 4;
172        rf_reset |= parameters.pause_after_radio_on & 0x0F;
173        let mut disable_tcl_cid: u8 = 0x00;
174        disable_tcl_cid |= (parameters.switch_to_tcl as u8) << 7;
175        disable_tcl_cid |= parameters.tcl_cid & 0x0F;
176        let mut param: u8 = 0x00;
177        param |= (parameters.btype_use_ext_atqb as u8) << 4;
178        param |= parameters.btype_time_slots & 0x07;
179
180        let res = raw_reader.send(&vec![0x75, 
181            type_baud, 
182            rf_reset, 
183            disable_tcl_cid, 
184            parameters.btype_afi, 
185            param])?;
186
187        if res.len() < 2 {
188            return Err(UemError::ReaderIncorrectResponse);
189        }
190
191        let mbli = res[0];
192        let atqb_len = res[1];
193
194        if atqb_len < 12 {
195            return Err(UemError::ReaderIncorrectResponse);
196        }
197
198        let atqb = res[2 .. 2 + atqb_len as usize].to_vec();
199        let pupi = res[3..7].to_vec();
200        let app_data = res[7..11].to_vec();
201        let prot_info = res[11..14].to_vec();
202        
203        Ok(UemCardIso14443B{
204            mbli, 
205            pupi,
206            app_data,
207            prot_info,
208            atq: atqb,
209        })
210    }
211}