tinkerforge_async/bindings/nfc_rfid_bricklet.rs
1/* ***********************************************************
2 * This file was automatically generated on 2024-02-16. *
3 * *
4 * Rust Bindings Version 2.0.20 *
5 * *
6 * If you have a bugfix for this file and want to commit it, *
7 * please fix the bug in the generator. You can find a link *
8 * to the generators git repository on tinkerforge.com *
9 *************************************************************/
10
11//! Reads and writes NFC and RFID tags.
12//!
13//! See also the documentation [here](https://www.tinkerforge.com/en/doc/Software/Bricklets/NFCRFID_Bricklet_Rust.html).
14#[allow(unused_imports)]
15use crate::{
16 base58::Uid, byte_converter::*, device::*, error::TinkerforgeError, ip_connection::async_io::AsyncIpConnection,
17 low_level_traits::LowLevelRead,
18};
19#[allow(unused_imports)]
20use futures_core::Stream;
21#[allow(unused_imports)]
22use tokio_stream::StreamExt;
23pub enum NfcRfidBrickletFunction {
24 RequestTagId,
25 GetTagId,
26 GetState,
27 AuthenticateMifareClassicPage,
28 WritePage,
29 RequestPage,
30 GetPage,
31 GetIdentity,
32 CallbackStateChanged,
33}
34impl From<NfcRfidBrickletFunction> for u8 {
35 fn from(fun: NfcRfidBrickletFunction) -> Self {
36 match fun {
37 NfcRfidBrickletFunction::RequestTagId => 1,
38 NfcRfidBrickletFunction::GetTagId => 2,
39 NfcRfidBrickletFunction::GetState => 3,
40 NfcRfidBrickletFunction::AuthenticateMifareClassicPage => 4,
41 NfcRfidBrickletFunction::WritePage => 5,
42 NfcRfidBrickletFunction::RequestPage => 6,
43 NfcRfidBrickletFunction::GetPage => 7,
44 NfcRfidBrickletFunction::GetIdentity => 255,
45 NfcRfidBrickletFunction::CallbackStateChanged => 8,
46 }
47 }
48}
49pub const NFC_RFID_BRICKLET_TAG_TYPE_MIFARE_CLASSIC: u8 = 0;
50pub const NFC_RFID_BRICKLET_TAG_TYPE_TYPE1: u8 = 1;
51pub const NFC_RFID_BRICKLET_TAG_TYPE_TYPE2: u8 = 2;
52pub const NFC_RFID_BRICKLET_STATE_INITIALIZATION: u8 = 0;
53pub const NFC_RFID_BRICKLET_STATE_IDLE: u8 = 128;
54pub const NFC_RFID_BRICKLET_STATE_ERROR: u8 = 192;
55pub const NFC_RFID_BRICKLET_STATE_REQUEST_TAG_ID: u8 = 2;
56pub const NFC_RFID_BRICKLET_STATE_REQUEST_TAG_ID_READY: u8 = 130;
57pub const NFC_RFID_BRICKLET_STATE_REQUEST_TAG_ID_ERROR: u8 = 194;
58pub const NFC_RFID_BRICKLET_STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE: u8 = 3;
59pub const NFC_RFID_BRICKLET_STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_READY: u8 = 131;
60pub const NFC_RFID_BRICKLET_STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_ERROR: u8 = 195;
61pub const NFC_RFID_BRICKLET_STATE_WRITE_PAGE: u8 = 4;
62pub const NFC_RFID_BRICKLET_STATE_WRITE_PAGE_READY: u8 = 132;
63pub const NFC_RFID_BRICKLET_STATE_WRITE_PAGE_ERROR: u8 = 196;
64pub const NFC_RFID_BRICKLET_STATE_REQUEST_PAGE: u8 = 5;
65pub const NFC_RFID_BRICKLET_STATE_REQUEST_PAGE_READY: u8 = 133;
66pub const NFC_RFID_BRICKLET_STATE_REQUEST_PAGE_ERROR: u8 = 197;
67pub const NFC_RFID_BRICKLET_KEY_A: u8 = 0;
68pub const NFC_RFID_BRICKLET_KEY_B: u8 = 1;
69
70#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
71pub struct TagId {
72 pub tag_type: u8,
73 pub tid_length: u8,
74 pub tid: [u8; 7],
75}
76impl FromByteSlice for TagId {
77 fn bytes_expected() -> usize {
78 9
79 }
80 fn from_le_byte_slice(bytes: &[u8]) -> TagId {
81 TagId {
82 tag_type: <u8>::from_le_byte_slice(&bytes[0..1]),
83 tid_length: <u8>::from_le_byte_slice(&bytes[1..2]),
84 tid: <[u8; 7]>::from_le_byte_slice(&bytes[2..9]),
85 }
86 }
87}
88
89#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
90pub struct State {
91 pub state: u8,
92 pub idle: bool,
93}
94impl FromByteSlice for State {
95 fn bytes_expected() -> usize {
96 2
97 }
98 fn from_le_byte_slice(bytes: &[u8]) -> State {
99 State { state: <u8>::from_le_byte_slice(&bytes[0..1]), idle: <bool>::from_le_byte_slice(&bytes[1..2]) }
100 }
101}
102
103#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
104pub struct StateChangedEvent {
105 pub state: u8,
106 pub idle: bool,
107}
108impl FromByteSlice for StateChangedEvent {
109 fn bytes_expected() -> usize {
110 2
111 }
112 fn from_le_byte_slice(bytes: &[u8]) -> StateChangedEvent {
113 StateChangedEvent { state: <u8>::from_le_byte_slice(&bytes[0..1]), idle: <bool>::from_le_byte_slice(&bytes[1..2]) }
114 }
115}
116
117#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
118pub struct Identity {
119 pub uid: String,
120 pub connected_uid: String,
121 pub position: char,
122 pub hardware_version: [u8; 3],
123 pub firmware_version: [u8; 3],
124 pub device_identifier: u16,
125}
126impl FromByteSlice for Identity {
127 fn bytes_expected() -> usize {
128 25
129 }
130 fn from_le_byte_slice(bytes: &[u8]) -> Identity {
131 Identity {
132 uid: <String>::from_le_byte_slice(&bytes[0..8]),
133 connected_uid: <String>::from_le_byte_slice(&bytes[8..16]),
134 position: <char>::from_le_byte_slice(&bytes[16..17]),
135 hardware_version: <[u8; 3]>::from_le_byte_slice(&bytes[17..20]),
136 firmware_version: <[u8; 3]>::from_le_byte_slice(&bytes[20..23]),
137 device_identifier: <u16>::from_le_byte_slice(&bytes[23..25]),
138 }
139 }
140}
141
142/// Reads and writes NFC and RFID tags
143#[derive(Clone)]
144pub struct NfcRfidBricklet {
145 device: Device,
146}
147impl NfcRfidBricklet {
148 pub const DEVICE_IDENTIFIER: u16 = 246;
149 pub const DEVICE_DISPLAY_NAME: &'static str = "NFC/RFID Bricklet";
150 /// Creates an object with the unique device ID `uid`. This object can then be used after the IP Connection `ip_connection` is connected.
151 pub fn new(uid: Uid, connection: AsyncIpConnection) -> NfcRfidBricklet {
152 let mut result = NfcRfidBricklet { device: Device::new([2, 0, 10], uid, connection, Self::DEVICE_DISPLAY_NAME) };
153 result.device.response_expected[u8::from(NfcRfidBrickletFunction::RequestTagId) as usize] = ResponseExpectedFlag::False;
154 result.device.response_expected[u8::from(NfcRfidBrickletFunction::GetTagId) as usize] = ResponseExpectedFlag::AlwaysTrue;
155 result.device.response_expected[u8::from(NfcRfidBrickletFunction::GetState) as usize] = ResponseExpectedFlag::AlwaysTrue;
156 result.device.response_expected[u8::from(NfcRfidBrickletFunction::AuthenticateMifareClassicPage) as usize] =
157 ResponseExpectedFlag::False;
158 result.device.response_expected[u8::from(NfcRfidBrickletFunction::WritePage) as usize] = ResponseExpectedFlag::False;
159 result.device.response_expected[u8::from(NfcRfidBrickletFunction::RequestPage) as usize] = ResponseExpectedFlag::False;
160 result.device.response_expected[u8::from(NfcRfidBrickletFunction::GetPage) as usize] = ResponseExpectedFlag::AlwaysTrue;
161 result.device.response_expected[u8::from(NfcRfidBrickletFunction::GetIdentity) as usize] = ResponseExpectedFlag::AlwaysTrue;
162 result
163 }
164
165 /// Returns the response expected flag for the function specified by the function ID parameter.
166 /// It is true if the function is expected to send a response, false otherwise.
167 ///
168 /// For getter functions this is enabled by default and cannot be disabled, because those
169 /// functions will always send a response. For callback configuration functions it is enabled
170 /// by default too, but can be disabled by [`set_response_expected`](crate::nfc_rfid_bricklet::NfcRfidBricklet::set_response_expected).
171 /// For setter functions it is disabled by default and can be enabled.
172 ///
173 /// Enabling the response expected flag for a setter function allows to detect timeouts
174 /// and other error conditions calls of this setter as well. The device will then send a response
175 /// for this purpose. If this flag is disabled for a setter function then no response is sent
176 /// and errors are silently ignored, because they cannot be detected.
177 ///
178 /// See [`set_response_expected`](crate::nfc_rfid_bricklet::NfcRfidBricklet::set_response_expected) for the list of function ID constants available for this function.
179 pub fn get_response_expected(&mut self, fun: NfcRfidBrickletFunction) -> Result<bool, GetResponseExpectedError> {
180 self.device.get_response_expected(u8::from(fun))
181 }
182
183 /// Changes the response expected flag of the function specified by the function ID parameter.
184 /// This flag can only be changed for setter (default value: false) and callback configuration
185 /// functions (default value: true). For getter functions it is always enabled.
186 ///
187 /// Enabling the response expected flag for a setter function allows to detect timeouts and
188 /// other error conditions calls of this setter as well. The device will then send a response
189 /// for this purpose. If this flag is disabled for a setter function then no response is sent
190 /// and errors are silently ignored, because they cannot be detected.
191 pub fn set_response_expected(&mut self, fun: NfcRfidBrickletFunction, response_expected: bool) -> Result<(), SetResponseExpectedError> {
192 self.device.set_response_expected(u8::from(fun), response_expected)
193 }
194
195 /// Changes the response expected flag for all setter and callback configuration functions of this device at once.
196 pub fn set_response_expected_all(&mut self, response_expected: bool) {
197 self.device.set_response_expected_all(response_expected)
198 }
199
200 /// Returns the version of the API definition (major, minor, revision) implemented by this API bindings.
201 /// This is neither the release version of this API bindings nor does it tell you anything about the represented Brick or Bricklet.
202 pub fn get_api_version(&self) -> [u8; 3] {
203 self.device.api_version
204 }
205
206 /// This receiver is called if the state of the NFC/RFID Bricklet changes.
207 /// See [`get_state`] for more information about the possible states.
208 ///
209 /// [`get_state`]: #method.get_state
210 pub async fn get_state_changed_callback_receiver(&mut self) -> impl Stream<Item = StateChangedEvent> {
211 self.device
212 .get_callback_receiver(u8::from(NfcRfidBrickletFunction::CallbackStateChanged))
213 .await
214 .map(|p| StateChangedEvent::from_le_byte_slice(p.body()))
215 }
216
217 /// To read or write a tag that is in proximity of the NFC/RFID Bricklet you
218 /// first have to call this function with the expected tag type as parameter.
219 /// It is no problem if you don't know the tag type. You can cycle through
220 /// the available tag types until the tag gives an answer to the request.
221 ///
222 /// Currently the following tag types are supported:
223 ///
224 /// * Mifare Classic
225 /// * NFC Forum Type 1
226 /// * NFC Forum Type 2
227 ///
228 /// After you call [`request_tag_id`] the NFC/RFID Bricklet will try to read
229 /// the tag ID from the tag. After this process is done the state will change.
230 /// You can either register the [`get_state_changed_callback_receiver`] receiver or you can poll
231 /// [`get_state`] to find out about the state change.
232 ///
233 /// If the state changes to *RequestTagIDError* it means that either there was
234 /// no tag present or that the tag is of an incompatible type. If the state
235 /// changes to *RequestTagIDReady* it means that a compatible tag was found
236 /// and that the tag ID could be read out. You can now get the tag ID by
237 /// calling [`get_tag_id`].
238 ///
239 /// If two tags are in the proximity of the NFC/RFID Bricklet, this
240 /// function will cycle through the tags. To select a specific tag you have
241 /// to call [`request_tag_id`] until the correct tag id is found.
242 ///
243 /// In case of any *Error* state the selection is lost and you have to
244 /// start again by calling [`request_tag_id`].
245 ///
246 /// Associated constants:
247 /// * NFC_RFID_BRICKLET_TAG_TYPE_MIFARE_CLASSIC
248 /// * NFC_RFID_BRICKLET_TAG_TYPE_TYPE1
249 /// * NFC_RFID_BRICKLET_TAG_TYPE_TYPE2
250 pub async fn request_tag_id(&mut self, tag_type: u8) -> Result<(), TinkerforgeError> {
251 let mut payload = [0; 1];
252 tag_type.write_to_slice(&mut payload[0..1]);
253
254 #[allow(unused_variables)]
255 let result = self.device.set(u8::from(NfcRfidBrickletFunction::RequestTagId), &payload).await?;
256 Ok(())
257 }
258
259 /// Returns the tag type, tag ID and the length of the tag ID
260 /// (4 or 7 bytes are possible length). This function can only be called if the
261 /// NFC/RFID is currently in one of the *Ready* states. The returned ID
262 /// is the ID that was saved through the last call of [`request_tag_id`].
263 ///
264 /// To get the tag ID of a tag the approach is as follows:
265 ///
266 /// 1. Call [`request_tag_id`]
267 /// 2. Wait for state to change to *RequestTagIDReady* (see [`get_state`] or
268 /// [`get_state_changed_callback_receiver`] receiver)
269 /// 3. Call [`get_tag_id`]
270 ///
271 /// Associated constants:
272 /// * NFC_RFID_BRICKLET_TAG_TYPE_MIFARE_CLASSIC
273 /// * NFC_RFID_BRICKLET_TAG_TYPE_TYPE1
274 /// * NFC_RFID_BRICKLET_TAG_TYPE_TYPE2
275 pub async fn get_tag_id(&mut self) -> Result<TagId, TinkerforgeError> {
276 let payload = [0; 0];
277
278 #[allow(unused_variables)]
279 let result = self.device.get(u8::from(NfcRfidBrickletFunction::GetTagId), &payload).await?;
280 Ok(TagId::from_le_byte_slice(result.body()))
281 }
282
283 /// Returns the current state of the NFC/RFID Bricklet.
284 ///
285 /// On startup the Bricklet will be in the *Initialization* state. The
286 /// initialization will only take about 20ms. After that it changes to *Idle*.
287 ///
288 /// The functions of this Bricklet can be called in the *Idle* state and all of
289 /// the *Ready* and *Error* states.
290 ///
291 /// Example: If you call [`request_page`], the state will change to
292 /// *RequestPage* until the reading of the page is finished. Then it will change
293 /// to either *RequestPageReady* if it worked or to *RequestPageError* if it
294 /// didn't. If the request worked you can get the page by calling [`get_page`].
295 ///
296 /// The same approach is used analogously for the other API functions.
297 ///
298 /// Associated constants:
299 /// * NFC_RFID_BRICKLET_STATE_INITIALIZATION
300 /// * NFC_RFID_BRICKLET_STATE_IDLE
301 /// * NFC_RFID_BRICKLET_STATE_ERROR
302 /// * NFC_RFID_BRICKLET_STATE_REQUEST_TAG_ID
303 /// * NFC_RFID_BRICKLET_STATE_REQUEST_TAG_ID_READY
304 /// * NFC_RFID_BRICKLET_STATE_REQUEST_TAG_ID_ERROR
305 /// * NFC_RFID_BRICKLET_STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE
306 /// * NFC_RFID_BRICKLET_STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_READY
307 /// * NFC_RFID_BRICKLET_STATE_AUTHENTICATING_MIFARE_CLASSIC_PAGE_ERROR
308 /// * NFC_RFID_BRICKLET_STATE_WRITE_PAGE
309 /// * NFC_RFID_BRICKLET_STATE_WRITE_PAGE_READY
310 /// * NFC_RFID_BRICKLET_STATE_WRITE_PAGE_ERROR
311 /// * NFC_RFID_BRICKLET_STATE_REQUEST_PAGE
312 /// * NFC_RFID_BRICKLET_STATE_REQUEST_PAGE_READY
313 /// * NFC_RFID_BRICKLET_STATE_REQUEST_PAGE_ERROR
314 pub async fn get_state(&mut self) -> Result<State, TinkerforgeError> {
315 let payload = [0; 0];
316
317 #[allow(unused_variables)]
318 let result = self.device.get(u8::from(NfcRfidBrickletFunction::GetState), &payload).await?;
319 Ok(State::from_le_byte_slice(result.body()))
320 }
321
322 /// Mifare Classic tags use authentication. If you want to read from or write to
323 /// a Mifare Classic page you have to authenticate it beforehand.
324 /// Each page can be authenticated with two keys: A (``key_number`` = 0) and B
325 /// (``key_number`` = 1). A new Mifare Classic
326 /// tag that has not yet been written to can be accessed with key A
327 /// and the default key ``[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]``.
328 ///
329 /// The approach to read or write a Mifare Classic page is as follows:
330 ///
331 /// 1. Call [`request_tag_id`]
332 /// 2. Wait for state to change to *RequestTagIDReady* (see [`get_state`]
333 /// or [`get_state_changed_callback_receiver`] receiver)
334 /// 3. If looking for a specific tag then call [`get_tag_id`] and check if the
335 /// expected tag was found, if it was not found go back to step 1
336 /// 4. Call [`authenticate_mifare_classic_page`] with page and key for the page
337 /// 5. Wait for state to change to *AuthenticatingMifareClassicPageReady* (see
338 /// [`get_state`] or [`get_state_changed_callback_receiver`] receiver)
339 /// 6. Call [`request_page`] or [`write_page`] to read/write page
340 ///
341 /// Associated constants:
342 /// * NFC_RFID_BRICKLET_KEY_A
343 /// * NFC_RFID_BRICKLET_KEY_B
344 pub async fn authenticate_mifare_classic_page(&mut self, page: u16, key_number: u8, key: &[u8; 6]) -> Result<(), TinkerforgeError> {
345 let mut payload = [0; 9];
346 page.write_to_slice(&mut payload[0..2]);
347 key_number.write_to_slice(&mut payload[2..3]);
348 key.write_to_slice(&mut payload[3..9]);
349
350 #[allow(unused_variables)]
351 let result = self.device.set(u8::from(NfcRfidBrickletFunction::AuthenticateMifareClassicPage), &payload).await?;
352 Ok(())
353 }
354
355 /// Writes 16 bytes starting from the given page. How many pages are written
356 /// depends on the tag type. The page sizes are as follows:
357 ///
358 /// * Mifare Classic page size: 16 byte (one page is written)
359 /// * NFC Forum Type 1 page size: 8 byte (two pages are written)
360 /// * NFC Forum Type 2 page size: 4 byte (four pages are written)
361 ///
362 /// The general approach for writing to a tag is as follows:
363 ///
364 /// 1. Call [`request_tag_id`]
365 /// 2. Wait for state to change to *RequestTagIDReady* (see [`get_state`] or
366 /// [`get_state_changed_callback_receiver`] receiver)
367 /// 3. If looking for a specific tag then call [`get_tag_id`] and check if the
368 /// expected tag was found, if it was not found got back to step 1
369 /// 4. Call [`write_page`] with page number and data
370 /// 5. Wait for state to change to *WritePageReady* (see [`get_state`] or
371 /// [`get_state_changed_callback_receiver`] receiver)
372 ///
373 /// If you use a Mifare Classic tag you have to authenticate a page before you
374 /// can write to it. See [`authenticate_mifare_classic_page`].
375 pub async fn write_page(&mut self, page: u16, data: &[u8; 16]) -> Result<(), TinkerforgeError> {
376 let mut payload = [0; 18];
377 page.write_to_slice(&mut payload[0..2]);
378 data.write_to_slice(&mut payload[2..18]);
379
380 #[allow(unused_variables)]
381 let result = self.device.set(u8::from(NfcRfidBrickletFunction::WritePage), &payload).await?;
382 Ok(())
383 }
384
385 /// Reads 16 bytes starting from the given page and stores them into a buffer.
386 /// The buffer can then be read out with [`get_page`].
387 /// How many pages are read depends on the tag type. The page sizes are
388 /// as follows:
389 ///
390 /// * Mifare Classic page size: 16 byte (one page is read)
391 /// * NFC Forum Type 1 page size: 8 byte (two pages are read)
392 /// * NFC Forum Type 2 page size: 4 byte (four pages are read)
393 ///
394 /// The general approach for reading a tag is as follows:
395 ///
396 /// 1. Call [`request_tag_id`]
397 /// 2. Wait for state to change to *RequestTagIDReady* (see [`get_state`]
398 /// or [`get_state_changed_callback_receiver`] receiver)
399 /// 3. If looking for a specific tag then call [`get_tag_id`] and check if the
400 /// expected tag was found, if it was not found got back to step 1
401 /// 4. Call [`request_page`] with page number
402 /// 5. Wait for state to change to *RequestPageReady* (see [`get_state`]
403 /// or [`get_state_changed_callback_receiver`] receiver)
404 /// 6. Call [`get_page`] to retrieve the page from the buffer
405 ///
406 /// If you use a Mifare Classic tag you have to authenticate a page before you
407 /// can read it. See [`authenticate_mifare_classic_page`].
408 pub async fn request_page(&mut self, page: u16) -> Result<(), TinkerforgeError> {
409 let mut payload = [0; 2];
410 page.write_to_slice(&mut payload[0..2]);
411
412 #[allow(unused_variables)]
413 let result = self.device.set(u8::from(NfcRfidBrickletFunction::RequestPage), &payload).await?;
414 Ok(())
415 }
416
417 /// Returns 16 bytes of data from an internal buffer. To fill the buffer
418 /// with specific pages you have to call [`request_page`] beforehand.
419 pub async fn get_page(&mut self) -> Result<Box<[u8; 16]>, TinkerforgeError> {
420 let payload = [0; 0];
421
422 #[allow(unused_variables)]
423 let result = self.device.get(u8::from(NfcRfidBrickletFunction::GetPage), &payload).await?;
424 Ok(Box::<[u8; 16]>::from_le_byte_slice(result.body()))
425 }
426
427 /// Returns the UID, the UID where the Bricklet is connected to,
428 /// the position, the hardware and firmware version as well as the
429 /// device identifier.
430 ///
431 /// The position can be 'a', 'b', 'c', 'd', 'e', 'f', 'g' or 'h' (Bricklet Port).
432 /// A Bricklet connected to an [Isolator Bricklet](isolator_bricklet) is always at
433 /// position 'z'.
434 ///
435 /// The device identifier numbers can be found [here](device_identifier).
436 /// |device_identifier_constant|
437 pub async fn get_identity(&mut self) -> Result<Identity, TinkerforgeError> {
438 let payload = [0; 0];
439
440 #[allow(unused_variables)]
441 let result = self.device.get(u8::from(NfcRfidBrickletFunction::GetIdentity), &payload).await?;
442 Ok(Identity::from_le_byte_slice(result.body()))
443 }
444}