Merge branch 'mega' into feature/taskvalueset_by_name

This commit is contained in:
Ton Huisman
2021-03-27 13:06:52 +01:00
committed by GitHub
15 changed files with 2842 additions and 1 deletions
+83
View File
@@ -0,0 +1,83 @@
.. include:: ../Plugin/_plugin_substitutions_p11x.repl
.. _P111_page:
|P111_typename|
==================================================
|P111_shortinfo|
Plugin details
--------------
Type: |P111_type|
Name: |P111_name|
Status: |P111_status|
GitHub: |P111_github|_
Maintainer: |P111_maintainer|
Used libraries: |P111_usedlibraries|
Description
-----------
This SPI device reads the tag ID from Mifare tags, cards and stickers using the NXP MFRC522 NFC chip.
The value is placed in the Tag variable, and can be read from rules and sent to controllers.
Settings
--------
.. image:: P111_Settings.png
**Name**: The name for this task, should be unique.
**Enabled**: Allows to enable/disable the device.
This device is connected via SPI, so the SPI interface should be enabled on the Hardware tab. There, also the common SPI pin numbers are shown. CS and other optional pin configurations are to be set in the device cconfiguration.
The MFRC522 needs at least the CS pin configured, the RST (Reset) pin is optional.
**CS Pin**: The Chip Select signal, often labeled SDA on the board.
**RST Pin**: Optional pin that is pulled low when communication with the device fails a few times. Usually labeled RST on the board.
**Tag removal mode** After scanning a tag, it can be automatically removed (reset). There are 2 removal modes, 'None' and 'Autoremove after Time-out' (default).
**Tag removal Time-out** (Default 500 mSec) The timeout in milli seconds (range 0 - 60000) after which the last Tag will be automatically removed, if the Time-out option is selected.
**Value to set on Tag removal** (Default 0) Set a value to the Tag when the previous tag is removed. (Range 0 to 2147483647 as larger values are difficult to store in settings.)
**Event on Tag removal** (Disabled by default) When enabled sends the removed Tag value as an event and to all enabled controllers.
Supported hardware
------------------
MFRC522 based NFC RFID reader connected via SPI.
|P111_usedby|
.. Commands available
.. ^^^^^^^^^^^^^^^^^^
.. .. include:: P111_commands.repl
.. Events
.. ~~~~~~
.. .. include:: P111_events.repl
Change log
----------
.. versionadded:: 2.0
...
|added|
2021-02-07: Moved from PluginPlayground to main repository.
Added options for tag reset and event on tag reset.
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+1
View File
@@ -130,6 +130,7 @@ There's three different released versions of ESP Easy:
":ref:`P106_page`","|P106_status|","P106"
":ref:`P107_page`","|P107_status|","P107"
":ref:`P108_page`","|P108_status|","P108"
":ref:`P111_page`","|P111_status|","P111"
Internal GPIO handling
+1 -1
View File
@@ -21,7 +21,7 @@
.. |Plugin_Output| replace:: :ref:`P029_page`, :ref:`P038_page`, :ref:`P041_page`, :ref:`P042_page`, :ref:`P043_page`, :ref:`P070_page`
.. |Plugin_Position| replace:: :ref:`P013_page`, :ref:`P082_page`
.. |Plugin_Regulator| replace:: :ref:`P021_page`
.. |Plugin_RFID| replace:: :ref:`P008_page`, :ref:`P017_page`, :ref:`P040_page`
.. |Plugin_RFID| replace:: :ref:`P008_page`, :ref:`P017_page`, :ref:`P040_page`, :ref:`P111_page`
.. |Plugin_Switch_input| replace:: :ref:`P001_page`, :ref:`P009_page`, :ref:`P019_page`, :ref:`P059_page`, :ref:`P080_page`, :ref:`P091_page`, :ref:`P097_page`
.. |Plugin_Touch| replace:: :ref:`P097_page`, :ref:`P099_page`
.. |Plugin_Weight| replace:: :ref:`P067_page`
@@ -9,3 +9,4 @@
.. include:: ../Plugin/_plugin_substitutions_p08x.repl
.. include:: ../Plugin/_plugin_substitutions_p09x.repl
.. include:: ../Plugin/_plugin_substitutions_p10x.repl
.. include:: ../Plugin/_plugin_substitutions_p11x.repl
@@ -0,0 +1,13 @@
.. |P111_name| replace:: :cyan:`MFRC5222`
.. |P111_type| replace:: :cyan:`RFID`
.. |P111_typename| replace:: :cyan:`RFID - MFRC522`
.. |P111_porttype| replace:: `.`
.. |P111_status| replace:: :yellow:`TESTING`
.. |P111_github| replace:: P111_RC522_RFID.ino
.. _P111_github: https://github.com/letscontrolit/ESPEasy/blob/mega/src/_P111_RC522_RFID.ino
.. |P111_usedby| replace:: `.`
.. |P111_shortinfo| replace:: `RFID Reader`
.. |P111_maintainer| replace:: `TD-er, twinbee77, tonhuisman`
.. |P111_compileinfo| replace:: `.`
.. |P111_usedlibraries| replace:: `https://github.com/miguelbalboa/rfid (local copy)`
File diff suppressed because it is too large Load Diff
+371
View File
@@ -0,0 +1,371 @@
/**
* Library to use Arduino MFRC522 module.
*
* @authors Dr.Leong, Miguel Balboa, Søren Thing Andersen, Tom Clement, many more! See GitLog.
*
* For more information read the README.
*
* Please read this file for an overview and then MFRC522.cpp for comments on the specific functions.
*/
#ifndef MFRC522_h
#define MFRC522_h
#include "require_cpp11.h"
#include "deprecated.h"
// Enable integer limits
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <Arduino.h>
#include <SPI.h>
#ifndef MFRC522_SPICLOCK
#define MFRC522_SPICLOCK (4000000u) // MFRC522 accept upto 10MHz, set to 4MHz.
#endif
// Firmware data for self-test
// Reference values based on firmware version
// Hint: if needed, you can remove unused self-test data to save flash memory
//
// Version 0.0 (0x90)
// Philips Semiconductors; Preliminary Specification Revision 2.0 - 01 August 2005; 16.1 self-test
const byte MFRC522_firmware_referenceV0_0[] PROGMEM = {
0x00, 0x87, 0x98, 0x0f, 0x49, 0xFF, 0x07, 0x19,
0xBF, 0x22, 0x30, 0x49, 0x59, 0x63, 0xAD, 0xCA,
0x7F, 0xE3, 0x4E, 0x03, 0x5C, 0x4E, 0x49, 0x50,
0x47, 0x9A, 0x37, 0x61, 0xE7, 0xE2, 0xC6, 0x2E,
0x75, 0x5A, 0xED, 0x04, 0x3D, 0x02, 0x4B, 0x78,
0x32, 0xFF, 0x58, 0x3B, 0x7C, 0xE9, 0x00, 0x94,
0xB4, 0x4A, 0x59, 0x5B, 0xFD, 0xC9, 0x29, 0xDF,
0x35, 0x96, 0x98, 0x9E, 0x4F, 0x30, 0x32, 0x8D
};
// Version 1.0 (0x91)
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 self-test
const byte MFRC522_firmware_referenceV1_0[] PROGMEM = {
0x00, 0xC6, 0x37, 0xD5, 0x32, 0xB7, 0x57, 0x5C,
0xC2, 0xD8, 0x7C, 0x4D, 0xD9, 0x70, 0xC7, 0x73,
0x10, 0xE6, 0xD2, 0xAA, 0x5E, 0xA1, 0x3E, 0x5A,
0x14, 0xAF, 0x30, 0x61, 0xC9, 0x70, 0xDB, 0x2E,
0x64, 0x22, 0x72, 0xB5, 0xBD, 0x65, 0xF4, 0xEC,
0x22, 0xBC, 0xD3, 0x72, 0x35, 0xCD, 0xAA, 0x41,
0x1F, 0xA7, 0xF3, 0x53, 0x14, 0xDE, 0x7E, 0x02,
0xD9, 0x0F, 0xB5, 0x5E, 0x25, 0x1D, 0x29, 0x79
};
// Version 2.0 (0x92)
// NXP Semiconductors; Rev. 3.8 - 17 September 2014; 16.1.1 self-test
const byte MFRC522_firmware_referenceV2_0[] PROGMEM = {
0x00, 0xEB, 0x66, 0xBA, 0x57, 0xBF, 0x23, 0x95,
0xD0, 0xE3, 0x0D, 0x3D, 0x27, 0x89, 0x5C, 0xDE,
0x9D, 0x3B, 0xA7, 0x00, 0x21, 0x5B, 0x89, 0x82,
0x51, 0x3A, 0xEB, 0x02, 0x0C, 0xA5, 0x00, 0x49,
0x7C, 0x84, 0x4D, 0xB3, 0xCC, 0xD2, 0x1B, 0x81,
0x5D, 0x48, 0x76, 0xD5, 0x71, 0x61, 0x21, 0xA9,
0x86, 0x96, 0x83, 0x38, 0xCF, 0x9D, 0x5B, 0x6D,
0xDC, 0x15, 0xBA, 0x3E, 0x7D, 0x95, 0x3B, 0x2F
};
// Clone
// Fudan Semiconductor FM17522 (0x88)
const byte FM17522_firmware_reference[] PROGMEM = {
0x00, 0xD6, 0x78, 0x8C, 0xE2, 0xAA, 0x0C, 0x18,
0x2A, 0xB8, 0x7A, 0x7F, 0xD3, 0x6A, 0xCF, 0x0B,
0xB1, 0x37, 0x63, 0x4B, 0x69, 0xAE, 0x91, 0xC7,
0xC3, 0x97, 0xAE, 0x77, 0xF4, 0x37, 0xD7, 0x9B,
0x7C, 0xF5, 0x3C, 0x11, 0x8F, 0x15, 0xC3, 0xD7,
0xC1, 0x5B, 0x00, 0x2A, 0xD0, 0x75, 0xDE, 0x9E,
0x51, 0x64, 0xAB, 0x3E, 0xE9, 0x15, 0xB5, 0xAB,
0x56, 0x9A, 0x98, 0x82, 0x26, 0xEA, 0x2A, 0x62
};
class MFRC522 {
public:
// Size of the MFRC522 FIFO
static constexpr byte FIFO_SIZE = 64; // The FIFO is 64 bytes.
// Default value for unused pin
static constexpr uint8_t UNUSED_PIN = UINT8_MAX;
// MFRC522 registers. Described in chapter 9 of the datasheet.
// When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3)
enum PCD_Register : byte {
// Page 0: Command and status
// 0x00 // reserved for future use
CommandReg = 0x01 << 1, // starts and stops command execution
ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits
DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits
ComIrqReg = 0x04 << 1, // interrupt request bits
DivIrqReg = 0x05 << 1, // interrupt request bits
ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed
Status1Reg = 0x07 << 1, // communication status bits
Status2Reg = 0x08 << 1, // receiver and transmitter status bits
FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer
FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer
WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning
ControlReg = 0x0C << 1, // miscellaneous control registers
BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames
CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface
// 0x0F // reserved for future use
// Page 1: Command
// 0x10 // reserved for future use
ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving
TxModeReg = 0x12 << 1, // defines transmission data rate and framing
RxModeReg = 0x13 << 1, // defines reception data rate and framing
TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2
TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation
TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver
RxSelReg = 0x17 << 1, // selects internal receiver settings
RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder
DemodReg = 0x19 << 1, // defines demodulator settings
// 0x1A // reserved for future use
// 0x1B // reserved for future use
MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters
MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters
// 0x1E // reserved for future use
SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface
// Page 2: Configuration
// 0x20 // reserved for future use
CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation
CRCResultRegL = 0x22 << 1,
// 0x23 // reserved for future use
ModWidthReg = 0x24 << 1, // controls the ModWidth setting?
// 0x25 // reserved for future use
RFCfgReg = 0x26 << 1, // configures the receiver gain
GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation
CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation
ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation
TModeReg = 0x2A << 1, // defines settings for the internal timer
TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value
TReloadRegL = 0x2D << 1,
TCounterValueRegH = 0x2E << 1, // shows the 16-bit timer value
TCounterValueRegL = 0x2F << 1,
// Page 3: Test Registers
// 0x30 // reserved for future use
TestSel1Reg = 0x31 << 1, // general test signal configuration
TestSel2Reg = 0x32 << 1, // general test signal configuration
TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7
TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus
TestBusReg = 0x35 << 1, // shows the status of the internal test bus
AutoTestReg = 0x36 << 1, // controls the digital self-test
VersionReg = 0x37 << 1, // shows the software version
AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2
TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1
TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2
TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels
// 0x3C // reserved for production tests
// 0x3D // reserved for production tests
// 0x3E // reserved for production tests
// 0x3F // reserved for production tests
};
// MFRC522 commands. Described in chapter 10 of the datasheet.
enum PCD_Command : byte {
PCD_Idle = 0x00, // no action, cancels current command execution
PCD_Mem = 0x01, // stores 25 bytes into the internal buffer
PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number
PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self-test
PCD_Transmit = 0x04, // transmits data from the FIFO buffer
PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
PCD_Receive = 0x08, // activates the receiver circuits
PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader
PCD_SoftReset = 0x0F // resets the MFRC522
};
// MFRC522 RxGain[2:0] masks, defines the receiver's signal voltage gain factor (on the PCD).
// Described in 9.3.3.6 / table 98 of the datasheet at http://www.nxp.com/documents/data_sheet/MFRC522.pdf
enum PCD_RxGain : byte {
RxGain_18dB = 0x00 << 4, // 000b - 18 dB, minimum
RxGain_23dB = 0x01 << 4, // 001b - 23 dB
RxGain_18dB_2 = 0x02 << 4, // 010b - 18 dB, it seems 010b is a duplicate for 000b
RxGain_23dB_2 = 0x03 << 4, // 011b - 23 dB, it seems 011b is a duplicate for 001b
RxGain_33dB = 0x04 << 4, // 100b - 33 dB, average, and typical default
RxGain_38dB = 0x05 << 4, // 101b - 38 dB
RxGain_43dB = 0x06 << 4, // 110b - 43 dB
RxGain_48dB = 0x07 << 4, // 111b - 48 dB, maximum
RxGain_min = 0x00 << 4, // 000b - 18 dB, minimum, convenience for RxGain_18dB
RxGain_avg = 0x04 << 4, // 100b - 33 dB, average, convenience for RxGain_33dB
RxGain_max = 0x07 << 4 // 111b - 48 dB, maximum, convenience for RxGain_48dB
};
// Commands sent to the PICC.
enum PICC_Command : byte {
// The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision.
PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1
PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 2
PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 3
PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT.
PICC_CMD_RATS = 0xE0, // Request command for Answer To Reset.
// The commands used for MIFARE Classic (from http://www.mouser.com/ds/2/302/MF1S503x-89574.pdf, Section 9)
// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
// The read/write commands can also be used for MIFARE Ultralight.
PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A
PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B
PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight.
PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register.
PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register.
PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block.
// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
// The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight.
PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC.
};
// MIFARE constants that does not fit anywhere else
enum MIFARE_Misc {
MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK.
MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes.
};
// PICC types we can detect. Remember to update PICC_GetTypeName() if you add more.
// last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered
enum PICC_Type : byte {
PICC_TYPE_UNKNOWN ,
PICC_TYPE_ISO_14443_4 , // PICC compliant with ISO/IEC 14443-4
PICC_TYPE_ISO_18092 , // PICC compliant with ISO/IEC 18092 (NFC)
PICC_TYPE_MIFARE_MINI , // MIFARE Classic protocol, 320 bytes
PICC_TYPE_MIFARE_1K , // MIFARE Classic protocol, 1KB
PICC_TYPE_MIFARE_4K , // MIFARE Classic protocol, 4KB
PICC_TYPE_MIFARE_UL , // MIFARE Ultralight or Ultralight C
PICC_TYPE_MIFARE_PLUS , // MIFARE Plus
PICC_TYPE_MIFARE_DESFIRE, // MIFARE DESFire
PICC_TYPE_TNP3XXX , // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure
PICC_TYPE_NOT_COMPLETE = 0xff // SAK indicates UID is not complete.
};
// Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more.
// last value set to 0xff, then compiler uses less ram, it seems some optimisations are triggered
enum StatusCode : byte {
STATUS_OK , // Success
STATUS_ERROR , // Error in communication
STATUS_COLLISION , // Collission detected
STATUS_TIMEOUT , // Timeout in communication.
STATUS_NO_ROOM , // A buffer is not big enough.
STATUS_INTERNAL_ERROR , // Internal error in the code. Should not happen ;-)
STATUS_INVALID , // Invalid argument.
STATUS_CRC_WRONG , // The CRC_A does not match
STATUS_MIFARE_NACK = 0xff // A MIFARE PICC responded with NAK.
};
// A struct used for passing the UID of a PICC.
typedef struct {
byte size; // Number of bytes in the UID. 4, 7 or 10.
byte uidByte[10];
byte sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection.
} Uid;
// A struct used for passing a MIFARE Crypto1 key
typedef struct {
byte keyByte[MF_KEY_SIZE];
} MIFARE_Key;
// Member variables
Uid uid; // Used by PICC_ReadCardSerial().
/////////////////////////////////////////////////////////////////////////////////////
// Functions for setting up the Arduino
/////////////////////////////////////////////////////////////////////////////////////
MFRC522();
MFRC522(byte resetPowerDownPin);
MFRC522(byte chipSelectPin, byte resetPowerDownPin);
/////////////////////////////////////////////////////////////////////////////////////
// Basic interface functions for communicating with the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_WriteRegister(PCD_Register reg, byte value);
void PCD_WriteRegister(PCD_Register reg, byte count, byte *values);
byte PCD_ReadRegister(PCD_Register reg);
void PCD_ReadRegister(PCD_Register reg, byte count, byte *values, byte rxAlign = 0);
void PCD_SetRegisterBitMask(PCD_Register reg, byte mask);
void PCD_ClearRegisterBitMask(PCD_Register reg, byte mask);
StatusCode PCD_CalculateCRC(byte *data, byte length, byte *result);
/////////////////////////////////////////////////////////////////////////////////////
// Functions for manipulating the MFRC522
/////////////////////////////////////////////////////////////////////////////////////
void PCD_Init();
void PCD_Init(byte resetPowerDownPin);
void PCD_Init(byte chipSelectPin, byte resetPowerDownPin);
void PCD_Reset();
void PCD_AntennaOn();
void PCD_AntennaOff();
byte PCD_GetAntennaGain();
void PCD_SetAntennaGain(byte mask);
bool PCD_PerformSelfTest();
/////////////////////////////////////////////////////////////////////////////////////
// Power control functions
/////////////////////////////////////////////////////////////////////////////////////
void PCD_SoftPowerDown();
void PCD_SoftPowerUp();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with PICCs
/////////////////////////////////////////////////////////////////////////////////////
StatusCode PCD_TransceiveData(byte *sendData, byte sendLen, byte *backData, byte *backLen, byte *validBits = nullptr, byte rxAlign = 0, bool checkCRC = false);
StatusCode PCD_CommunicateWithPICC(byte command, byte waitIRq, byte *sendData, byte sendLen, byte *backData = nullptr, byte *backLen = nullptr, byte *validBits = nullptr, byte rxAlign = 0, bool checkCRC = false);
StatusCode PICC_RequestA(byte *bufferATQA, byte *bufferSize);
StatusCode PICC_WakeupA(byte *bufferATQA, byte *bufferSize);
StatusCode PICC_REQA_or_WUPA(byte command, byte *bufferATQA, byte *bufferSize);
virtual StatusCode PICC_Select(Uid *uid, byte validBits = 0);
StatusCode PICC_HaltA();
/////////////////////////////////////////////////////////////////////////////////////
// Functions for communicating with MIFARE PICCs
/////////////////////////////////////////////////////////////////////////////////////
StatusCode PCD_Authenticate(byte command, byte blockAddr, MIFARE_Key *key, Uid *uid);
void PCD_StopCrypto1();
StatusCode MIFARE_Read(byte blockAddr, byte *buffer, byte *bufferSize);
StatusCode MIFARE_Write(byte blockAddr, byte *buffer, byte bufferSize);
StatusCode MIFARE_Ultralight_Write(byte page, byte *buffer, byte bufferSize);
StatusCode MIFARE_Decrement(byte blockAddr, int32_t delta);
StatusCode MIFARE_Increment(byte blockAddr, int32_t delta);
StatusCode MIFARE_Restore(byte blockAddr);
StatusCode MIFARE_Transfer(byte blockAddr);
StatusCode MIFARE_GetValue(byte blockAddr, int32_t *value);
StatusCode MIFARE_SetValue(byte blockAddr, int32_t value);
StatusCode PCD_NTAG216_AUTH(byte *passWord, byte pACK[]);
/////////////////////////////////////////////////////////////////////////////////////
// Support functions
/////////////////////////////////////////////////////////////////////////////////////
StatusCode PCD_MIFARE_Transceive(byte *sendData, byte sendLen, bool acceptTimeout = false);
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
//const char *GetStatusCodeName(byte code);
static const __FlashStringHelper *GetStatusCodeName(StatusCode code);
static PICC_Type PICC_GetType(byte sak);
// old function used too much memory, now name moved to flash; if you need char, copy from flash to memory
//const char *PICC_GetTypeName(byte type);
static const __FlashStringHelper *PICC_GetTypeName(PICC_Type type);
// Support functions for debuging
void PCD_DumpVersionToSerial();
void PICC_DumpToSerial(Uid *uid);
void PICC_DumpDetailsToSerial(Uid *uid);
void PICC_DumpMifareClassicToSerial(Uid *uid, PICC_Type piccType, MIFARE_Key *key);
void PICC_DumpMifareClassicSectorToSerial(Uid *uid, MIFARE_Key *key, byte sector);
void PICC_DumpMifareUltralightToSerial();
// Advanced functions for MIFARE
void MIFARE_SetAccessBits(byte *accessBitBuffer, byte g0, byte g1, byte g2, byte g3);
bool MIFARE_OpenUidBackdoor(bool logErrors);
bool MIFARE_SetUid(byte *newUid, byte uidSize, bool logErrors);
bool MIFARE_UnbrickUidSector(bool logErrors);
/////////////////////////////////////////////////////////////////////////////////////
// Convenience functions - does not add extra functionality
/////////////////////////////////////////////////////////////////////////////////////
virtual bool PICC_IsNewCardPresent();
virtual bool PICC_ReadCardSerial();
protected:
byte _chipSelectPin; // Arduino pin connected to MFRC522's SPI slave select input (Pin 24, NSS, active low)
byte _resetPowerDownPin; // Arduino pin connected to MFRC522's reset and power down input (Pin 6, NRSTPD, active low)
StatusCode MIFARE_TwoStepHelper(byte command, byte blockAddr, int32_t data);
};
#endif
+28
View File
@@ -0,0 +1,28 @@
/**
* Copyright (c) 2016 by Ludwig Grill (www.rotzbua.de)
* Simple deprecated workaround for Arduino IDE
* IDE 1.6.8 use gcc 4.8 which do not support c++14 [[deprecated]]
* Later versions should support c++14, then use c++14 syntax
*/
#ifndef DEPRECATED_H
#define DEPRECATED_H
#ifdef __has_cpp_attribute
#if __has_cpp_attribute(deprecated)
#ifndef DEPRECATED
#define DEPRECATED [[deprecated]]
#endif
#ifndef DEPRECATED_MSG
#define DEPRECATED_MSG(msg) [[deprecated(msg)]]
#endif
#endif // __has_cpp_attribute(deprecated)
#else
#ifndef DEPRECATED
#define DEPRECATED __attribute__((deprecated))
#endif
#ifndef DEPRECATED_MSG
#define DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
#endif
#endif // __has_cpp_attribute
#endif // DEPRECATED_H
+12
View File
@@ -0,0 +1,12 @@
/**
* Copyright (c) 2016 by Ludwig Grill (www.rotzbua.de)
* Throws error if c++11 is not supported
*/
#ifndef REQUIRE_CPP11_H
#define REQUIRE_CPP11_H
#if __cplusplus < 201103L
#error "This library needs at least a C++11 compliant compiler, maybe compiler argument for C++11 support is missing or if you use Arduino IDE upgrade to version >=1.6.6"
#endif
#endif // REQUIRE_CPP11_H
+1
View File
@@ -290,6 +290,7 @@
// #define USES_P105 // Atlas_EZO_ORP
// #define USES_P106 // BME680
// #define USES_P107 // Si1145
// #define USES_P111 // RF522 RFID reader
// Special plugins needing IR library
+214
View File
@@ -0,0 +1,214 @@
#include "_Plugin_Helper.h"
#ifdef USES_P111
//#######################################################################################################
//################################ Plugin-214: RC522 SPI RFID reader ####################################
//#######################################################################################################
// Changelog:
// 2021-03-13, tonhuisman: Disabled tag removal detection, as it seems impossible to achieve with the MFRC522.
// Other takers to try and solve this challenge are welcome.
// If this feature is desired, use a PN532 RFID detector, that does support removal detection properly and easily.
// Set TimerOption to false as nothing is processed during PLUGIN_READ stage.
// 2021-02-10, tonhuisman: Add tag removal detection, can be combined with time-out
// 2021-02-07, tonhuisman: Rework to adhere to current plugin requirements, make pin settings user-selectable
// Add options for tag removal time-out, as implemented before in P008 (Wiegand RFID) and P017 (PN532 RFID)
// Implement PluginStruct to enable multiple instances
// 2021-02-07, twinbee77: Adjustments to P129 from PluginPlayground
#define PLUGIN_111
#define PLUGIN_ID_111 111
#define PLUGIN_NAME_111 "RFID - RC522 [TESTING]"
#define PLUGIN_VALUENAME1_111 "Tag"
#include "src/PluginStructs/P111_data_struct.h"
#define P111_NO_KEY 0xFFFFFFFF
// #define P111_USE_REMOVAL // Enable (real) Tag Removal detection options
boolean Plugin_111(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_111;
Device[deviceCount].Type = DEVICE_TYPE_SPI2;
Device[deviceCount].VType = Sensor_VType::SENSOR_TYPE_LONG;
Device[deviceCount].Ports = 0;
Device[deviceCount].PullUpOption = false;
Device[deviceCount].InverseLogicOption = false;
Device[deviceCount].ValueCount = 1;
Device[deviceCount].SendDataOption = true;
Device[deviceCount].TimerOption = false;
Device[deviceCount].GlobalSyncOption = true;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_111);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_111));
break;
}
case PLUGIN_GET_DEVICEGPIONAMES: //define 'GPIO 1st' name in webserver
{
event->String1 = formatGpioName_output(F("CS PIN")); // PIN(0)
event->String2 = formatGpioName_output(F("RST PIN (optional)")); // PIN(1)
break;
}
case PLUGIN_SET_DEFAULTS:
{
PCONFIG_LONG(1) = 500; // Default 500 msec reset delay
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormSubHeader(F("Options"));
{
#ifdef P111_USE_REMOVAL
#define P111_removaltypes 3
#else // P111_USE_REMOVAL
#define P111_removaltypes 2
#endif // P111_USE_REMOVAL
String removaltype[P111_removaltypes] = {
F("None")
,F("Autoremove after Time-out")
#ifdef P111_USE_REMOVAL
,F("Tag removal detection + Time-out")
#endif // P111_USE_REMOVAL
};
int removalopts[P111_removaltypes] = { 1, 0
#ifdef P111_USE_REMOVAL
, 2
#endif // P111_USE_REMOVAL
}; // A-typical order for logical order and backward compatibility
addFormSelector(F("Tag removal mode"), F("p111_autotagremoval"), P111_removaltypes, removaltype, removalopts, PCONFIG(0));
}
addFormNumericBox(F("Tag removal Time-out"),F("p111_removaltimeout"), PCONFIG_LONG(1), 0, 60000); // 0 to 60 seconds
addUnit(F("mSec. (0..60000)"));
addFormNumericBox(F("Value to set on Tag removal"),F("p111_removalvalue"), PCONFIG_LONG(0), 0, 2147483647); // Max allowed is int = 0x7FFFFFFF ...
addFormCheckBox(F("Event on Tag removal"), F("p111_sendreset"), PCONFIG(1) == 1);
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
PCONFIG(0) = getFormItemInt(F("p111_autotagremoval"));
PCONFIG(1) = isFormItemChecked(F("p111_sendreset")) ? 1 : 0;
PCONFIG_LONG(0) = getFormItemInt(F("p111_removalvalue"));
PCONFIG_LONG(1) = getFormItemInt(F("p111_removaltimeout"));
success = true;
break;
}
case PLUGIN_INIT:
{
initPluginTaskData(event->TaskIndex, new (std::nothrow) P111_data_struct(PIN(0), PIN(1)));
P111_data_struct *P111_data = static_cast<P111_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr == P111_data) {
return success;
}
P111_data->init();
success = true;
break;
}
case PLUGIN_TIMER_IN:
{
// Reset card id on timeout
if (PCONFIG(0) == 0
#ifdef P111_USE_REMOVAL
|| PCONFIG(0) == 2
#endif // P111_USE_REMOVAL
) {
UserVar.setSensorTypeLong(event->TaskIndex, PCONFIG_LONG(0));
addLog(LOG_LEVEL_INFO, F("MFRC522: Removed Tag"));
if (PCONFIG(1) == 1) {
sendData(event);
}
success = true;
}
break;
}
case PLUGIN_TEN_PER_SECOND:
{
P111_data_struct *P111_data = static_cast<P111_data_struct *>(getPluginTaskData(event->TaskIndex));
if (nullptr == P111_data) {
return success;
}
P111_data->counter++; // This variable replaces a static variable in the original implementation
if (P111_data->counter == 3) { // Only every 3rd 0.1 second we do a read
P111_data->counter = 0;
unsigned long key = P111_NO_KEY;
bool removedTag = false;
byte error = P111_data->readCardStatus(&key, &removedTag);
if (error == 0) {
unsigned long old_key = UserVar.getSensorTypeLong(event->TaskIndex);
bool new_key = false;
#ifdef P111_USE_REMOVAL
if (removedTag && PCONFIG(0) == 2) { // removal detected and enabled
key = PCONFIG_LONG(0);
}
#endif // P111_USE_REMOVAL
if (old_key != key && key != P111_NO_KEY) {
UserVar.setSensorTypeLong(event->TaskIndex, key);
new_key = true;
}
if (loglevelActiveFor(LOG_LEVEL_INFO) && key != P111_NO_KEY) {
String log = F("MFRC522: ");
if (new_key) {
log += F("New Tag: ");
} else {
log += F("Old Tag: ");
}
log += key;
if (!removedTag) {
log += F(" card: ");
log += P111_data->getCardName();
}
addLog(LOG_LEVEL_INFO, log);
}
if (new_key && !removedTag) { // Removal event sent from PLUGIN_TIMER_IN, if any
sendData(event);
}
Scheduler.setPluginTaskTimer(PCONFIG_LONG(1), event->TaskIndex, event->Par1);
}
}
break;
}
}
return success;
}
#endif // USES_P111
+1
View File
@@ -926,6 +926,7 @@ To create/register a plugin, you have to :
#define USES_P106 // BME680
#define USES_P107 // SI1145 UV index
//#define USES_P108 // DDS238-x ZN MODBUS energy meter (was P224 in the Playground)
// #define USES_P111 // RC522 RFID reader
#endif
+155
View File
@@ -0,0 +1,155 @@
#include "../PluginStructs/P111_data_struct.h"
#ifdef USES_P111
#include "../PluginStructs/P111_data_struct.h"
// Needed also here for PlatformIO's library finder as the .h file
// is in a directory which is excluded in the src_filter
#include <MFRC522.h>
P111_data_struct::P111_data_struct(byte csPin, byte rstPin) : mfrc522(nullptr), _csPin(csPin), _rstPin(rstPin)
{}
void P111_data_struct::init() {
if (mfrc522 == nullptr){
mfrc522 = new MFRC522 (_csPin, _rstPin); // Instantiate a MFRC522
mfrc522->PCD_Init(); // Initialize MFRC522 reader
}
}
/**
* read status and tag
*/
byte P111_data_struct::readCardStatus(unsigned long *key, bool *removedTag) {
byte error = 0;
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
uint8_t uidLength;
error = readPassiveTargetID(uid, &uidLength);
switch(error) {
case 1: // Read error
{
errorCount++;
removedState = false;
String log = F("MFRC522: Read error: ");
log += errorCount;
addLog(LOG_LEVEL_ERROR, log);
break;
}
case 2: // No tag found
if (!removedState) {
removedState = true;
*removedTag = true;
error = 0; // pass through that removal just once
}
errorCount = 0;
break;
default: // Read a tag correctly
errorCount = 0;
removedState = false; // No longer removed
break;
}
if (errorCount > 2) { // if three consecutive read errors, reset MFRC522
reset(_csPin,_rstPin);
}
unsigned long tmpKey = uid[0];
for (uint8_t i = 1; i < 4; i++) {
tmpKey <<= 8;
tmpKey += uid[i];
}
*key = tmpKey;
return error;
}
/**
* Returns last read card (type) name
*/
String P111_data_struct::getCardName() {
return mfrc522->PICC_GetTypeName(mfrc522->PICC_GetType(mfrc522->uid.sak));
}
/*********************************************************************************************\
* MFRC522 init
\*********************************************************************************************/
bool P111_data_struct::reset(int8_t csPin, int8_t resetPin) {
if (resetPin != -1) {
String log = F("MFRC522: Reset on pin: ");
log += resetPin;
addLog(LOG_LEVEL_INFO, log);
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, LOW);
delay(100);
digitalWrite(resetPin, HIGH);
pinMode(resetPin, INPUT_PULLUP);
delay(10);
}
pinMode(csPin, OUTPUT);
digitalWrite(csPin, LOW);
mfrc522->PCD_Init(csPin, resetPin); // Init MFRC522 module
//If you set Antenna Gain to Max it will increase reading distance
mfrc522->PCD_SetAntennaGain(mfrc522->RxGain_max);
bool result = mfrc522->PCD_PerformSelfTest(); // perform the test
if (result) {
//String log = F("RC522: Found");
// Get the MFRC522 software version
byte v = mfrc522->PCD_ReadRegister(mfrc522->VersionReg);
// When 0x00 or 0xFF is returned, communication probably failed
if ((v == 0x00) || (v == 0xFF)) {
String log=F("MFRC522: Communication failure, is the MFRC522 properly connected?");
addLog(LOG_LEVEL_ERROR,log);
return false;
} else {
String log=F("MFRC522: Software Version: ");
if (v == 0x91)
log+=F(" = v1.0");
else if (v == 0x92)
log+=F(" = v2.0");
else
log+=F(" (unknown),probably a chinese clone?");
addLog(LOG_LEVEL_INFO, log);
}
return true;
}
return false;
}
/*********************************************************************************************\
* RC522 read tag ID
\*********************************************************************************************/
byte P111_data_struct::readPassiveTargetID(uint8_t *uid, uint8_t *uidLength) { //needed ? see above (not PN532)
// Getting ready for Reading PICCs
if ( ! mfrc522->PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue
return 2;
}
addLog(LOG_LEVEL_INFO, F("MFRC522: New Card Detected"));
if ( ! mfrc522->PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
return 1;
}
// There are Mifare PICCs which have 4 byte or 7 byte UID care if you use 7 byte PICC
// I think we should assume every PICC as they have 4 byte UID
// Until we support 7 byte PICCs
addLog(LOG_LEVEL_INFO, F("MFRC522: Scanned PICC's UID"));
for (uint8_t i = 0; i < 4; i++) { //
uid[i] = mfrc522->uid.uidByte[i];
}
*uidLength = 4;
mfrc522->PICC_HaltA(); // Stop reading
return 0;
}
#endif // ifdef USES_P111
+32
View File
@@ -0,0 +1,32 @@
#ifndef PLUGINSTRUCTS_P111_DATA_STRUCT_H
#define PLUGINSTRUCTS_P111_DATA_STRUCT_H
#include "../../_Plugin_Helper.h"
#ifdef USES_P111
#include <MFRC522.h>
struct P111_data_struct : public PluginTaskData_base {
P111_data_struct(byte csPin, byte rstPin);
void init();
byte readCardStatus(unsigned long *key, bool *removedTag);
String getCardName();
MFRC522 *mfrc522;
byte counter = 0;
private:
bool reset(int8_t csPin, int8_t resetPin);
byte readPassiveTargetID(uint8_t *uid, uint8_t *uidLength);
byte _csPin;
byte _rstPin;
byte errorCount = 0;
bool removedState = true; // On startup, there will usually not be a tag nearby
};
#endif // ifdef USES_P111
#endif // ifndef PLUGINSTRUCTS_P111_DATA_STRUCT_H