FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
grove_rfid_reader.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
21#ifndef GROVE_RFID_READER_HH
22#define GROVE_RFID_READER_HH
23
24#include "../bits.h"
25#include "../gpio.h"
26#include "../int.h"
27#include "../interrupts.h"
28#include "../pci.h"
29#include "../streambuf.h"
30#include "../streams.h"
31#include "../time.h"
32#include "../uart_commons.h"
33#include "wiegand.h"
34
49#define REGISTER_GROVE_RFID_READER_INT_ISR(DATA0_INT, DATA1_INT, READER) \
50 ISR(CAT3(INT, DATA0_INT, _vect)) \
51 { \
52 devices::rfid::isr_handler_grove::callback_fall_0<DATA0_INT, DATA1_INT, READER>(); \
53 } \
54 ISR(CAT3(INT, DATA1_INT, _vect)) \
55 { \
56 devices::rfid::isr_handler_grove::callback_fall_1<DATA0_INT, DATA1_INT, READER>(); \
57 }
58
71#define REGISTER_GROVE_RFID_READER_PCI_ISR(DATA01_PCI, READER) \
72 ISR(CAT3(PCINT, DATA01_PCI, _vect)) \
73 { \
74 devices::rfid::isr_handler_grove::callback_fall_0_or_1<DATA01_PCI, READER>(); \
75 } \
76
77namespace devices
78{
82 namespace rfid
83 {
84 }
85}
86
87namespace devices::rfid
88{
118 template<typename UART_> class Grove125KHzRFIDReaderUART
119 {
120 static constexpr uint16_t UART_SPEED = 9600;
121
122 // Check that UART type is suitable
123 static_assert(serial::UART_trait<UART_>::IS_UART, "UART template argument must be a serial device");
124 static_assert(serial::UART_trait<UART_>::HAS_RX, "UART template argument must be a serial device with RX mode");
125
126 public:
128 using UART = UART_;
129
137 explicit Grove125KHzRFIDReaderUART(UART& uart) : uart_{uart}, in_{uart_.in()}, buf_{in_.rdbuf()} {}
138
141 Grove125KHzRFIDReaderUART& operator=(const Grove125KHzRFIDReaderUART&) = delete;
143
149 void begin()
150 {
151 // Just start UART with proper settings: 9600bps, 8 bits, 1 stop, no parity
152 uart_.begin(UART_SPEED, serial::Parity::NONE, serial::StopBits::ONE);
153 }
154
160 void end()
161 {
162 // Stop UART
164 }
165
178 bool has_data()
179 {
180 return buf_.sgetc() != streams::istreambuf::EOF;
181 }
182
206 void get_data(char* data, uint8_t size)
207 {
208 // 1. Wait for STX
209 while (in_.get() != STX)
210 time::yield();
211
212 // 2. Read each character until ETX
213 in_.getline(data, size, ETX);
214 }
215
216 private:
217 static constexpr char STX = 0x02;
218 static constexpr char ETX = 0x03;
219
220 UART& uart_;
223 };
224
251 template<board::ExternalInterruptPin DATA0_, board::ExternalInterruptPin DATA1_>
253 {
254 static constexpr board::ExternalInterruptPin DATA0 = DATA0_;
255 static constexpr board::ExternalInterruptPin DATA1 = DATA1_;
256 static_assert(DATA0 != DATA1, "DATA0 and DATA1 must be two distinct pins");
257
258 public:
264
271 static constexpr uint8_t DATA_BITS = protocols::Wiegand::DATA_BITS;
272
278 {
280 }
281
286
292 void begin()
293 {
294 enabler0_.enable();
295 enabler1_.enable();
296 }
297
303 void end()
304 {
305 enabler0_.disable();
306 enabler1_.disable();
307 }
308
316 bool has_data()
317 {
318 synchronized return wiegand_.available_() && wiegand_.valid_();
319 }
320
334 void get_data(DATA_TYPE& data)
335 {
336 if (has_data())
337 {
338 data = wiegand_.get_data_();
339 wiegand_.reset();
340 }
341 else
342 data = DATA_TYPE{};
343 }
344
345 private:
346 void fall_0()
347 {
348 wiegand_.on_falling_data0();
349 }
350
351 void fall_1()
352 {
353 wiegand_.on_falling_data1();
354 }
355
360 protocols::Wiegand wiegand_;
361
362 friend struct isr_handler_grove;
363 };
364
393 template<board::InterruptPin DATA0_, board::InterruptPin DATA1_>
395 {
396 static constexpr board::InterruptPin DATA0 = DATA0_;
397 static constexpr board::InterruptPin DATA1 = DATA1_;
398
399 static constexpr board::DigitalPin DATA0_PIN = board::PCI_PIN<DATA0>();
400 using DATA0_TRAIT = board_traits::DigitalPin_trait<DATA0_PIN>;
401 static constexpr board::DigitalPin DATA1_PIN = board::PCI_PIN<DATA1>();
402 using DATA1_TRAIT = board_traits::DigitalPin_trait<DATA1_PIN>;
403 using DATA_SIGNAL = interrupt::PCI_SIGNAL<DATA0>;
404
405 static_assert(DATA0 != DATA1, "DATA0 and DATA1 must be two distinct pins");
406 static_assert(DATA0_TRAIT::PORT == DATA1_TRAIT::PORT, "DATA0 and DATA1 must be on the same port");
407
408 public:
414
421 static constexpr uint8_t DATA_BITS = protocols::Wiegand::DATA_BITS;
422
428 {
430 enabler_.set_enable_pins(PCI_MASK);
431 }
432
437
443 void begin()
444 {
445 enabler_.enable();
446 }
447
453 void end()
454 {
455 enabler_.disable();
456 }
457
465 bool has_data()
466 {
467 synchronized return wiegand_.available_() && wiegand_.valid_();
468 }
469
483 void get_data(DATA_TYPE& data)
484 {
485 if (has_data())
486 {
487 data = wiegand_.get_data_();
488 wiegand_.reset();
489 }
490 else
491 data = DATA_TYPE{};
492 }
493
494 private:
495 void fall_0_or_1()
496 {
497 if (!data0_.value())
498 wiegand_.on_falling_data0();
499 else if (!data1_.value())
500 wiegand_.on_falling_data1();
501 }
502
503 static constexpr uint8_t PCI_MASK = bits::BV8(DATA0_TRAIT::BIT, DATA1_TRAIT::BIT);
504
507 DATA_SIGNAL enabler_;
508 protocols::Wiegand wiegand_;
509
510 friend struct isr_handler_grove;
511 };
512
514 // Traits for Grove RFID Readers
515 template<typename READER> struct Grove125KHzRFIDReader_trait
516 {
517 static constexpr bool IS_GROVE_125_READER = false;
518 static constexpr bool IS_UART_MODE = false;
519 static constexpr bool IS_WIEGAND_MODE = false;
520 static constexpr bool IS_PCI = false;
521 static constexpr bool IS_EXT = false;
522 static constexpr bool USES_DISTINCT_PINS = false;
523 };
524 template<typename UART> struct Grove125KHzRFIDReader_trait<Grove125KHzRFIDReaderUART<UART>>
525 {
526 static constexpr bool IS_GROVE_125_READER = true;
527 static constexpr bool IS_UART_MODE = true;
528 static constexpr bool IS_WIEGAND_MODE = false;
529 static constexpr bool IS_PCI = false;
530 static constexpr bool IS_EXT = false;
531 static constexpr bool USES_DISTINCT_PINS = false;
532 };
533 template<board::ExternalInterruptPin DATA0, board::ExternalInterruptPin DATA1>
534 struct Grove125KHzRFIDReader_trait<Grove125KHzRFIDReaderWiegandEXT<DATA0, DATA1>>
535 {
536 static constexpr bool IS_GROVE_125_READER = true;
537 static constexpr bool IS_UART_MODE = false;
538 static constexpr bool IS_WIEGAND_MODE = true;
539 static constexpr bool IS_PCI = false;
540 static constexpr bool IS_EXT = true;
541 static constexpr bool USES_DISTINCT_PINS = (DATA0 != DATA1);
542 };
543 template<board::InterruptPin DATA0, board::InterruptPin DATA1>
544 struct Grove125KHzRFIDReader_trait<Grove125KHzRFIDReaderWiegandPCI<DATA0, DATA1>>
545 {
546 static constexpr bool IS_GROVE_125_READER = true;
547 static constexpr bool IS_UART_MODE = false;
548 static constexpr bool IS_WIEGAND_MODE = true;
549 static constexpr bool IS_PCI = true;
550 static constexpr bool IS_EXT = false;
551 static constexpr bool USES_DISTINCT_PINS = (DATA0 != DATA1);
552 };
554
556 struct isr_handler_grove
557 {
558 template<uint8_t DATA0_NUM, uint8_t DATA1_NUM, typename READER>
559 static void callback_fall_0()
560 {
561 // Check READER is a proper type
562 using GROVE_TRAIT = Grove125KHzRFIDReader_trait<READER>;
563 static_assert(GROVE_TRAIT::IS_GROVE_125_READER, "READER must be a Grove125KHzRFIDReaderWiegandEXT type");
564 static_assert(GROVE_TRAIT::IS_WIEGAND_MODE, "READER must be a Grove125KHzRFIDReaderWiegandEXT type");
565 static_assert(GROVE_TRAIT::IS_EXT, "READER must be a Grove125KHzRFIDReaderWiegandEXT type");
566 // Check pins are compliant
567 interrupt::isr_handler_int::check_int_pin<DATA0_NUM, READER::DATA0>();
568 interrupt::isr_handler_int::check_int_pin<DATA1_NUM, READER::DATA1>();
569 static_assert(DATA0_NUM != DATA1_NUM, "DATA0 and DATA1 must be two distinct pins");
570 // Call Grove RFID handler
571 interrupt::CallbackHandler<void (READER::*)(), &READER::fall_0>::call();
572 }
573
574 template<uint8_t DATA0_NUM, uint8_t DATA1_NUM, typename READER>
575 static void callback_fall_1()
576 {
577 // Check READER is a proper type
578 using GROVE_TRAIT = Grove125KHzRFIDReader_trait<READER>;
579 static_assert(GROVE_TRAIT::IS_GROVE_125_READER, "READER must be a Grove125KHzRFIDReaderWiegandEXT type");
580 static_assert(GROVE_TRAIT::IS_WIEGAND_MODE, "READER must be a Grove125KHzRFIDReaderWiegandEXT type");
581 static_assert(GROVE_TRAIT::IS_EXT, "READER must be a Grove125KHzRFIDReaderWiegandEXT type");
582 // Check pins are compliant
583 interrupt::isr_handler_int::check_int_pin<DATA0_NUM, READER::DATA0>();
584 interrupt::isr_handler_int::check_int_pin<DATA1_NUM, READER::DATA1>();
585 static_assert(DATA0_NUM != DATA1_NUM, "DATA0 and DATA1 must be two distinct pins");
586 // Call Grove RFID handler
587 interrupt::CallbackHandler<void (READER::*)(), &READER::fall_1>::call();
588 }
589
590 template<uint8_t DATA01_NUM, typename READER>
591 static void callback_fall_0_or_1()
592 {
593 // Check READER is a proper type
594 using GROVE_TRAIT = Grove125KHzRFIDReader_trait<READER>;
595 static_assert(GROVE_TRAIT::IS_GROVE_125_READER, "READER must be a Grove125KHzRFIDReaderWiegandPCI type");
596 static_assert(GROVE_TRAIT::IS_WIEGAND_MODE, "READER must be a Grove125KHzRFIDReaderWiegandPCI type");
597 static_assert(GROVE_TRAIT::IS_PCI, "READER must be a Grove125KHzRFIDReaderWiegandPCI type");
598 // Check pins are compliant
599 static_assert(GROVE_TRAIT::USES_DISTINCT_PINS, "DATA0 and DATA1 must be two distinct pins");
600 interrupt::isr_handler_pci::check_pci_pins<DATA01_NUM, READER::DATA0, READER::DATA1>();
601 // Call Grove RFID handler
602 interrupt::CallbackHandler<void (READER::*)(), &READER::fall_0_or_1>::call();
603 }
604 };
606}
607
608#endif /* GROVE_RFID_READER_HH */
bool available_() const
Check if data is available, i.e.
Definition: wiegand.h:127
DATA_TYPE get_data_() const
Get data read from access control device.
Definition: wiegand.h:170
static constexpr uint8_t DATA_BITS
The actual number of bits of data in DATA_TYPE.
Definition: wiegand.h:71
bool valid_() const
Check if current data is valid, i.e.
Definition: wiegand.h:144
void reset()
Reset current read state of this instance.
Definition: wiegand.h:93
void on_falling_data0()
Your device shall call this method whenever DATA0 line level is falling to 0, which means a 0 bit mus...
Definition: wiegand.h:184
void on_falling_data1()
Your device shall call this method whenever DATA1 line level is falling to 0, which means a 1 bit mus...
Definition: wiegand.h:217
uint32_t DATA_TYPE
The data type used to return data read from the access control device.
Definition: wiegand.h:63
Support for seeedstudio Grove 125KHz RFID Reader in UART mode.
UART_ UART
The UART type used to communicate with the Grove device.
void begin()
Start operations of the device.
Grove125KHzRFIDReaderUART(UART &uart)
Construct a new Grove 125KHz RFID Reader UART instance.
void end()
Stop operations of the device.
void get_data(char *data, uint8_t size)
Get complete data as ASCII C-string from the Grove device.
bool has_data()
Check if data from Grove device is ready to read.
Support for seeedstudio Grove 125KHz RFID Reader in Wiegand mode.
void end()
Stop operations of the device.
typename protocols::Wiegand::DATA_TYPE DATA_TYPE
The data type used to return data read from the Grove device.
bool has_data()
Check if data from Grove device is ready to read and valid (correct parity).
static constexpr uint8_t DATA_BITS
The actual number of bits of data in DATA_TYPE.
void begin()
Start operations of the device.
Grove125KHzRFIDReaderWiegandEXT()
Construct a new Grove 125KHz RFID Reader instance in Wiegand mode, where wires are connected to board...
void get_data(DATA_TYPE &data)
Get complete data as a DATA_TYPE value (integral type) from the Grove device.
Support for seeedstudio Grove 125KHz RFID Reader in Wiegand mode.
typename protocols::Wiegand::DATA_TYPE DATA_TYPE
The data type used to return data read from the Grove device.
void end()
Stop operations of the device.
void get_data(DATA_TYPE &data)
Get complete data as a DATA_TYPE value (integral type) from the Grove device.
Grove125KHzRFIDReaderWiegandPCI()
Construct a new Grove 125KHz RFID Reader instance in Wiegand mode, where wires are connected to board...
static constexpr uint8_t DATA_BITS
The actual number of bits of data in DATA_TYPE.
void begin()
Start operations of the device.
bool has_data()
Check if data from Grove device is ready to read and valid (correct parity).
Handler of an External Interrupt.
Definition: int.h:132
void disable()
Disable interrupts for this external interrupt pin.
Definition: int.h:195
void enable()
Enable interrupts for this external interrupt pin.
Definition: int.h:183
Input stream wrapper to provide formatted input API, a la C++.
Definition: streams.h:360
int get()
Extract a single character from this input stream.
Definition: streams.h:397
istream & getline(char *str, size_t n, char delim='\n')
Extract characters from this input stream and stores them as a C-string, until either (n - 1) charact...
Definition: streams.h:445
Input API based on a ring buffer.
Definition: streambuf.h:257
static const int EOF
Special value returned by sbumpc() when buffer is empty.
Definition: streambuf.h:268
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
DigitalPin
Defines all available digital input/output pins of the target MCU.
Definition: empty.h:56
InterruptPin
Defines all digital output pins of target MCU, usable as pin change interrupt (PCI) pins.
Definition: empty.h:98
ExternalInterruptPin
Defines all digital output pins of target MCU, usable as direct external interrupt pins.
Definition: empty.h:91
This namespace contains classes to support various RFID devices.
Defines all API for all external devices supported by FastArduino.
typename FastPinType< DPIN_ >::TYPE FAST_PIN
Useful alias type to the FastPin type matching a given board::DigitalPin.
Definition: gpio.h:694
typename FastPinType< board::EXT_PIN< EPIN_ >()>::TYPE FAST_EXT_PIN
Useful alias type to the FastPin type matching a given board::ExternalInterruptPin.
Definition: gpio.h:740
@ INPUT_PULLUP
Digital pin is configured as input with an internal pullup resistor.
@ FALLING_EDGE
Interrupt is triggered whenever pin level is falling from high to low.
typename PCIType< PIN >::TYPE PCI_SIGNAL
Useful alias type to the PCISignal type matching a given board::InterruptPin.
Definition: pci.h:568
void register_handler(Handler &handler)
Register a class instance containing methods that shall be called back by an ISR.
Definition: interrupts.h:185
@ CLEAR
Stop transmission immediately, clear buffer.
@ ONE
One stop bit.
@ NONE
No parity bit.
void yield()
Utility method used by many FastArduino API in order to "yield" some processor time; concretely it ju...
Definition: time.cpp:22
Common types used by 3D sensors (e.g.