1use nfc1_sys::{
2 nfc_version,
3 str_nfc_baud_rate,
4 str_nfc_modulation_type,
5 iso14443a_crc as nfc_iso14443a_crc,
6 iso14443a_crc_append as nfc_iso14443a_crc_append,
7 iso14443b_crc as nfc_iso14443b_crc,
8 iso14443b_crc_append as nfc_iso14443b_crc_append,
9};
10use std::ffi::CStr;
11use std::os::raw::c_int;
12use std::time::Duration;
13use std::string::ToString;
14use std::io::{ErrorKind, Error as IoError};
15
16mod target;
17mod context;
18mod device;
19#[cfg(test)]
20mod test;
21
22pub use target::Target;
23pub use device::Device;
24pub use context::Context;
25pub use target::info as target_info;
26
27#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub enum Error {
30 Malloc,
32 Undefined(c_int),
33 UndefinedModulationType,
34 NoDeviceFound,
35
36 Io,
38 InvalidArgument,
39 DeviceNotSupported,
40 NoSuchDeviceFound,
41 BufferOverflow,
42 Timeout,
43 OperationAborted,
44 NotImplemented,
45 TargetReleased,
46 RfTransmissionError,
47 MifareAuthFailed,
48 Soft,
49 Chip,
50}
51
52impl From<c_int> for Error {
53 fn from(input: c_int) -> Self {
54 match input {
55 nfc1_sys::NFC_EIO => Self::Io,
56 nfc1_sys::NFC_EINVARG => Self::InvalidArgument,
57 nfc1_sys::NFC_EDEVNOTSUPP => Self::DeviceNotSupported,
58 nfc1_sys::NFC_ENOTSUCHDEV => Self::NoSuchDeviceFound,
59 nfc1_sys::NFC_EOVFLOW => Self::BufferOverflow,
60 nfc1_sys::NFC_ETIMEOUT => Self::Timeout,
61 nfc1_sys::NFC_EOPABORTED => Self::OperationAborted,
62 nfc1_sys::NFC_ENOTIMPL => Self::NotImplemented,
63 nfc1_sys::NFC_ETGRELEASED => Self::TargetReleased,
64 nfc1_sys::NFC_ERFTRANS => Self::RfTransmissionError,
65 nfc1_sys::NFC_EMFCAUTHFAIL => Self::MifareAuthFailed,
66 nfc1_sys::NFC_ESOFT => Self::Soft,
67 nfc1_sys::NFC_ECHIP => Self::Chip,
68 _ => Self::Undefined(input),
69 }
70 }
71}
72
73impl From<Error> for IoError {
74 fn from(input: Error) -> Self {
75 match input {
76 Error::Malloc => IoError::from(ErrorKind::Interrupted),
78 Error::Undefined(_) => IoError::from(ErrorKind::Other),
79 Error::UndefinedModulationType => IoError::from(ErrorKind::InvalidInput),
80 Error::NoDeviceFound => IoError::from(ErrorKind::NotFound),
81
82 Error::Io => IoError::from(ErrorKind::Other),
84 Error::InvalidArgument => IoError::from(ErrorKind::InvalidInput),
85 Error::DeviceNotSupported => IoError::from(ErrorKind::Other),
86 Error::NoSuchDeviceFound => IoError::from(ErrorKind::NotFound),
87 Error::BufferOverflow => IoError::from(ErrorKind::Other),
88 Error::Timeout => IoError::from(ErrorKind::TimedOut),
89 Error::OperationAborted => IoError::from(ErrorKind::Interrupted),
90 Error::NotImplemented => IoError::from(ErrorKind::Other),
91 Error::TargetReleased => IoError::from(ErrorKind::Other),
92 Error::RfTransmissionError => IoError::from(ErrorKind::Interrupted),
93 Error::MifareAuthFailed => IoError::from(ErrorKind::PermissionDenied),
94 Error::Soft => IoError::from(ErrorKind::Other),
95 Error::Chip => IoError::from(ErrorKind::Other),
96 }
97 }
98}
99
100impl std::fmt::Display for Error {
101 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
102 match self {
103 Error::Malloc => write!(f, "Memory allocation error"),
105 Error::Undefined(errno) => write!(f, "Unknown libnfc error: {}", errno),
106 Error::UndefinedModulationType => write!(f, "Undefined modulation type"),
107 Error::NoDeviceFound => write!(f, "No device found"),
108
109 Error::Io => write!(f, "Input/output error, device may not be usable anymore without re-opening it"),
111 Error::InvalidArgument => write!(f, "Invalid argument(s)"),
112 Error::DeviceNotSupported => write!(f, "Operation not supported by device"),
113 Error::NoSuchDeviceFound => write!(f, "No such device found"),
114 Error::BufferOverflow => write!(f, "Buffer overflow"),
115 Error::Timeout => write!(f, "Operation timed out"),
116 Error::OperationAborted => write!(f, "Operation aborted (by user)"),
117 Error::NotImplemented => write!(f, "Not (yet) implemented"),
118 Error::TargetReleased => write!(f, "Target released"),
119 Error::RfTransmissionError => write!(f, "Error during RF transmission"),
120 Error::MifareAuthFailed => write!(f, "MIFARE Classic: authentication failed"),
121 Error::Soft => write!(f, "Software error (allocation, file/pipe creation, etc.)"),
122 Error::Chip => write!(f, "Device internal chip error"),
123 }
124 }
125}
126
127impl std::error::Error for Error {}
128
129pub type Result<T> = std::result::Result<T, Error>;
130
131pub(crate) fn wrap_err(res: c_int) -> Result<()> {
132 if res < 0 {
133 return Err(res.into());
134 }
135 Ok(())
136}
137
138pub(crate) fn wrap_err_usize(res: c_int) -> Result<usize> {
139 if res < 0 {
140 return Err(res.into());
141 }
142 Ok(res as usize)
143}
144
145#[derive(Debug, PartialEq, Eq, Clone, Copy)]
147pub enum Timeout {
148 None,
149 Default,
150 Duration(Duration),
151}
152
153impl From<Timeout> for c_int {
154 fn from(input: Timeout) -> Self {
155 match input {
156 Timeout::None => 0,
157 Timeout::Default => -1,
158 Timeout::Duration(duration) => duration.as_millis() as c_int,
159 }
160 }
161}
162
163impl From<c_int> for Timeout {
164 fn from(input: c_int) -> Self {
165 if input < 0 {
166 Timeout::Default
167 } else {
168 match input {
169 0 => Timeout::None,
170 millis => Timeout::Duration(Duration::from_millis(millis as u64)),
171 }
172 }
173 }
174}
175
176#[derive(Debug, PartialEq, Eq, Clone, Copy)]
178pub enum Mode {
179 Target,
180 Initiator,
181}
182
183impl From<Mode> for nfc1_sys::nfc_mode {
184 fn from(input: Mode) -> nfc1_sys::nfc_mode {
185 match input {
186 Mode::Target => nfc1_sys::nfc_mode_N_TARGET,
187 Mode::Initiator => nfc1_sys::nfc_mode_N_INITIATOR,
188 }
189 }
190}
191
192#[derive(Debug, PartialEq, Eq, Clone, Copy)]
194pub enum BaudRate {
195 Baud106,
196 Baud212,
197 Baud424,
198 Baud847,
199 Undefined,
200}
201
202impl ToString for BaudRate {
203 fn to_string(&self) -> String {
204 let baud_rate: nfc1_sys::nfc_baud_rate = self.clone().into();
205 return unsafe { CStr::from_ptr(str_nfc_baud_rate(baud_rate)) }.to_string_lossy().into_owned();
206 }
207}
208
209impl From<BaudRate> for nfc1_sys::nfc_baud_rate {
210 fn from(input: BaudRate) -> nfc1_sys::nfc_baud_rate {
211 match input {
212 BaudRate::Baud106 => nfc1_sys::nfc_baud_rate_NBR_106,
213 BaudRate::Baud212 => nfc1_sys::nfc_baud_rate_NBR_212,
214 BaudRate::Baud424 => nfc1_sys::nfc_baud_rate_NBR_424,
215 BaudRate::Baud847 => nfc1_sys::nfc_baud_rate_NBR_847,
216 BaudRate::Undefined => nfc1_sys::nfc_baud_rate_NBR_UNDEFINED,
217 }
218 }
219}
220
221impl From<nfc1_sys::nfc_baud_rate> for BaudRate {
222 fn from(input: nfc1_sys::nfc_baud_rate) -> Self {
223 match input {
224 nfc1_sys::nfc_baud_rate_NBR_106 => BaudRate::Baud106,
225 nfc1_sys::nfc_baud_rate_NBR_212 => BaudRate::Baud212,
226 nfc1_sys::nfc_baud_rate_NBR_424 => BaudRate::Baud424,
227 nfc1_sys::nfc_baud_rate_NBR_847 => BaudRate::Baud847,
228 _ => BaudRate::Undefined,
229 }
230 }
231}
232
233#[derive(Debug, PartialEq, Eq, Clone, Copy)]
235pub enum Property {
236 TimeoutCommand,
237 TimeoutAtr,
238 TimeoutCom,
239 HandleCrc,
240 HandleParity,
241 ActivateField,
242 ActivateCrypto1,
243 InfiniteSelect,
244 AcceptInvalidFrames,
245 AcceptMultipleFrames,
246 AutoIso144434,
247 EasyFraming,
248 ForceIso14443A,
249 ForceIso14443B,
250 ForceSpeed106,
251}
252
253impl From<Property> for nfc1_sys::nfc_property {
254 fn from(input: Property) -> nfc1_sys::nfc_property {
255 match input {
256 Property::TimeoutCommand => nfc1_sys::nfc_property_NP_TIMEOUT_COMMAND,
257 Property::TimeoutAtr => nfc1_sys::nfc_property_NP_TIMEOUT_ATR,
258 Property::TimeoutCom => nfc1_sys::nfc_property_NP_TIMEOUT_COM,
259 Property::HandleCrc => nfc1_sys::nfc_property_NP_HANDLE_CRC,
260 Property::HandleParity => nfc1_sys::nfc_property_NP_HANDLE_PARITY,
261 Property::ActivateField => nfc1_sys::nfc_property_NP_ACTIVATE_FIELD,
262 Property::ActivateCrypto1 => nfc1_sys::nfc_property_NP_ACTIVATE_CRYPTO1,
263 Property::InfiniteSelect => nfc1_sys::nfc_property_NP_INFINITE_SELECT,
264 Property::AcceptInvalidFrames => nfc1_sys::nfc_property_NP_ACCEPT_INVALID_FRAMES,
265 Property::AcceptMultipleFrames => nfc1_sys::nfc_property_NP_ACCEPT_MULTIPLE_FRAMES,
266 Property::AutoIso144434 => nfc1_sys::nfc_property_NP_AUTO_ISO14443_4,
267 Property::EasyFraming => nfc1_sys::nfc_property_NP_EASY_FRAMING,
268 Property::ForceIso14443A => nfc1_sys::nfc_property_NP_FORCE_ISO14443_A,
269 Property::ForceIso14443B => nfc1_sys::nfc_property_NP_FORCE_ISO14443_B,
270 Property::ForceSpeed106 => nfc1_sys::nfc_property_NP_FORCE_SPEED_106,
271 }
272 }
273}
274
275#[derive(Debug, PartialEq, Eq, Clone, Copy)]
277pub enum ModulationType {
278 Iso14443a,
279 Jewel,
280 Iso14443b,
281 Iso14443bi,
282 Iso14443b2sr,
283 Iso14443b2ct,
284 Felica,
285 Dep,
286 Barcode,
287 Iso14443biClass,
288 Undefined,
289}
290
291impl ToString for ModulationType {
292 fn to_string(&self) -> String {
293 let modulation_type: nfc1_sys::nfc_modulation_type = self.clone().into();
294 return unsafe { CStr::from_ptr(str_nfc_modulation_type(modulation_type)) }.to_string_lossy().into_owned();
295 }
296}
297
298impl From<ModulationType> for nfc1_sys::nfc_modulation_type {
299 fn from(input: ModulationType) -> nfc1_sys::nfc_modulation_type {
300 match input {
301 ModulationType::Iso14443a => nfc1_sys::nfc_modulation_type_NMT_ISO14443A,
302 ModulationType::Jewel => nfc1_sys::nfc_modulation_type_NMT_JEWEL,
303 ModulationType::Iso14443b => nfc1_sys::nfc_modulation_type_NMT_ISO14443B,
304 ModulationType::Iso14443bi => nfc1_sys::nfc_modulation_type_NMT_ISO14443BI,
305 ModulationType::Iso14443b2sr => nfc1_sys::nfc_modulation_type_NMT_ISO14443B2SR,
306 ModulationType::Iso14443b2ct => nfc1_sys::nfc_modulation_type_NMT_ISO14443B2CT,
307 ModulationType::Felica => nfc1_sys::nfc_modulation_type_NMT_FELICA,
308 ModulationType::Dep => nfc1_sys::nfc_modulation_type_NMT_DEP,
309 ModulationType::Barcode => nfc1_sys::nfc_modulation_type_NMT_BARCODE,
310 ModulationType::Iso14443biClass => nfc1_sys::nfc_modulation_type_NMT_ISO14443BICLASS,
311 ModulationType::Undefined => 0,
312 }
313 }
314}
315
316impl From<nfc1_sys::nfc_modulation_type> for ModulationType {
317 fn from(input: nfc1_sys::nfc_modulation_type) -> Self {
318 match input {
319 nfc1_sys::nfc_modulation_type_NMT_ISO14443A => ModulationType::Iso14443a,
320 nfc1_sys::nfc_modulation_type_NMT_JEWEL => ModulationType::Jewel,
321 nfc1_sys::nfc_modulation_type_NMT_ISO14443B => ModulationType::Iso14443b,
322 nfc1_sys::nfc_modulation_type_NMT_ISO14443BI => ModulationType::Iso14443bi,
323 nfc1_sys::nfc_modulation_type_NMT_ISO14443B2SR => ModulationType::Iso14443b2sr,
324 nfc1_sys::nfc_modulation_type_NMT_ISO14443B2CT => ModulationType::Iso14443b2ct,
325 nfc1_sys::nfc_modulation_type_NMT_FELICA => ModulationType::Felica,
326 nfc1_sys::nfc_modulation_type_NMT_DEP => ModulationType::Dep,
327 nfc1_sys::nfc_modulation_type_NMT_BARCODE => ModulationType::Barcode,
328 nfc1_sys::nfc_modulation_type_NMT_ISO14443BICLASS => ModulationType::Iso14443biClass,
329 _ => ModulationType::Undefined,
330 }
331 }
332}
333
334#[derive(Debug, PartialEq, Eq, Clone, Copy)]
336pub struct Modulation {
337 pub modulation_type: ModulationType,
338 pub baud_rate: BaudRate,
339}
340
341impl From<&Modulation> for nfc1_sys::nfc_modulation {
342 fn from(input: &Modulation) -> nfc1_sys::nfc_modulation {
343 nfc1_sys::nfc_modulation {
344 nmt: input.modulation_type.into(),
345 nbr: input.baud_rate.into(),
346 }
347 }
348}
349
350impl From<nfc1_sys::nfc_modulation> for Modulation {
351 fn from(input: nfc1_sys::nfc_modulation) -> Self {
352 Self{
353 modulation_type: input.nmt.into(),
354 baud_rate: input.nbr.into(),
355 }
356 }
357}
358
359#[derive(Debug, PartialEq, Eq, Clone, Copy)]
361pub enum DepMode {
362 Undefined,
363 Passive,
364 Active,
365}
366
367impl From<DepMode> for nfc1_sys::nfc_baud_rate {
368 fn from(input: DepMode) -> nfc1_sys::nfc_baud_rate {
369 match input {
370 DepMode::Undefined => nfc1_sys::nfc_dep_mode_NDM_UNDEFINED,
371 DepMode::Passive => nfc1_sys::nfc_dep_mode_NDM_PASSIVE,
372 DepMode::Active => nfc1_sys::nfc_dep_mode_NDM_ACTIVE,
373 }
374 }
375}
376
377impl From<nfc1_sys::nfc_baud_rate> for DepMode {
378 fn from(input: nfc1_sys::nfc_baud_rate) -> DepMode {
379 match input {
380 nfc1_sys::nfc_dep_mode_NDM_PASSIVE => DepMode::Passive,
381 nfc1_sys::nfc_dep_mode_NDM_ACTIVE => DepMode::Active,
382 _ => DepMode::Undefined,
383 }
384 }
385}
386
387pub fn iso14443a_crc(data: &mut [u8]) -> Vec<u8> {
390 let mut crc = vec![0u8; 2];
391 unsafe { nfc_iso14443a_crc(data.as_mut_ptr(), data.len(), crc.as_mut_ptr()) };
392 crc
393}
394
395pub fn iso14443a_crc_append(data: &mut Vec<u8>) {
396 unsafe { nfc_iso14443a_crc_append(data.as_mut_ptr(), data.len()) }
397}
398
399pub fn iso14443b_crc(data: &mut [u8]) -> Vec<u8> {
400 let mut crc = vec![0u8; 2];
401 unsafe { nfc_iso14443b_crc(data.as_mut_ptr(), data.len(), crc.as_mut_ptr()) };
402 crc
403}
404
405pub fn iso14443b_crc_append(data: &mut Vec<u8>) {
406 unsafe { nfc_iso14443b_crc_append(data.as_mut_ptr(), data.len()) }
407}
408
409pub fn iso14443a_locate_historical_bytes(ats: &[u8]) -> Option<&[u8]> {
410 if ats.len() != 0 {
411 let mut offset = 1;
412 if ats[0] & 0x10 != 0 { offset += 1;
414 }
415 if ats[0] & 0x20 != 0 { offset += 1;
417 }
418 if ats[0] & 0x40 != 0 { offset += 1;
420 }
421 if ats.len() > offset {
422 return Some(&ats[offset..]);
424 }
425 }
426 None
427}
428
429pub fn version() -> &'static str {
430 unsafe { CStr::from_ptr(nfc_version()) }.to_str().unwrap()
432}