diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index a490f8e6e..dec628ae1 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index b16ccf37f..d6c73baa9 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 8ad86d173..a9d85ba3c 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index f5f281ca4..b6b9dfa9d 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 7c03e76f4..0a85d6a8b 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index 73ec924c8..4503c4e57 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 09b7ef831..89a863810 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index 64e6aeae3..7e2deacab 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 6a6a21020..a7db58513 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 145b6064c..a5ffca743 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index cef56fb2e..773442714 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index dba0726e4..63a15c5a5 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index f8d037e83..1b0c34b16 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index aeed10329..b969449d2 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index aaa457ec7..b2ad0a1d8 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/sk-SK.h b/sonoff/language/sk-SK.h index e1ecafd63..49430c31e 100644 --- a/sonoff/language/sk-SK.h +++ b/sonoff/language/sk-SK.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index 5a7934d71..61ab33b57 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index 344e65b58..cfad17ca0 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index be8f0530a..ce72f093f 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index fbdc82207..a022f7939 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 008c33a10..06274c41b 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -553,6 +553,8 @@ #define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" #define D_SENSOR_CSE7766_TX "CSE7766 Tx" #define D_SENSOR_CSE7766_RX "CSE7766 Rx" +#define D_SENSOR_PN532_TX "PN532 Tx" +#define D_SENSOR_PN532_RX "PN532 Rx" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index c9c6505d5..c719f3c40 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -326,9 +326,6 @@ // #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) // #define USE_RTC_ADDR 0x68 // Default I2C address 0x68 // #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) -// #define USE_PN532_I2C // Enable PN532 - Near Field Communication (NFC) controller (+1k7 code, 164 bytes of mem) -// #define USE_PN532_DATA_FUNCTION // Enable PN532 DATA Usage using Sensor15 command (+1k6 code, 316 bytes of mem) -// #define USE_PN532_CAUSE_EVENTS // Enable PN532 driver to cause event's on card read in addition to immediate telemetry (+64 bytes code, 48 bytes mem) // #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) // #define USE_DISPLAY // Add I2C Display Support (+2k code) @@ -378,6 +375,9 @@ #define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) #define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer //#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code) +//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) +// #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem) +// #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram) // Power monitoring sensors ----------------------- #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 1e5e1a573..ff2ba6401 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -162,6 +162,8 @@ enum UserSelectablePins { GPIO_MCP39F5_TX, // MCP39F501 Serial interface (Shelly2) GPIO_MCP39F5_RX, // MCP39F501 Serial interface (Shelly2) GPIO_MCP39F5_RST, // MCP39F501 Reset (Shelly2) + GPIO_PN532_RXD, // PN532 NFC Serial Rx + GPIO_PN532_TXD, // PN532 NFC Serial Tx GPIO_SENSOR_END }; // Programmer selectable GPIO functionality offset by user selectable GPIOs @@ -227,6 +229,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_BUTTON "1in|" D_SENSOR_BUTTON "2in|" D_SENSOR_BUTTON "3in|" D_SENSOR_BUTTON "4in|" D_SENSOR_NRG_SEL "|" D_SENSOR_NRG_SEL "i|" D_SENSOR_NRG_CF1 "|" D_SENSOR_HLW_CF "|" D_SENSOR_HJL_CF "|" D_SENSOR_MCP39F5_TX "|" D_SENSOR_MCP39F5_RX "|" D_SENSOR_MCP39F5_RST + D_SENSOR_PN532_TX "|" D_SENSOR_PN532_RX ; /********************************************************************************************/ @@ -546,6 +549,10 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_MAX31855CLK, // MAX31855 Serial interface GPIO_MAX31855DO, // MAX31855 Serial interface #endif +#ifdef USE_PN532_HSU + GPIO_PN532_RXD, // PN532 HSU Rx + GPIO_PN532_TXD, // PN532 HSU Tx +#endif }; const uint8_t kModuleNiceList[MAXMODULE] PROGMEM = { diff --git a/sonoff/xsns_40_pn532.ino b/sonoff/xsns_40_pn532.ino new file mode 100644 index 000000000..af00720b2 --- /dev/null +++ b/sonoff/xsns_40_pn532.ino @@ -0,0 +1,615 @@ +/* + xsns_40_pn532.ino - Support for PN532 (HSU) NFC Tag Reader + + Copyright (C) 2019 Andre Thomas and Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_PN532_HSU + +#define XSNS_40 40 + +#include + +TasmotaSerial *PN532_Serial; + +#define PN532_INVALID_ACK -1 +#define PN532_TIMEOUT -2 +#define PN532_INVALID_FRAME -3 +#define PN532_NO_SPACE -4 + +#define PN532_PREAMBLE 0x00 +#define PN532_STARTCODE1 0x00 +#define PN532_STARTCODE2 0xFF +#define PN532_POSTAMBLE 0x00 + +#define PN532_HOSTTOPN532 0xD4 +#define PN532_PN532TOHOST 0xD5 + +#define PN532_ACK_WAIT_TIME 0x0A + +#define PN532_COMMAND_GETFIRMWAREVERSION 0x02 +#define PN532_COMMAND_SAMCONFIGURATION 0x14 +#define PN532_COMMAND_RFCONFIGURATION 0x32 +#define PN532_COMMAND_INDATAEXCHANGE 0x40 +#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A + +#define PN532_MIFARE_ISO14443A 0x00 +#define MIFARE_CMD_READ 0x30 +#define MIFARE_CMD_AUTH_A 0x60 +#define MIFARE_CMD_AUTH_B 0x61 +#define MIFARE_CMD_WRITE 0xA0 + +uint8_t pn532_model = 0; // Used to maintain detection flag +uint8_t pn532_command = 0; // Used to carry command code between functions +uint8_t pn532_scantimer = 0; // Used to prevent multiple successful reads within 2 second window + +uint8_t pn532_packetbuffer[64]; // Global buffer used to store packet + +#ifdef USE_PN532_DATA_FUNCTION +uint8_t pn532_function = 0; +uint8_t pn532_newdata[16]; +uint8_t pn532_newdata_len = 0; +#endif // USE_PN532_DATA_FUNCTION + +void PN532_Init(void) +{ + if ((pin[GPIO_PN532_RXD] < 99) && (pin[GPIO_PN532_TXD] < 99)) { + PN532_Serial = new TasmotaSerial(pin[GPIO_PN532_RXD], pin[GPIO_PN532_TXD], 1); + if (PN532_Serial->begin(115200)) { + if (PN532_Serial->hardwareSerial()) { ClaimSerial(); } + PN532_wakeup(); + uint32_t ver = PN532_getFirmwareVersion(); + if (ver) { + PN532_setPassiveActivationRetries(0xFF); + PN532_SAMConfig(); + pn532_model = 1; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC Reader detected (V%u.%u)",(ver>>16) & 0xFF, (ver>>8) & 0xFF); + AddLog(LOG_LEVEL_INFO); + } + } + } +} + +int8_t PN532_receive(uint8_t *buf, int len, uint16_t timeout) +{ + int read_bytes = 0; + int ret; + unsigned long start_millis; + while (read_bytes < len) { + start_millis = millis(); + do { + ret = PN532_Serial->read(); + if (ret >= 0) { + break; + } + } while((timeout == 0) || ((millis()- start_millis ) < timeout)); + + if (ret < 0) { + if (read_bytes) { + return read_bytes; + } else { + return PN532_TIMEOUT; + } + } + buf[read_bytes] = (uint8_t)ret; + read_bytes++; + } + return read_bytes; +} + +int8_t PN532_readAckFrame(void) +{ + const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; + uint8_t ackBuf[sizeof(PN532_ACK)]; + + if (PN532_receive(ackBuf, sizeof(PN532_ACK), PN532_ACK_WAIT_TIME) <= 0) { + return PN532_TIMEOUT; + } + + if (memcmp(&ackBuf, &PN532_ACK, sizeof(PN532_ACK))) { + return PN532_INVALID_ACK; + } + return 0; +} + +int8_t PN532_writeCommand(const uint8_t *header, uint8_t hlen, const uint8_t *body = 0, uint8_t blen = 0) +{ + // Clear the serial buffer just in case + while(PN532_Serial->available()) { PN532_Serial->read(); } + + pn532_command = header[0]; + PN532_Serial->write((uint8_t)PN532_PREAMBLE); + PN532_Serial->write((uint8_t)PN532_STARTCODE1); + PN532_Serial->write(PN532_STARTCODE2); + + uint8_t length = hlen + blen + 1; // length of data field: TFI + DATA + PN532_Serial->write(length); + PN532_Serial->write(~length + 1); // checksum of length + + PN532_Serial->write(PN532_HOSTTOPN532); + uint8_t sum = PN532_HOSTTOPN532; // sum of TFI + DATA + + PN532_Serial->write(header, hlen); + for (uint8_t i = 0; i < hlen; i++) { + sum += header[i]; + } + + PN532_Serial->write(body, blen); + for (uint8_t i = 0; i < blen; i++) { + sum += body[i]; + } + + uint8_t checksum = ~sum + 1; // checksum of TFI + DATA + PN532_Serial->write(checksum); + PN532_Serial->write((uint8_t)PN532_POSTAMBLE); + + return PN532_readAckFrame(); +} + +int16_t PN532_readResponse(uint8_t buf[], uint8_t len, uint16_t timeout = 50) +{ + uint8_t tmp[3]; + + // Read preamble and start code + if (PN532_receive(tmp, 3, timeout)<=0) { + return PN532_TIMEOUT; + } + if (0 != tmp[0] || 0!= tmp[1] || 0xFF != tmp[2]) { + return PN532_INVALID_FRAME; + } + + // Get length of data to be received + uint8_t length[2]; + if (PN532_receive(length, 2, timeout) <= 0) { + return PN532_TIMEOUT; + } + // Validate that frame is valid + if (0 != (uint8_t)(length[0] + length[1])) { + return PN532_INVALID_FRAME; + } + length[0] -= 2; + if (length[0] > len) { // If this happens, then pn532_packetbuffer is not large enough + return PN532_NO_SPACE; + } + + // Get the command byte + uint8_t cmd = pn532_command + 1; + if (PN532_receive(tmp, 2, timeout) <= 0) { // Time out while receiving + return PN532_TIMEOUT; + } + if (PN532_PN532TOHOST != tmp[0] || cmd != tmp[1]) { // Invalid frame received + return PN532_INVALID_FRAME; + } + + if (PN532_receive(buf, length[0], timeout) != length[0]) { // Timed out + return PN532_TIMEOUT; + } + + uint8_t sum = PN532_PN532TOHOST + cmd; + for (uint8_t i=0; i status) { + return 0; + } + + response = pn532_packetbuffer[0]; + response <<= 8; + response |= pn532_packetbuffer[1]; + response <<= 8; + response |= pn532_packetbuffer[2]; + response <<= 8; + response |= pn532_packetbuffer[3]; + + return response; +} + +void PN532_wakeup(void) +{ + uint8_t wakeup[5] = {0x55, 0x55, 0, 0, 0 }; + PN532_Serial->write(wakeup,sizeof(wakeup)); + + // Flush the serial buffer just in case there's garbage in there + while(PN532_Serial->available()) { PN532_Serial->read(); } +} + +bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength, uint16_t timeout = 50) +{ + pn532_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; + pn532_packetbuffer[1] = 1; // max 1 cards at once (we can set this to 2 later) + pn532_packetbuffer[2] = cardbaudrate; + if (PN532_writeCommand(pn532_packetbuffer, 3)) { + return 0x0; // command failed + } + // read data packet + if (PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer), timeout) < 0) { + return 0x0; + } + + /* Check some basic stuff + b0 Tags Found + b1 Tag Number (only one used in this example) + b2..3 SENS_RES + b4 SEL_RES + b5 NFCID Length + b6..NFCIDLen NFCID + */ + + if (pn532_packetbuffer[0] != 1) { + return 0; + } + + uint16_t sens_res = pn532_packetbuffer[2]; + sens_res <<= 8; + sens_res |= pn532_packetbuffer[3]; + + /* Card appears to be Mifare Classic */ + *uidLength = pn532_packetbuffer[5]; + + for (uint8_t i = 0; i < pn532_packetbuffer[5]; i++) { + uid[i] = pn532_packetbuffer[6 + i]; + } + + return 1; +} + +bool PN532_setPassiveActivationRetries(uint8_t maxRetries) +{ + pn532_packetbuffer[0] = PN532_COMMAND_RFCONFIGURATION; + pn532_packetbuffer[1] = 5; // Config item 5 (MaxRetries) + pn532_packetbuffer[2] = 0xFF; // MxRtyATR (default = 0xFF) + pn532_packetbuffer[3] = 0x01; // MxRtyPSL (default = 0x01) + pn532_packetbuffer[4] = maxRetries; + if (PN532_writeCommand(pn532_packetbuffer, 5)) { + return 0; // no ACK + } + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +bool PN532_SAMConfig(void) +{ + pn532_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; + pn532_packetbuffer[1] = 0x01; // normal mode + pn532_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second + pn532_packetbuffer[3] = 0x00; // we don't need the external IRQ pin + if (PN532_writeCommand(pn532_packetbuffer, 4)) { + return false; + } + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +#ifdef USE_PN532_DATA_FUNCTION + +uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) +{ + uint8_t i; + uint8_t _key[6]; + uint8_t _uid[7]; + uint8_t _uidLen; + + // Hang on to the key and uid data + memcpy(&_key, keyData, 6); + memcpy(&_uid, uid, uidLen); + _uidLen = uidLen; + + // Prepare the authentication command // + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ + pn532_packetbuffer[1] = 1; /* Max card numbers */ + pn532_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; + pn532_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ + memcpy(&pn532_packetbuffer[4], &_key, 6); + for (i = 0; i < _uidLen; i++) { + pn532_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */ + } + + if (PN532_writeCommand(pn532_packetbuffer, 10 + _uidLen)) { return 0; } + + // Read the response packet + PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); + + // Check if the response is valid and we are authenticated??? + // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 + // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good + if (pn532_packetbuffer[0] != 0x00) { + // Authentification failed + return 0; + } + + return 1; +} + +uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) +{ + /* Prepare the command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + + /* Send the command */ + if (PN532_writeCommand(pn532_packetbuffer, 4)) { + return 0; + } + + /* Read the response packet */ + PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer)); + + /* If byte 8 isn't 0x00 we probably have an error */ + if (pn532_packetbuffer[0] != 0x00) { + return 0; + } + + /* Copy the 16 data bytes to the output buffer */ + /* Block content starts at byte 9 of a valid response */ + memcpy (data, &pn532_packetbuffer[1], 16); + + return 1; +} + +uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) +{ + /* Prepare the first command */ + pn532_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; + pn532_packetbuffer[1] = 1; /* Card number */ + pn532_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ + pn532_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ + memcpy(&pn532_packetbuffer[4], data, 16); /* Data Payload */ + + /* Send the command */ + if (PN532_writeCommand(pn532_packetbuffer, 20)) { + return 0; + } + + /* Read the response packet */ + return (0 < PN532_readResponse(pn532_packetbuffer, sizeof(pn532_packetbuffer))); +} + +#endif // USE_PN532_DATA_FUNCTION + +void PN532_ScanForTag(void) +{ + if (!pn532_model) { return; } + uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; + uint8_t uid_len = 0; + uint8_t card_data[16]; + bool erase_success = false; + bool set_success = false; + if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) { + char uids[15]; + +#ifdef USE_PN532_DATA_FUNCTION + char card_datas[34]; +#endif // USE_PN532_DATA_FUNCTION + + sprintf(uids,""); + for (uint8_t i = 0;i < uid_len;i++) { + sprintf(uids,"%s%02X",uids,uid[i]); + } + +#ifdef USE_PN532_DATA_FUNCTION + if (uid_len == 4) { // Lets try to read block 1 of the mifare classic card for more information + uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; + if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { + if (mifareclassic_ReadDataBlock(1, card_data)) { +#ifdef USE_PN532_DATA_RAW + memcpy(&card_datas,&card_data,sizeof(card_data)); +#else + for (uint8_t i = 0;i < sizeof(card_data);i++) { + if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { + card_datas[i] = char(card_data[i]); + } else { + card_datas[i] = '\0'; + } + } +#endif // USE_PN532_DATA_RAW + } + if (pn532_function == 1) { // erase block 1 of card + for (uint8_t i = 0;i<16;i++) { + card_data[i] = 0x00; + } + if (mifareclassic_WriteDataBlock(1, card_data)) { + erase_success = true; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Erase success"); + AddLog(LOG_LEVEL_INFO); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } + } + if (pn532_function == 2) { +#ifdef USE_PN532_DATA_RAW + memcpy(&card_data,&pn532_newdata,sizeof(card_data)); + if (mifareclassic_WriteDataBlock(1, card_data)) { + set_success = true; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Data write successful"); + AddLog(LOG_LEVEL_INFO); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } +#else + bool IsAlphaNumeric = true; + for (uint8_t i = 0;i < pn532_newdata_len;i++) { + if ((!isalpha(pn532_newdata[i])) && (!isdigit(pn532_newdata[i]))) { + IsAlphaNumeric = false; + } + } + if (IsAlphaNumeric) { + memcpy(&card_data,&pn532_newdata,pn532_newdata_len); + card_data[pn532_newdata_len] = '\0'; // Enforce null termination + if (mifareclassic_WriteDataBlock(1, card_data)) { + set_success = true; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Data write successful"); + AddLog(LOG_LEVEL_INFO); + memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string + } + } else { + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Data must be alphanumeric"); + AddLog(LOG_LEVEL_INFO); + } +#endif // USE_PN532_DATA_RAW + } + } else { + sprintf(card_datas,"AUTHFAIL"); + } + } + switch (pn532_function) { + case 0x01: + if (!erase_success) { + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Erase fail - exiting erase mode"); + AddLog(LOG_LEVEL_INFO); + } + break; + case 0x02: + if (!set_success) { + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Write failed - exiting set mode"); + AddLog(LOG_LEVEL_INFO); + } + default: + break; + } + pn532_function = 0; +#endif // USE_PN532_DATA_FUNCTION + + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + +#ifdef USE_PN532_DATA_FUNCTION + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), mqtt_data, uids, card_datas); +#else + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\"}}"), mqtt_data, uids); +#endif // USE_PN532_DATA_FUNCTION + + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); + +#ifdef USE_PN532_CAUSE_EVENTS + + char command[71]; +#ifdef USE_PN532_DATA_FUNCTION + sprintf(command,"backlog event PN532_UID=%s;event PN532_DATA=%s",uids,card_datas); +#else + sprintf(command,"event PN532_UID=%s",uids); +#endif // USE_PN532_DATA_FUNCTION + ExecuteCommand(command, SRC_RULE); +#endif // USE_PN532_CAUSE_EVENTS + + pn532_scantimer = 7; // Ignore tags found for two seconds + } +} + +#ifdef USE_PN532_DATA_FUNCTION + +bool PN532_Command(void) +{ + bool serviced = true; + uint8_t paramcount = 0; + if (XdrvMailbox.data_len > 0) { + paramcount=1; + } else { + serviced = false; + return serviced; + } + char sub_string[XdrvMailbox.data_len]; + char sub_string_tmp[XdrvMailbox.data_len]; + for (uint8_t ca=0;ca 1) { + if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { + serviced = false; + return serviced; + } + sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2)); + pn532_newdata_len = strlen(sub_string_tmp); + if (pn532_newdata_len > 15) { pn532_newdata_len = 15; } + memcpy(&pn532_newdata,&sub_string_tmp,pn532_newdata_len); + pn532_newdata[pn532_newdata_len] = 0x00; // Null terminate the string + pn532_function = 2; + snprintf_P(log_data, sizeof(log_data),"NFC: PN532 NFC - Next scanned tag data block 1 will be set to '%s'",pn532_newdata); + AddLog(LOG_LEVEL_INFO); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"S\"\"}}"), mqtt_data); + return serviced; + } + } +} + +#endif // USE_PN532_DATA_FUNCTION + +bool Xsns40(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_INIT: + PN532_Init(); + result = true; + break; + case FUNC_EVERY_50_MSECOND: + break; + case FUNC_EVERY_100_MSECOND: + break; + case FUNC_EVERY_250_MSECOND: + if (pn532_scantimer > 0) { + pn532_scantimer--; + } else { + PN532_ScanForTag(); + } + break; + case FUNC_EVERY_SECOND: + break; +#ifdef USE_PN532_DATA_FUNCTION + case FUNC_COMMAND: + if (XSNS_40 == XdrvMailbox.index) { + result = PN532_Command(); + } + break; +#endif + } + return result; +} + +#endif // USE_PN532_HSU diff --git a/sonoff/xsns_40_pn532_i2c.ino b/sonoff/xsns_40_pn532_i2c.ino deleted file mode 100644 index 640e21c6e..000000000 --- a/sonoff/xsns_40_pn532_i2c.ino +++ /dev/null @@ -1,606 +0,0 @@ -/* - xsns_40_pn532.ino - Support for PN532 (I2C) NFC Tag Reader - - Copyright (C) 2019 Andre Thomas and Theo Arends - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#ifdef USE_I2C -#ifdef USE_PN532_I2C - -/*********************************************************************************************\ - * PN532 - Near Field Communication (NFC) controller - * - * Datasheet at https://www.nxp.com/docs/en/nxp/data-sheets/PN532_C1.pdf - * - * I2C Address: 0x24 -\*********************************************************************************************/ - -#define XSNS_40 40 - -#define PN532_I2C_ADDRESS 0x24 - -#define PN532_COMMAND_GETFIRMWAREVERSION 0x02 -#define PN532_COMMAND_SAMCONFIGURATION 0x14 -#define PN532_COMMAND_INDATAEXCHANGE 0x40 -#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A - -#define MIFARE_CMD_READ 0x30 -#define MIFARE_CMD_AUTH_A 0x60 -#define MIFARE_CMD_AUTH_B 0x61 -#define MIFARE_CMD_WRITE 0xA0 - -#define PN532_PREAMBLE 0x00 -#define PN532_STARTCODE1 0x00 -#define PN532_STARTCODE2 0xFF -#define PN532_POSTAMBLE 0x00 - -#define PN532_HOSTTOPN532 0xD4 -#define PN532_PN532TOHOST 0xD5 - -#define PN532_INVALID_ACK -1 -#define PN532_TIMEOUT -2 -#define PN532_INVALID_FRAME -3 -#define PN532_NO_SPACE -4 - -#define PN532_MIFARE_ISO14443A 0x00 - -uint8_t pn532_i2c_detected = 0; -uint8_t pn532_i2c_packetbuffer[64]; -uint8_t pn532_i2c_scan_defer_report = 0; // If a valid card was found we will not scan for one again in the same two seconds so we set this to 19 if a card was found -uint8_t pn532_i2c_command = 0; - -uint8_t pn532_i2c_disable = 0; - -#ifdef USE_PN532_DATA_FUNCTION -uint8_t pn532_i2c_function = 0; -uint8_t pn532_i2c_newdata[16]; -uint8_t pn532_i2c_newdata_len = 0; -#endif // USE_PN532_DATA_FUNCTION - -const uint8_t PROGMEM pn532_global_timeout = 10; - -int16_t PN532_getResponseLength(uint8_t buf[], uint8_t len) { - const uint8_t PN532_NACK[] = {0, 0, 0xFF, 0xFF, 0, 0}; - uint8_t time = 0; - do { - if (Wire.requestFrom(PN532_I2C_ADDRESS, 6)) { - if (Wire.read() & 1) { // check first byte --- status - break; // PN532 is ready - } - } - delay(1); - time++; - if (time > pn532_global_timeout) { - return -1; - } - } while (1); - - if ((0x00 != Wire.read()) || (0x00 != Wire.read()) || (0xFF != Wire.read())) { // PREAMBLE || STARTCODE1 || STARTCODE2 - return PN532_INVALID_FRAME; - } - - uint8_t length = Wire.read(); - - // request for last respond msg again - Wire.beginTransmission(PN532_I2C_ADDRESS); - for (uint16_t i = 0;i < sizeof(PN532_NACK); ++i) { - Wire.write(PN532_NACK[i]); - } - Wire.endTransmission(); - return length; -} - - -int16_t PN532_readResponse(uint8_t buf[], uint8_t len) -{ - uint8_t time = 0; - uint8_t length; - - length = PN532_getResponseLength(buf, len); - - // [RDY] 00 00 FF LEN LCS (TFI PD0 ... PDn) DCS 00 - - do { - if (Wire.requestFrom(PN532_I2C_ADDRESS, 6 + length + 2)) { - if (Wire.read() & 1) { // check first byte --- status - break; // PN532 is ready - } - } - delay(1); - time++; - if (time > pn532_global_timeout) { - return -1; - } - } while (1); - - if ((0x00 != Wire.read()) || (0x00 != Wire.read()) || (0xFF != Wire.read())) { // PREAMBLE || STARTCODE1 || STARTCODE2 - return PN532_INVALID_FRAME; - } - - length = Wire.read(); - - if (0 != (uint8_t)(length + Wire.read())) { // checksum of length - return PN532_INVALID_FRAME; - } - - uint8_t cmd = pn532_i2c_command + 1; // response command - if ((PN532_PN532TOHOST != Wire.read()) || ((cmd) != Wire.read())) { - return PN532_INVALID_FRAME; - } - length -= 2; - if (length > len) { - return PN532_NO_SPACE; // not enough space - } - uint8_t sum = PN532_PN532TOHOST + cmd; - for (uint8_t i = 0; i < length; i++) { - buf[i] = Wire.read(); - sum += buf[i]; - } - uint8_t checksum = Wire.read(); - if (0 != (uint8_t)(sum + checksum)) { - return PN532_INVALID_FRAME; - } - Wire.read(); // POSTAMBLE - return length; -} - - -int8_t PN532_readAckFrame(void) -{ - const uint8_t PN532_ACK[] = {0, 0, 0xFF, 0, 0xFF, 0}; - uint8_t ackBuf[sizeof(PN532_ACK)]; - - uint8_t time = 0; - - do { - if (Wire.requestFrom(PN532_I2C_ADDRESS, sizeof(PN532_ACK) + 1)) { - if (Wire.read() & 1) { // check first byte --- status - break; // PN532 is ready - } - } - delay(1); - time++; - if (time > pn532_global_timeout) { // We time out after 10ms - return PN532_TIMEOUT; - } - } while (1); - - for (uint8_t i = 0; i < sizeof(PN532_ACK); i++) { - ackBuf[i] = Wire.read(); - } - - if (memcmp(ackBuf, PN532_ACK, sizeof(PN532_ACK))) { - return PN532_INVALID_ACK; - } - - return 0; -} - -int8_t PN532_writeCommand(const uint8_t *header, uint8_t hlen) -{ - pn532_i2c_command = header[0]; - Wire.beginTransmission(PN532_I2C_ADDRESS); - Wire.write(PN532_PREAMBLE); - Wire.write(PN532_STARTCODE1); - Wire.write(PN532_STARTCODE2); - uint8_t length = hlen + 1; // TFI + DATA - Wire.write(length); - Wire.write(~length + 1); // checksum of length - Wire.write(PN532_HOSTTOPN532); - uint8_t sum = PN532_HOSTTOPN532; // Sum of TFI + DATA - for (uint8_t i = 0; i < hlen; i++) { - if (Wire.write(header[i])) { - sum += header[i]; - } else { - return PN532_INVALID_FRAME; - } - } - uint8_t checksum = ~sum + 1; // Checksum of TFI + DATA - Wire.write(checksum); - Wire.write(PN532_POSTAMBLE); - Wire.endTransmission(); - return PN532_readAckFrame(); -} - -uint32_t PN532_getFirmwareVersion(void) -{ - uint32_t response; - pn532_i2c_packetbuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; - if (PN532_writeCommand(pn532_i2c_packetbuffer, 1)) { - return 0; - } - int16_t status = PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)); - if (0 > status) { - return 0; - } - response = pn532_i2c_packetbuffer[0]; - response <<= 8; - response |= pn532_i2c_packetbuffer[1]; - response <<= 8; - response |= pn532_i2c_packetbuffer[2]; - response <<= 8; - response |= pn532_i2c_packetbuffer[3]; - return response; -} - -bool PN532_SAMConfig(void) -{ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION; - pn532_i2c_packetbuffer[1] = 0x01; // normal mode; - pn532_i2c_packetbuffer[2] = 0x01; // timeout 50ms * 1 = 50ms - pn532_i2c_packetbuffer[3] = 0x00; // Disable IRQ pin - - if (PN532_writeCommand(pn532_i2c_packetbuffer, 4)) - return false; - - return (0 < PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer))); -} - -void PN532_Detect(void) -{ - if ((pn532_i2c_detected) || (pn532_i2c_disable)) { return; } - - Wire.setClockStretchLimit(1000); // Enable 1ms clock stretch as per datasheet Table 12.25 (Timing for the I2C interface) - - uint32_t ver = PN532_getFirmwareVersion(); - if (ver) { - pn532_i2c_detected = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "PN532 NFC Reader (V%u.%u)", PN532_I2C_ADDRESS); - snprintf_P(log_data, sizeof(log_data), log_data, (ver>>16) & 0xFF, (ver>>8) & 0xFF); - AddLog(LOG_LEVEL_DEBUG); - PN532_SAMConfig(); - } -} - -bool PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *uidLength) -{ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; - pn532_i2c_packetbuffer[1] = 1; - pn532_i2c_packetbuffer[2] = cardbaudrate; - - if (PN532_writeCommand(pn532_i2c_packetbuffer, 3)) { - return false; // command failed - } - - if (PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)) < 0) { // No data packet so no tag was found - Wire.beginTransmission(PN532_I2C_ADDRESS); - Wire.endTransmission(); - return false; - } - - if (pn532_i2c_packetbuffer[0] != 1) { return false; } // Not a valid tag - - *uidLength = pn532_i2c_packetbuffer[5]; - for (uint8_t i = 0;i < pn532_i2c_packetbuffer[5]; i++) { - uid[i] = pn532_i2c_packetbuffer[6 + i]; - } - return true; -} - -#ifdef USE_PN532_DATA_FUNCTION - -uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData) -{ - uint8_t i; - uint8_t _key[6]; - uint8_t _uid[7]; - uint8_t _uidLen; - - // Hang on to the key and uid data - memcpy (_key, keyData, 6); - memcpy (_uid, uid, uidLen); - _uidLen = uidLen; - - // Prepare the authentication command // - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */ - pn532_i2c_packetbuffer[1] = 1; /* Max card numbers */ - pn532_i2c_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A; - pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */ - memcpy (&pn532_i2c_packetbuffer[4], _key, 6); - for (i = 0; i < _uidLen; i++) { - pn532_i2c_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */ - } - - if (PN532_writeCommand(pn532_i2c_packetbuffer, 10 + _uidLen)) - return 0; - - // Read the response packet - PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)); - - // Check if the response is valid and we are authenticated??? - // for an auth success it should be bytes 5-7: 0xD5 0x41 0x00 - // Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good - if (pn532_i2c_packetbuffer[0] != 0x00) { - // Authentification failed - return 0; - } - - return 1; -} - -uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data) -{ - /* Prepare the command */ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_i2c_packetbuffer[1] = 1; /* Card number */ - pn532_i2c_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */ - pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ - - /* Send the command */ - if (PN532_writeCommand(pn532_i2c_packetbuffer, 4)) { - return 0; - } - - /* Read the response packet */ - PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)); - - /* If byte 8 isn't 0x00 we probably have an error */ - if (pn532_i2c_packetbuffer[0] != 0x00) { - return 0; - } - - /* Copy the 16 data bytes to the output buffer */ - /* Block content starts at byte 9 of a valid response */ - memcpy (data, &pn532_i2c_packetbuffer[1], 16); - - return 1; -} - -uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data) -{ - /* Prepare the first command */ - pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; - pn532_i2c_packetbuffer[1] = 1; /* Card number */ - pn532_i2c_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */ - pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */ - memcpy(&pn532_i2c_packetbuffer[4], data, 16); /* Data Payload */ - - /* Send the command */ - if (PN532_writeCommand(pn532_i2c_packetbuffer, 20)) { - return 0; - } - - /* Read the response packet */ - return (0 < PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer))); -} - -#endif // USE_PN532_DATA_FUNCTION - -void PN532_ScanForTag(void) -{ - if (pn532_i2c_disable) { return; } - uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; - uint8_t uid_len = 0; - uint8_t card_data[16]; - bool erase_success = false; - bool set_success = false; - if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) { - if (pn532_i2c_scan_defer_report > 0) { - pn532_i2c_scan_defer_report--; - } else { - char uids[15]; - -#ifdef USE_PN532_DATA_FUNCTION - char card_datas[34]; -#endif // USE_PN532_DATA_FUNCTION - - sprintf(uids,""); - for (uint8_t i = 0;i < uid_len;i++) { - sprintf(uids,"%s%02X",uids,uid[i]); - } - -#ifdef USE_PN532_DATA_FUNCTION - if (uid_len == 4) { // Lets try to read block 0 of the mifare classic card for more information - uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) { - if (mifareclassic_ReadDataBlock(1, card_data)) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_datas,&card_data,sizeof(card_data)); -#else - for (uint8_t i = 0;i < sizeof(card_data);i++) { - if ((isalpha(card_data[i])) || ((isdigit(card_data[i])))) { - card_datas[i] = char(card_data[i]); - } else { - card_datas[i] = '\0'; - } - } -#endif // USE_PN532_DATA_RAW - } - if (pn532_i2c_function == 1) { // erase block 1 of card - for (uint8_t i = 0;i<16;i++) { - card_data[i] = 0x00; - } - if (mifareclassic_WriteDataBlock(1, card_data)) { - erase_success = true; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Erase success"); - AddLog(LOG_LEVEL_INFO); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } - } - if (pn532_i2c_function == 2) { -#ifdef USE_PN532_DATA_RAW - memcpy(&card_data,&pn532_i2c_newdata,sizeof(card_data)); - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data write successful"); - AddLog(LOG_LEVEL_INFO); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } -#else - bool IsAlphaNumeric = true; - for (uint8_t i = 0;i < pn532_i2c_newdata_len;i++) { - if ((!isalpha(pn532_i2c_newdata[i])) && (!isdigit(pn532_i2c_newdata[i]))) { - IsAlphaNumeric = false; - } - } - if (IsAlphaNumeric) { - memcpy(&card_data,&pn532_i2c_newdata,pn532_i2c_newdata_len); - card_data[pn532_i2c_newdata_len] = '\0'; // Enforce null termination - if (mifareclassic_WriteDataBlock(1, card_data)) { - set_success = true; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data write successful"); - AddLog(LOG_LEVEL_INFO); - memcpy(&card_datas,&card_data,sizeof(card_data)); // Cast block 1 to a string - } - } else { - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data must be alphanumeric"); - AddLog(LOG_LEVEL_INFO); - } -#endif // USE_PN532_DATA_RAW - } - } else { - sprintf(card_datas,"AUTHFAIL"); - } - } - switch (pn532_i2c_function) { - case 0x01: - if (!erase_success) { - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Erase fail - exiting erase mode"); - AddLog(LOG_LEVEL_INFO); - } - break; - case 0x02: - if (!set_success) { - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Write failed - exiting set mode"); - AddLog(LOG_LEVEL_INFO); - } - default: - break; - } - pn532_i2c_function = 0; -#endif // USE_PN532_DATA_FUNCTION - - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); - -#ifdef USE_PN532_DATA_FUNCTION - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), mqtt_data, uids, card_datas); -#else - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\"}}"), mqtt_data, uids); -#endif // USE_PN532_DATA_FUNCTION - - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); - -#ifdef USE_PN532_CAUSE_EVENTS - - char command[71]; -#ifdef USE_PN532_DATA_FUNCTION - sprintf(command,"backlog event PN532_UID=%s;event PN532_DATA=%s",uids,card_datas); -#else - sprintf(command,"event PN532_UID=%s",uids); -#endif // USE_PN532_DATA_FUNCTION - ExecuteCommand(command, SRC_RULE); -#endif // USE_PN532_CAUSE_EVENTS - - pn532_i2c_scan_defer_report = 7; // Ignore tags found for two seconds - } - } else { - if (pn532_i2c_scan_defer_report > 0) { pn532_i2c_scan_defer_report--; } - } -} - -#ifdef USE_PN532_DATA_FUNCTION - -bool PN532_Command(void) -{ - bool serviced = true; - uint8_t paramcount = 0; - if (XdrvMailbox.data_len > 0) { - paramcount=1; - } else { - serviced = false; - return serviced; - } - char sub_string[XdrvMailbox.data_len]; - char sub_string_tmp[XdrvMailbox.data_len]; - for (uint8_t ca=0;ca 1) { - if (XdrvMailbox.data[XdrvMailbox.data_len-1] == ',') { - serviced = false; - return serviced; - } - sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2)); - pn532_i2c_newdata_len = strlen(sub_string_tmp); - if (pn532_i2c_newdata_len > 15) { pn532_i2c_newdata_len = 15; } - memcpy(&pn532_i2c_newdata,&sub_string_tmp,pn532_i2c_newdata_len); - pn532_i2c_newdata[pn532_i2c_newdata_len] = 0x00; // Null terminate the string - pn532_i2c_function = 2; - snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Next scanned tag data block 1 will be set to '%s'",pn532_i2c_newdata); - AddLog(LOG_LEVEL_INFO); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str()); - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"S\"\"}}"), mqtt_data); - return serviced; - } - } -} - -#endif // USE_PN532_DATA_FUNCTION - -/*********************************************************************************************\ - * Interface -\*********************************************************************************************/ - -bool Xsns40(uint8_t function) -{ - bool result = false; - - if (i2c_flg) { - switch (function) { - case FUNC_EVERY_250_MSECOND: - if (pn532_i2c_detected) { - PN532_ScanForTag(); - } - break; - case FUNC_EVERY_SECOND: - PN532_Detect(); - break; - -#ifdef USE_PN532_DATA_FUNCTION - case FUNC_COMMAND: - if (XSNS_40 == XdrvMailbox.index) { - result = PN532_Command(); - } - break; -#endif // USE_PN532_DATA_FUNCTION - - case FUNC_SAVE_BEFORE_RESTART: - if (!pn532_i2c_disable) { - pn532_i2c_disable = 1; - snprintf_P(log_data, sizeof(log_data), S_LOG_I2C_FOUND_AT, "PN532 NFC Reader - Disabling for reboot", PN532_I2C_ADDRESS); - AddLog(LOG_LEVEL_DEBUG); - } - break; - default: - break; - } - } - return result; -} - -#endif // USE_PN532_I2C -#endif // USE_I2C