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}