Skip to main content

nfc1/
lib.rs

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/// Safe error type representing the NFC_E* constants
28#[derive(Debug, PartialEq, Eq, Clone, Copy)]
29pub enum Error {
30	// rs-nfc1 errors
31	Malloc,
32	Undefined(c_int),
33	UndefinedModulationType,
34	NoDeviceFound,
35
36	// libnfc errors
37	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			// rs-nfc1 errors
77			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			// libnfc errors
83			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			// rs-nfc1 errors
104			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			// libnfc errors
110			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/// Safe version of the int values used for timeouts in libnfc
146#[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/// Safe version of nfc_mode
177#[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/// Safe version of nfc_baud_rate
193#[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/// Safe version of nfc_property
234#[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/// Safe version of nfc_modulation_type
276#[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/// Safe version of nfc_modulation
335#[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/// Safe version of nfc_dep_mode
360#[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
387// Misc. functions
388
389pub 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 { // TA
413			offset += 1;
414		}
415		if ats[0] & 0x20 != 0 { // TB
416			offset += 1;
417		}
418		if ats[0] & 0x40 != 0 { // TC
419			offset += 1;
420		}
421		if ats.len() > offset {
422			// *pszTk = (szAts - offset);
423			return Some(&ats[offset..]);
424		}
425	}
426	None
427}
428
429pub fn version() -> &'static str {
430	// SAFETY: nfc_version returns a constant string (#define)
431	unsafe { CStr::from_ptr(nfc_version()) }.to_str().unwrap()
432}