diff --git a/src/Ntp.cpp b/src/Ntp.cpp index b1dbe4af..ff20ad70 100644 --- a/src/Ntp.cpp +++ b/src/Ntp.cpp @@ -19,120 +19,114 @@ byte NtpClient::NTPpacket[NTP_PACKET_SIZE]; void ICACHE_FLASH_ATTR NtpClient::Ntp(const char *server, int8_t tz, time_t syncSecs) { - TimeServerName = strdup(server); - timezone = tz; - syncInterval = syncSecs; - WiFi.hostByName(TimeServerName, timeServer); - setSyncProvider(getNtpTime); - setSyncInterval(syncInterval); + TimeServerName = strdup(server); + timezone = tz; + syncInterval = syncSecs; + WiFi.hostByName(TimeServerName, timeServer); + setSyncProvider(getNtpTime); + setSyncInterval(syncInterval); } ICACHE_FLASH_ATTR NtpClient::~NtpClient() { - udpListener.close(); + udpListener.close(); } // send an NTP request to the time server at the given address time_t ICACHE_FLASH_ATTR NtpClient::getNtpTime() { - memset(NTPpacket, 0, sizeof(NTPpacket)); - NTPpacket[0] = 0b11100011; - NTPpacket[1] = 0; - NTPpacket[2] = 6; - NTPpacket[3] = 0xEC; - NTPpacket[12] = 49; - NTPpacket[13] = 0x4E; - NTPpacket[14] = 49; - NTPpacket[15] = 52; - if (udpListener.connect(timeServer, 123)) - { - udpListener.onPacket([](AsyncUDPPacket packet) - { - unsigned long highWord = word(packet.data()[40], packet.data()[41]); - unsigned long lowWord = word(packet.data()[42], packet.data()[43]); - time_t UnixUTCtime = (highWord << 16 | lowWord) - 2208988800UL; - setTime(UnixUTCtime); - }); - } - else - { - } - udpListener.write(NTPpacket, sizeof(NTPpacket)); - // ugly - return 0; + memset(NTPpacket, 0, sizeof(NTPpacket)); + NTPpacket[0] = 0b11100011; + NTPpacket[1] = 0; + NTPpacket[2] = 6; + NTPpacket[3] = 0xEC; + NTPpacket[12] = 49; + NTPpacket[13] = 0x4E; + NTPpacket[14] = 49; + NTPpacket[15] = 52; + if (udpListener.connect(timeServer, 123)) { + udpListener.onPacket([](AsyncUDPPacket packet) + { + unsigned long highWord = word(packet.data()[40], packet.data()[41]); + unsigned long lowWord = word(packet.data()[42], packet.data()[43]); + time_t UnixUTCtime = (highWord << 16 | lowWord) - 2208988800UL; + setTime(UnixUTCtime); + }); + } else { + } + udpListener.write(NTPpacket, sizeof(NTPpacket)); + // ugly + return 0; } bool ICACHE_FLASH_ATTR NtpClient::processTime() { - - timeStatus_t ts = timeStatus(); - - switch (ts) - { - case timeNeedsSync: - return false; - break; - case timeSet: - return true; - break; - default: - return false; - } + timeStatus_t ts = timeStatus(); + + switch (ts) { + case timeNeedsSync: + return false; + break; + case timeSet: + return true; + break; + default: + return false; + } } String ICACHE_FLASH_ATTR NtpClient::zeroPaddedIntVal(int val) { - if (val < 10) - return "0" + String(val); - else - return String(val); + if (val < 10) { + return "0" + String(val); + } else { + return String(val); + } } //returns the current date/time as a string in iso8601 format String ICACHE_FLASH_ATTR NtpClient::iso8601DateTime() { - - String hyphen = "-"; - String colon = ":"; - - return String(year()) + hyphen + - zeroPaddedIntVal(month()) + hyphen + - zeroPaddedIntVal(day()) + "T" + - zeroPaddedIntVal(hour()) + colon + - zeroPaddedIntVal(minute()) + colon + - zeroPaddedIntVal(second()) + - (timezone == 0 ? "Z" : String(timezone)); + String hyphen = "-"; + String colon = ":"; + + return String(year()) + hyphen + + zeroPaddedIntVal(month()) + hyphen + + zeroPaddedIntVal(day()) + "T" + + zeroPaddedIntVal(hour()) + colon + + zeroPaddedIntVal(minute()) + colon + + zeroPaddedIntVal(second()) + + (timezone == 0 ? "Z" : String(timezone)); } time_t NtpClient::getUptimeSec() { - _uptimesec = _uptimesec + (millis() - _uptimesec); - return _uptimesec / 1000; + _uptimesec = _uptimesec + (millis() - _uptimesec); + return _uptimesec / 1000; } deviceUptime ICACHE_FLASH_ATTR NtpClient::getDeviceUptime() { + unsigned long currentmillis = millis(); - unsigned long currentmillis = millis(); + deviceUptime uptime; - deviceUptime uptime; - uptime.secs = (long)((currentmillis / 1000) % 60); - uptime.mins = (long)((currentmillis / 60000) % 60); - uptime.hours = (long)((currentmillis / 3600000) % 24); - uptime.days = (long)((currentmillis / 86400000) % 10); + uptime.secs = (long)((currentmillis / 1000) % 60); + uptime.mins = (long)((currentmillis / 60000) % 60); + uptime.hours = (long)((currentmillis / 3600000) % 24); + uptime.days = (long)((currentmillis / 86400000) % 10); - return uptime; + return uptime; } String ICACHE_FLASH_ATTR NtpClient::getDeviceUptimeString() { + deviceUptime uptime = getDeviceUptime(); - deviceUptime uptime = getDeviceUptime(); - - return String(uptime.days) + " days, " + - String(uptime.hours) + " hours, " + - String(uptime.mins) + " mins, " + - String(uptime.secs) + " secs"; + return String(uptime.days) + " days, " + + String(uptime.hours) + " hours, " + + String(uptime.mins) + " mins, " + + String(uptime.secs) + " secs"; } /* @@ -140,6 +134,5 @@ String ICACHE_FLASH_ATTR NtpClient::getDeviceUptimeString() */ ICACHE_FLASH_ATTR time_t NtpClient::getUtcTimeNow() { - - return now() - timezone; -} \ No newline at end of file + return now() - timezone; +} diff --git a/src/Ntp.h b/src/Ntp.h index 0de48d77..1c78b166 100644 --- a/src/Ntp.h +++ b/src/Ntp.h @@ -14,42 +14,41 @@ #define NTP_PACKET_SIZE 48 // NTP time is in the first 48 bytes of message -struct deviceUptime -{ - long days; - long hours; - long mins; - long secs; +struct deviceUptime { + long days; + long hours; + long mins; + long secs; }; class NtpClient { public: - void ICACHE_FLASH_ATTR Ntp(const char *server, int8_t tz, time_t syncSecs); - ICACHE_FLASH_ATTR virtual ~NtpClient(); + void ICACHE_FLASH_ATTR Ntp(const char *server, int8_t tz, time_t syncSecs); + ICACHE_FLASH_ATTR virtual ~NtpClient(); - static char *TimeServerName; - static IPAddress timeServer; - static int8_t timezone; - static time_t syncInterval; + static char *TimeServerName; + static IPAddress timeServer; + static int8_t timezone; + static time_t syncInterval; - static AsyncUDP udpListener; + static AsyncUDP udpListener; - static byte NTPpacket[NTP_PACKET_SIZE]; + static byte NTPpacket[NTP_PACKET_SIZE]; - static ICACHE_FLASH_ATTR String iso8601DateTime(); - static ICACHE_FLASH_ATTR deviceUptime getDeviceUptime(); - static ICACHE_FLASH_ATTR String getDeviceUptimeString(); - static ICACHE_FLASH_ATTR time_t getUtcTimeNow(); - bool ICACHE_FLASH_ATTR processTime(); - time_t getUptimeSec(); + static ICACHE_FLASH_ATTR String iso8601DateTime(); + static ICACHE_FLASH_ATTR deviceUptime getDeviceUptime(); + static ICACHE_FLASH_ATTR String getDeviceUptimeString(); + static ICACHE_FLASH_ATTR time_t getUtcTimeNow(); + bool ICACHE_FLASH_ATTR processTime(); + time_t getUptimeSec(); private: - static ICACHE_FLASH_ATTR String zeroPaddedIntVal(int val); - static ICACHE_FLASH_ATTR time_t getNtpTime(); + static ICACHE_FLASH_ATTR String zeroPaddedIntVal(int val); + static ICACHE_FLASH_ATTR time_t getNtpTime(); protected: - time_t _uptimesec = 0; + time_t _uptimesec = 0; }; #endif /* NTP_H_ */ diff --git a/src/PN532.cpp b/src/PN532.cpp index 5a54a715..b2257da3 100644 --- a/src/PN532.cpp +++ b/src/PN532.cpp @@ -1,53 +1,53 @@ #ifndef OFFICIALBOARD /************************************************************************** - @file PN532.cpp - @author Adafruit Industries, Elmü - @license BSD (see license.txt) - - Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver - - This is a library for the Adafruit PN532 NFC/RFID breakout board. - This library works with the Adafruit NFC breakout - ----> https://www.adafruit.com/products/364 - - Check out the links above for our tutorials and wiring diagrams - These chips use SPI or I2C to communicate. - - Adafruit invests time and resources providing this open source code, - please support Adafruit and open-source hardware by purchasing products from Adafruit! - - ---------------------------------------------------------- - April 2016, modifications by Elmü: - The code from Adafruit was a VERY SLOPPY code just for testing and playing around but not usable for production. - It has been rewritten completely by Elmü. - IRQ is not required anymore in I2C mode. Now the software handshake is used instead. - Removed all compiler warnings that appeared when compiling Adafruit code. - Bugfix: Adafruit used strncmp() to compare binary data which is completey wrong -> replaced with memcmp() - Bugfix: (Severe bug) Adafruit code does not check for valid return packets. The checksum is completely irgnored. Bytes received before the start code are not skipped! - Bugfix: (Severe bug) Adafruit code used a timeout = 0 (wait forever). This is completely wrong. If the chip does not respond, the code hangs forever! - Bugfix: Adafruit code does not allow to distinguish why readPassiveTargetID() returns false. (because there is no card or because of communication problem?) - Added support for Value blocks (in Mifare.cpp) - Added memory Dump (in Mifare.cpp) - AuthenticateDataBlock(), ReadDataBlock() and WriteDataBlock() rewritten (in Mifare.cpp) - Implemented the correct wake up procedure (sending PN532_WAKEUP) instead of sending getFirmwareVersion. - Debug output was buggy: The checksum bytes were displayed as 0xFFFFFFFC instead of 0xFC and removed useless "0x" before each byte. - Detailed debug output was missing. Added display of valid data bytes inside the packet. - SPI slow speed added (using Software SPI to get 10kHz clock) - getFirmwareVersion() was a very clumsy and cryptic command -> completely rewritten - writeGPIO() rewritten -> no warning about wrong usage anymore. - setPassiveActivationRetries() did not have any error checking at all. - Ugly code in writecommand() completely rewritten - Crappy code like this removed: int offset = mb_UsingSPI ? 5 : 6; - ---------------------------------------------------------- - - Check for a new version on http://www.codeproject.com/Articles/1096861/DIY-electronic-RFID-Door-Lock-with-Battery-Backup - +* @file PN532.cpp +* @author Adafruit Industries, Elmü +* @license BSD (see license.txt) +* +* Driver for NXP's PN532 NFC/13.56MHz RFID Transceiver +* +* This is a library for the Adafruit PN532 NFC/RFID breakout board. +* This library works with the Adafruit NFC breakout +* ----> https://www.adafruit.com/products/364 +* +* Check out the links above for our tutorials and wiring diagrams +* These chips use SPI or I2C to communicate. +* +* Adafruit invests time and resources providing this open source code, +* please support Adafruit and open-source hardware by purchasing products from Adafruit! +* +* ---------------------------------------------------------- +* April 2016, modifications by Elmü: +* The code from Adafruit was a VERY SLOPPY code just for testing and playing around but not usable for production. +* It has been rewritten completely by Elmü. +* IRQ is not required anymore in I2C mode. Now the software handshake is used instead. +* Removed all compiler warnings that appeared when compiling Adafruit code. +* Bugfix: Adafruit used strncmp() to compare binary data which is completey wrong -> replaced with memcmp() +* Bugfix: (Severe bug) Adafruit code does not check for valid return packets. The checksum is completely irgnored. Bytes received before the start code are not skipped! +* Bugfix: (Severe bug) Adafruit code used a timeout = 0 (wait forever). This is completely wrong. If the chip does not respond, the code hangs forever! +* Bugfix: Adafruit code does not allow to distinguish why readPassiveTargetID() returns false. (because there is no card or because of communication problem?) +* Added support for Value blocks (in Mifare.cpp) +* Added memory Dump (in Mifare.cpp) +* AuthenticateDataBlock(), ReadDataBlock() and WriteDataBlock() rewritten (in Mifare.cpp) +* Implemented the correct wake up procedure (sending PN532_WAKEUP) instead of sending getFirmwareVersion. +* Debug output was buggy: The checksum bytes were displayed as 0xFFFFFFFC instead of 0xFC and removed useless "0x" before each byte. +* Detailed debug output was missing. Added display of valid data bytes inside the packet. +* SPI slow speed added (using Software SPI to get 10kHz clock) +* getFirmwareVersion() was a very clumsy and cryptic command -> completely rewritten +* writeGPIO() rewritten -> no warning about wrong usage anymore. +* setPassiveActivationRetries() did not have any error checking at all. +* Ugly code in writecommand() completely rewritten +* Crappy code like this removed: int offset = mb_UsingSPI ? 5 : 6; +* ---------------------------------------------------------- +* +* Check for a new version on http://www.codeproject.com/Articles/1096861/DIY-electronic-RFID-Door-Lock-with-Battery-Backup +* **************************************************************************/ #include "PN532.h" /************************************************************************** - Constructor +* Constructor **************************************************************************/ PN532::PN532() { @@ -59,8 +59,8 @@ PN532::PN532() } /************************************************************************** - Initializes for hardware I2C usage. - param reset The RSTPD_N pin +* Initializes for hardware I2C usage. +* param reset The RSTPD_N pin **************************************************************************/ #if USE_HARDWARE_I2C void PN532::InitI2C(byte u8_Reset) @@ -71,12 +71,12 @@ void PN532::InitI2C(byte u8_Reset) #endif /************************************************************************** - Initializes for software SPI usage. - param clk SPI clock pin (SCK) - param miso SPI MISO pin - param mosi SPI MOSI pin - param sel SPI chip select pin (CS/SSEL) - param reset Location of the RSTPD_N pin +* Initializes for software SPI usage. +* param clk SPI clock pin (SCK) +* param miso SPI MISO pin +* param mosi SPI MOSI pin +* param sel SPI chip select pin (CS/SSEL) +* param reset Location of the RSTPD_N pin **************************************************************************/ #if USE_SOFTWARE_SPI void PN532::InitSoftwareSPI(byte u8_Clk, byte u8_Miso, byte u8_Mosi, byte u8_Sel, byte u8_Reset) @@ -96,9 +96,9 @@ void PN532::InitSoftwareSPI(byte u8_Clk, byte u8_Miso, byte u8_Mosi, byte u8_Sel #endif /************************************************************************** - Initializes for hardware SPI uage. - param sel SPI chip select pin (CS/SSEL) - param reset Location of the RSTPD_N pin +* Initializes for hardware SPI uage. +* param sel SPI chip select pin (CS/SSEL) +* param reset Location of the RSTPD_N pin **************************************************************************/ #if USE_HARDWARE_SPI void PN532::InitHardwareSPI(byte u8_Sel, byte u8_Reset) @@ -112,12 +112,13 @@ void PN532::InitHardwareSPI(byte u8_Sel, byte u8_Reset) #endif /************************************************************************** - Reset the PN532, wake up and start communication +* Reset the PN532, wake up and start communication **************************************************************************/ void PN532::begin() { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** begin()\r\n"); + } Utils::WritePin(mu8_ResetPin, HIGH); Utils::DelayMilli(10); @@ -137,8 +138,7 @@ void PN532::begin() memset(u8_Buffer, PN532_WAKEUP, sizeof(u8_Buffer)); SendPacket(u8_Buffer, sizeof(u8_Buffer)); - if (mu8_DebugLevel > 1) - { + if (mu8_DebugLevel > 1) { Utils::Print("Send WakeUp packet: "); Utils::PrintHexBuf(u8_Buffer, sizeof(u8_Buffer), LF); } @@ -151,8 +151,8 @@ void PN532::begin() } /************************************************************************** - Enable / disable debug output to SerialClass - 0 = Off, 1 = high level debug, 2 = low level debug (more details) +* Enable / disable debug output to SerialClass +* 0 = Off, 1 = high level debug, 2 = low level debug (more details) **************************************************************************/ void PN532::SetDebugLevel(byte level) { @@ -160,26 +160,28 @@ void PN532::SetDebugLevel(byte level) } /************************************************************************** - Gets the firmware version of the PN5xx chip - returns: - pIcType = Version of the IC. For PN532, this byte is 0x32 - pVersionHi, pVersionLo = Firmware version - pFlags, bit 0 = Support of ISO 14443A - pFlags, bit 1 = Support of ISO 14443B - pFlags, bit 2 = Support of ISO 18092 +* Gets the firmware version of the PN5xx chip +* returns: +* pIcType = Version of the IC. For PN532, this byte is 0x32 +* pVersionHi, pVersionLo = Firmware version +* pFlags, bit 0 = Support of ISO 14443A +* pFlags, bit 1 = Support of ISO 14443B +* pFlags, bit 2 = Support of ISO 18092 **************************************************************************/ bool PN532::GetFirmwareVersion(byte *pIcType, byte *pVersionHi, byte *pVersionLo, byte *pFlags) { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** GetFirmwareVersion()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_GETFIRMWAREVERSION; - if (!SendCommandCheckAck(mu8_PacketBuffer, 1)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 1)) { return 0; + } byte len = ReadData(mu8_PacketBuffer, 13); - if (len != 6 || mu8_PacketBuffer[1] != PN532_COMMAND_GETFIRMWAREVERSION + 1) - { + + if (len != 6 || mu8_PacketBuffer[1] != PN532_COMMAND_GETFIRMWAREVERSION + 1) { Utils::Print("GetFirmwareVersion failed\r\n"); return false; } @@ -192,24 +194,26 @@ bool PN532::GetFirmwareVersion(byte *pIcType, byte *pVersionHi, byte *pVersionLo } /************************************************************************** - Configures the SAM (Secure Access Module) +* Configures the SAM (Secure Access Module) **************************************************************************/ bool PN532::SamConfig(void) { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** SamConfig()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_SAMCONFIGURATION; mu8_PacketBuffer[1] = 0x01; // normal mode; mu8_PacketBuffer[2] = 0x14; // timeout 50ms * 20 = 1 second mu8_PacketBuffer[3] = 0x01; // use IRQ pin! - if (!SendCommandCheckAck(mu8_PacketBuffer, 4)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 4)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 9); - if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_SAMCONFIGURATION + 1) - { + + if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_SAMCONFIGURATION + 1) { Utils::Print("SamConfig failed\r\n"); return false; } @@ -217,12 +221,13 @@ bool PN532::SamConfig(void) } /************************************************************************** - Sets the amount of reties that the PN532 tries to activate a target +* Sets the amount of reties that the PN532 tries to activate a target **************************************************************************/ bool PN532::SetPassiveActivationRetries() { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** SetPassiveActivationRetries()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_RFCONFIGURATION; mu8_PacketBuffer[1] = 5; // Config item 5 (MaxRetries) @@ -230,12 +235,13 @@ bool PN532::SetPassiveActivationRetries() mu8_PacketBuffer[3] = 0x01; // MxRtyPSL (default = 0x01) mu8_PacketBuffer[4] = 3; // one retry is enough for Mifare Classic but Desfire is slower (if you modify this, you must also modify PN532_TIMEOUT!) - if (!SendCommandCheckAck(mu8_PacketBuffer, 5)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 5)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 9); - if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_RFCONFIGURATION + 1) - { + + if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_RFCONFIGURATION + 1) { Utils::Print("SetPassiveActivationRetries failed\r\n"); return false; } @@ -243,26 +249,28 @@ bool PN532::SetPassiveActivationRetries() } /************************************************************************** - Turns the RF field off. - When the field is on, the PN532 consumes approx 110 mA - When the field is off, the PN532 consumes approx 18 mA - The RF field is turned on again by ReadPassiveTargetID(). +* Turns the RF field off. +* When the field is on, the PN532 consumes approx 110 mA +* When the field is off, the PN532 consumes approx 18 mA +* The RF field is turned on again by ReadPassiveTargetID(). **************************************************************************/ bool PN532::SwitchOffRfField() { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** SwitchOffRfField()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_RFCONFIGURATION; - mu8_PacketBuffer[1] = 1; // Config item 1 (RF Field) - mu8_PacketBuffer[2] = 0; // Field Off + mu8_PacketBuffer[1] = 1; // Config item 1 (RF Field) + mu8_PacketBuffer[2] = 0; // Field Off - if (!SendCommandCheckAck(mu8_PacketBuffer, 3)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 3)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 9); - if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_RFCONFIGURATION + 1) - { + + if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_RFCONFIGURATION + 1) { Utils::Print("SwitchOffRfField failed\r\n"); return false; } @@ -271,32 +279,33 @@ bool PN532::SwitchOffRfField() /**************************************************************************/ /*! - Writes an 8-bit value that sets the state of the PN532's GPIO pins - - All pins that can not be used as GPIO should ALWAYS be left high - (value = 1) or the system will become unstable and a HW reset - will be required to recover the PN532. - - pinState[0] (01) = P30 Can be used as GPIO - pinState[1] (02) = P31 Can be used as GPIO - pinState[2] (04) = P32 *** RESERVED (Must be set) *** - pinState[3] (08) = P33 Can be used as GPIO - pinState[4] (10) = P34 *** RESERVED (Must be set) *** - pinState[5] (20) = P35 Can be used as GPIO - - This function is not used. The original intention was to drive a LED that - is connected to the PN532 board. But the pins deliver so few current - that a connected LED is very dark. (even if connected without resistor!) - Additionally the red LED cannot be connected to the PN532 because it should - flash if there is a communication error with the PN532. But if there is a - communication problem the command WRITEGPIO will never arrive at the PN532 - and the red LED would never flash. -*/ + * Writes an 8-bit value that sets the state of the PN532's GPIO pins + * + * All pins that can not be used as GPIO should ALWAYS be left high + * (value = 1) or the system will become unstable and a HW reset + * will be required to recover the PN532. + * + * pinState[0] (01) = P30 Can be used as GPIO + * pinState[1] (02) = P31 Can be used as GPIO + * pinState[2] (04) = P32 *** RESERVED (Must be set) *** + * pinState[3] (08) = P33 Can be used as GPIO + * pinState[4] (10) = P34 *** RESERVED (Must be set) *** + * pinState[5] (20) = P35 Can be used as GPIO + * + * This function is not used. The original intention was to drive a LED that + * is connected to the PN532 board. But the pins deliver so few current + * that a connected LED is very dark. (even if connected without resistor!) + * Additionally the red LED cannot be connected to the PN532 because it should + * flash if there is a communication error with the PN532. But if there is a + * communication problem the command WRITEGPIO will never arrive at the PN532 + * and the red LED would never flash. + */ /**************************************************************************/ bool PN532::WriteGPIO(bool P30, bool P31, bool P33, bool P35) { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** WriteGPIO()\r\n"); + } byte pinState = (P30 ? PN532_GPIO_P30 : 0) | (P31 ? PN532_GPIO_P31 : 0) | @@ -306,15 +315,16 @@ bool PN532::WriteGPIO(bool P30, bool P31, bool P33, bool P35) (P35 ? PN532_GPIO_P35 : 0); mu8_PacketBuffer[0] = PN532_COMMAND_WRITEGPIO; - mu8_PacketBuffer[1] = PN532_GPIO_VALIDATIONBIT | pinState; // P3 Pins - mu8_PacketBuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by SPI) + mu8_PacketBuffer[1] = PN532_GPIO_VALIDATIONBIT | pinState; // P3 Pins + mu8_PacketBuffer[2] = 0x00; // P7 GPIO Pins (not used ... taken by SPI) - if (!SendCommandCheckAck(mu8_PacketBuffer, 3)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 3)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 9); - if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_WRITEGPIO + 1) - { + + if (len != 2 || mu8_PacketBuffer[1] != PN532_COMMAND_WRITEGPIO + 1) { Utils::Print("WriteGPIO failed\r\n"); return false; } @@ -322,66 +332,67 @@ bool PN532::WriteGPIO(bool P30, bool P31, bool P33, bool P35) } /************************************************************************** - Waits for an ISO14443A target to enter the field. - If the RF field has been turned off before, this command switches it on. - - param u8_UidBuffer Pointer to an 8 byte buffer that will be populated with the card's UID (4 or 7 bytes) - param pu8_UidLength Pointer to the variable that will hold the length of the card's UID. - param pe_CardType Pointer to the variable that will hold if the card is a Desfire card - - returns false only on error! - returns true and *UidLength = 0 if no card was found - returns true and *UidLength > 0 if a card has been read successfully +* Waits for an ISO14443A target to enter the field. +* If the RF field has been turned off before, this command switches it on. +* +* param u8_UidBuffer Pointer to an 8 byte buffer that will be populated with the card's UID (4 or 7 bytes) +* param pu8_UidLength Pointer to the variable that will hold the length of the card's UID. +* param pe_CardType Pointer to the variable that will hold if the card is a Desfire card +* +* returns false only on error! +* returns true and *UidLength = 0 if no card was found +* returns true and *UidLength > 0 if a card has been read successfully **************************************************************************/ bool PN532::ReadPassiveTargetID(byte *u8_UidBuffer, byte *pu8_UidLength, eCardType *pe_CardType) { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** ReadPassiveTargetID()\r\n"); + } *pu8_UidLength = 0; *pe_CardType = CARD_Unknown; memset(u8_UidBuffer, 0, 8); mu8_PacketBuffer[0] = PN532_COMMAND_INLISTPASSIVETARGET; - mu8_PacketBuffer[1] = 1; // read data of 1 card (The PN532 can read max 2 targets at the same time) - mu8_PacketBuffer[2] = CARD_TYPE_106KB_ISO14443A; // This function currently does not support other card types. + mu8_PacketBuffer[1] = 1; // read data of 1 card (The PN532 can read max 2 targets at the same time) + mu8_PacketBuffer[2] = CARD_TYPE_106KB_ISO14443A; // This function currently does not support other card types. - if (!SendCommandCheckAck(mu8_PacketBuffer, 3)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 3)) { return false; // Error (no valid ACK received or timeout) - - /* - ISO14443A card response: - mu8_PacketBuffer Description - ------------------------------------------------------- - b0 D5 (always) (PN532_PN532TOHOST) - b1 4B (always) (PN532_COMMAND_INLISTPASSIVETARGET + 1) - b2 Amount of cards found - b3 Tag number (always 1) - b4,5 SENS_RES (ATQA = Answer to Request Type A) - b6 SEL_RES (SAK = Select Acknowledge) - b7 UID Length - b8..Length UID (4 or 7 bytes) - nn ATS Length (Desfire only) - nn..Length-1 ATS data bytes (Desfire only) - */ + } + /* + * ISO14443A card response: + * mu8_PacketBuffer Description + * ------------------------------------------------------- + * b0 D5 (always) (PN532_PN532TOHOST) + * b1 4B (always) (PN532_COMMAND_INLISTPASSIVETARGET + 1) + * b2 Amount of cards found + * b3 Tag number (always 1) + * b4,5 SENS_RES (ATQA = Answer to Request Type A) + * b6 SEL_RES (SAK = Select Acknowledge) + * b7 UID Length + * b8..Length UID (4 or 7 bytes) + * nn ATS Length (Desfire only) + * nn..Length-1 ATS data bytes (Desfire only) + */ byte len = ReadData(mu8_PacketBuffer, 28); - if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INLISTPASSIVETARGET + 1) - { + + if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INLISTPASSIVETARGET + 1) { Utils::Print("ReadPassiveTargetID failed\r\n"); return false; } byte cardsFound = mu8_PacketBuffer[2]; - if (mu8_DebugLevel > 0) - { + + if (mu8_DebugLevel > 0) { Utils::Print("Cards found: "); Utils::PrintDec(cardsFound, LF); } - if (cardsFound != 1) + if (cardsFound != 1) { return true; // no card found -> this is not an error! - + } byte u8_IdLength = mu8_PacketBuffer[7]; - if (u8_IdLength != 4 && u8_IdLength != 7) - { + + if (u8_IdLength != 4 && u8_IdLength != 7) { Utils::Print("Card has unsupported UID length: "); Utils::PrintDec(u8_IdLength, LF); return true; // unsupported card found -> this is not an error! @@ -394,13 +405,14 @@ bool PN532::ReadPassiveTargetID(byte *u8_UidBuffer, byte *pu8_UidLength, eCardTy uint16_t u16_ATQA = ((uint16_t)mu8_PacketBuffer[4] << 8) | mu8_PacketBuffer[5]; byte u8_SAK = mu8_PacketBuffer[6]; - if (u8_IdLength == 7 && u8_UidBuffer[0] != 0x80 && u16_ATQA == 0x0344 && u8_SAK == 0x20) + if (u8_IdLength == 7 && u8_UidBuffer[0] != 0x80 && u16_ATQA == 0x0344 && u8_SAK == 0x20) { *pe_CardType = CARD_Desfire; - if (u8_IdLength == 4 && u8_UidBuffer[0] == 0x80 && u16_ATQA == 0x0304 && u8_SAK == 0x20) + } + if (u8_IdLength == 4 && u8_UidBuffer[0] == 0x80 && u16_ATQA == 0x0304 && u8_SAK == 0x20) { *pe_CardType = CARD_DesRandom; + } - if (mu8_DebugLevel > 0) - { + if (mu8_DebugLevel > 0) { Utils::Print("Card UID: "); Utils::PrintHexBuf(u8_UidBuffer, u8_IdLength, LF); @@ -416,10 +428,12 @@ bool PN532::ReadPassiveTargetID(byte *u8_UidBuffer, byte *pu8_UidLength, eCardTy char s8_Buf[80]; sprintf(s8_Buf, "Card Type: ATQA= 0x%04X, SAK= 0x%02X", u16_ATQA, u8_SAK); - if (*pe_CardType == CARD_Desfire) + if (*pe_CardType == CARD_Desfire) { strcat(s8_Buf, " (Desfire Default)"); - if (*pe_CardType == CARD_DesRandom) + } + if (*pe_CardType == CARD_DesRandom) { strcat(s8_Buf, " (Desfire RandomID)"); + } Utils::Print(s8_Buf, LF); } @@ -427,23 +441,25 @@ bool PN532::ReadPassiveTargetID(byte *u8_UidBuffer, byte *pu8_UidLength, eCardTy } /************************************************************************** - The goal of this command is to select the target. (Initialization, anti-collision loop and Selection) - If the target is already selected, no action is performed and Status OK is returned. +* The goal of this command is to select the target. (Initialization, anti-collision loop and Selection) +* If the target is already selected, no action is performed and Status OK is returned. **************************************************************************/ bool PN532::SelectCard() { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** SelectCard()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_INSELECT; mu8_PacketBuffer[1] = 1; // Target 1 - if (!SendCommandCheckAck(mu8_PacketBuffer, 2)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 2)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 10); - if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INSELECT + 1) - { + + if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INSELECT + 1) { Utils::Print("Select failed\r\n"); return false; } @@ -452,28 +468,30 @@ bool PN532::SelectCard() } /************************************************************************** - The goal of this command is to deselect the target. - The PN532 keeps all the information relative to this target (also certain error status). - This function is required due to a stupid behaviour with Mifare Classic: - When AuthenticateDataBlock() has failed for a sector, you also get an - authentication error for the next sector although you have passed the correct key. - So, after an authentication error you must first deselect the card before - authenticating a new sector! +* The goal of this command is to deselect the target. +* The PN532 keeps all the information relative to this target (also certain error status). +* This function is required due to a stupid behaviour with Mifare Classic: +* When AuthenticateDataBlock() has failed for a sector, you also get an +* authentication error for the next sector although you have passed the correct key. +* So, after an authentication error you must first deselect the card before +* authenticating a new sector! **************************************************************************/ bool PN532::DeselectCard() { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** DeselectCard()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_INDESELECT; mu8_PacketBuffer[1] = 0; // Deselect all cards - if (!SendCommandCheckAck(mu8_PacketBuffer, 2)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 2)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 10); - if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INDESELECT + 1) - { + + if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INDESELECT + 1) { Utils::Print("Deselect failed\r\n"); return false; } @@ -482,24 +500,26 @@ bool PN532::DeselectCard() } /************************************************************************** - The goal of this command is to release the target. - Releasing a target means that the host controller has finished the communication with - the target, so the PN532 erases all the information relative to it. +* The goal of this command is to release the target. +* Releasing a target means that the host controller has finished the communication with +* the target, so the PN532 erases all the information relative to it. **************************************************************************/ bool PN532::ReleaseCard() { - if (mu8_DebugLevel > 0) + if (mu8_DebugLevel > 0) { Utils::Print("\r\n*** ReleaseCard()\r\n"); + } mu8_PacketBuffer[0] = PN532_COMMAND_INRELEASE; mu8_PacketBuffer[1] = 0; // Deselect all cards - if (!SendCommandCheckAck(mu8_PacketBuffer, 2)) + if (!SendCommandCheckAck(mu8_PacketBuffer, 2)) { return false; + } byte len = ReadData(mu8_PacketBuffer, 10); - if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INRELEASE + 1) - { + + if (len < 3 || mu8_PacketBuffer[1] != PN532_COMMAND_INRELEASE + 1) { Utils::Print("Release failed\r\n"); return false; } @@ -508,106 +528,107 @@ bool PN532::ReleaseCard() } /************************************************************************** - This function is private - It checks the status byte that is returned by some commands. - See chapter 7.1 in the manual. - u8_Status = the status byte +* This function is private +* It checks the status byte that is returned by some commands. +* See chapter 7.1 in the manual. +* u8_Status = the status byte **************************************************************************/ bool PN532::CheckPN532Status(byte u8_Status) { // Bits 0...5 contain the error code. u8_Status &= 0x3F; - if (u8_Status == 0) + if (u8_Status == 0) { return true; + } char s8_Buf[50]; + sprintf(s8_Buf, "PN532 Error 0x%02X: ", u8_Status); Utils::Print(s8_Buf); - switch (u8_Status) - { - case 0x01: - Utils::Print("Timeout\r\n"); - return false; - case 0x02: - Utils::Print("CRC error\r\n"); - return false; - case 0x03: - Utils::Print("Parity error\r\n"); - return false; - case 0x04: - Utils::Print("Wrong bit count during anti-collision\r\n"); - return false; - case 0x05: - Utils::Print("Framing error\r\n"); - return false; - case 0x06: - Utils::Print("Abnormal bit collision\r\n"); - return false; - case 0x07: - Utils::Print("Insufficient communication buffer\r\n"); - return false; - case 0x09: - Utils::Print("RF buffer overflow\r\n"); - return false; - case 0x0A: - Utils::Print("RF field has not been switched on\r\n"); - return false; - case 0x0B: - Utils::Print("RF protocol error\r\n"); - return false; - case 0x0D: - Utils::Print("Overheating\r\n"); - return false; - case 0x0E: - Utils::Print("Internal buffer overflow\r\n"); - return false; - case 0x10: - Utils::Print("Invalid parameter\r\n"); - return false; - case 0x12: - Utils::Print("Command not supported\r\n"); - return false; - case 0x13: - Utils::Print("Wrong data format\r\n"); - return false; - case 0x14: - Utils::Print("Authentication error\r\n"); - return false; - case 0x23: - Utils::Print("Wrong UID check byte\r\n"); - return false; - case 0x25: - Utils::Print("Invalid device state\r\n"); - return false; - case 0x26: - Utils::Print("Operation not allowed\r\n"); - return false; - case 0x27: - Utils::Print("Command not acceptable\r\n"); - return false; - case 0x29: - Utils::Print("Target has been released\r\n"); - return false; - case 0x2A: - Utils::Print("Card has been exchanged\r\n"); - return false; - case 0x2B: - Utils::Print("Card has disappeared\r\n"); - return false; - case 0x2C: - Utils::Print("NFCID3 initiator/target mismatch\r\n"); - return false; - case 0x2D: - Utils::Print("Over-current\r\n"); - return false; - case 0x2E: - Utils::Print("NAD msssing\r\n"); - return false; - default: - Utils::Print("Undocumented error\r\n"); - return false; + switch (u8_Status) { + case 0x01: + Utils::Print("Timeout\r\n"); + return false; + case 0x02: + Utils::Print("CRC error\r\n"); + return false; + case 0x03: + Utils::Print("Parity error\r\n"); + return false; + case 0x04: + Utils::Print("Wrong bit count during anti-collision\r\n"); + return false; + case 0x05: + Utils::Print("Framing error\r\n"); + return false; + case 0x06: + Utils::Print("Abnormal bit collision\r\n"); + return false; + case 0x07: + Utils::Print("Insufficient communication buffer\r\n"); + return false; + case 0x09: + Utils::Print("RF buffer overflow\r\n"); + return false; + case 0x0A: + Utils::Print("RF field has not been switched on\r\n"); + return false; + case 0x0B: + Utils::Print("RF protocol error\r\n"); + return false; + case 0x0D: + Utils::Print("Overheating\r\n"); + return false; + case 0x0E: + Utils::Print("Internal buffer overflow\r\n"); + return false; + case 0x10: + Utils::Print("Invalid parameter\r\n"); + return false; + case 0x12: + Utils::Print("Command not supported\r\n"); + return false; + case 0x13: + Utils::Print("Wrong data format\r\n"); + return false; + case 0x14: + Utils::Print("Authentication error\r\n"); + return false; + case 0x23: + Utils::Print("Wrong UID check byte\r\n"); + return false; + case 0x25: + Utils::Print("Invalid device state\r\n"); + return false; + case 0x26: + Utils::Print("Operation not allowed\r\n"); + return false; + case 0x27: + Utils::Print("Command not acceptable\r\n"); + return false; + case 0x29: + Utils::Print("Target has been released\r\n"); + return false; + case 0x2A: + Utils::Print("Card has been exchanged\r\n"); + return false; + case 0x2B: + Utils::Print("Card has disappeared\r\n"); + return false; + case 0x2C: + Utils::Print("NFCID3 initiator/target mismatch\r\n"); + return false; + case 0x2D: + Utils::Print("Over-current\r\n"); + return false; + case 0x2E: + Utils::Print("NAD msssing\r\n"); + return false; + default: + Utils::Print("Undocumented error\r\n"); + return false; } } @@ -616,7 +637,7 @@ bool PN532::CheckPN532Status(byte u8_Status) // ######################################################################## /************************************************************************** - Return true if the PN532 is ready with a response. +* Return true if the PN532 is ready with a response. **************************************************************************/ bool PN532::IsReady() { @@ -625,14 +646,14 @@ bool PN532::IsReady() Utils::WritePin(mu8_SselPin, LOW); Utils::DelayMilli(2); // INDISPENSABLE!! Otherwise reads bullshit - if (mu8_DebugLevel > 2) + if (mu8_DebugLevel > 2) { Utils::Print("IsReady(): write STATUSREAD\r\n"); + } SpiWrite(PN532_SPI_STATUSREAD); byte u8_Ready = SpiRead(); - if (mu8_DebugLevel > 2) - { + if (mu8_DebugLevel > 2) { Utils::Print("IsReady(): read "); Utils::PrintHex8(u8_Ready, LF); } @@ -649,8 +670,7 @@ bool PN532::IsReady() // PN532 Manual chapter 6.2.4: Before the data bytes the chip sends a Ready byte. byte u8_Ready = I2cClass::Read(); - if (mu8_DebugLevel > 2) - { + if (mu8_DebugLevel > 2) { Utils::Print("IsReady(): read "); Utils::PrintHex8(u8_Ready, LF); } @@ -661,17 +681,17 @@ bool PN532::IsReady() } /************************************************************************** - Waits until the PN532 is ready. +* Waits until the PN532 is ready. **************************************************************************/ bool PN532::WaitReady() { uint16_t timer = 0; - while (!IsReady()) - { - if (timer >= PN532_TIMEOUT) - { - if (mu8_DebugLevel > 0) + + while (!IsReady()) { + if (timer >= PN532_TIMEOUT) { + if (mu8_DebugLevel > 0) { Utils::Print("WaitReady() -> TIMEOUT\r\n"); + } return false; } Utils::DelayMilli(10); @@ -681,12 +701,12 @@ bool PN532::WaitReady() } /************************************************************************** - Sends a command and waits a specified period for the ACK - param cmd Pointer to the command buffer - param cmdlen The size of the command in bytes - - returns true if everything is OK, - false if timeout occured before an ACK was recieved +* Sends a command and waits a specified period for the ACK +* param cmd Pointer to the command buffer +* param cmdlen The size of the command in bytes +* +* returns true if everything is OK, +* false if timeout occured before an ACK was recieved **************************************************************************/ bool PN532::SendCommandCheckAck(byte *cmd, byte cmdlen) { @@ -695,31 +715,31 @@ bool PN532::SendCommandCheckAck(byte *cmd, byte cmdlen) } /************************************************************************** - Writes a command to the PN532, inserting the - preamble and required frame details (checksum, len, etc.) - - param cmd Command buffer - param cmdlen Command length in bytes +* Writes a command to the PN532, inserting the +* preamble and required frame details (checksum, len, etc.) +* +* param cmd Command buffer +* param cmdlen Command length in bytes **************************************************************************/ void PN532::WriteCommand(byte *cmd, byte cmdlen) { byte TxBuffer[PN532_PACKBUFFSIZE + 10]; int P = 0; - TxBuffer[P++] = PN532_PREAMBLE; // 00 - TxBuffer[P++] = PN532_STARTCODE1; // 00 - TxBuffer[P++] = PN532_STARTCODE2; // FF + + TxBuffer[P++] = PN532_PREAMBLE; // 00 + TxBuffer[P++] = PN532_STARTCODE1; // 00 + TxBuffer[P++] = PN532_STARTCODE2; // FF TxBuffer[P++] = cmdlen + 1; TxBuffer[P++] = 0xFF - cmdlen; TxBuffer[P++] = PN532_HOSTTOPN532; // D4 - for (byte i = 0; i < cmdlen; i++) - { + for (byte i = 0; i < cmdlen; i++) { TxBuffer[P++] = cmd[i]; } byte checksum = 0; - for (byte i = 0; i < P; i++) - { + + for (byte i = 0; i < P; i++) { checksum += TxBuffer[i]; } @@ -728,15 +748,14 @@ void PN532::WriteCommand(byte *cmd, byte cmdlen) SendPacket(TxBuffer, P); - if (mu8_DebugLevel > 1) - { + if (mu8_DebugLevel > 1) { Utils::Print("Sending: "); Utils::PrintHexBuf(TxBuffer, P, LF, 5, cmdlen + 6); } } /************************************************************************** - Send a data packet +* Send a data packet **************************************************************************/ void PN532::SendPacket(byte *buff, byte len) { @@ -745,12 +764,12 @@ void PN532::SendPacket(byte *buff, byte len) Utils::WritePin(mu8_SselPin, LOW); Utils::DelayMilli(2); // INDISPENSABLE!! - if (mu8_DebugLevel > 2) + if (mu8_DebugLevel > 2) { Utils::Print("WriteCommand(): write DATAWRITE\r\n"); + } SpiWrite(PN532_SPI_DATAWRITE); - for (byte i = 0; i < len; i++) - { + for (byte i = 0; i < len; i++) { SpiWrite(buff[i]); } @@ -762,8 +781,7 @@ void PN532::SendPacket(byte *buff, byte len) Utils::DelayMilli(2); // delay is for waking up the board I2cClass::BeginTransmission(PN532_I2C_ADDRESS); - for (byte i = 0; i < len; i++) - { + for (byte i = 0; i < len; i++) { I2cClass::Write(buff[i]); } I2cClass::EndTransmission(); @@ -772,26 +790,24 @@ void PN532::SendPacket(byte *buff, byte len) } /************************************************************************** - Read the ACK packet (acknowledge) +* Read the ACK packet (acknowledge) **************************************************************************/ bool PN532::ReadAck() { - const byte Ack[] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00}; + const byte Ack[] = { 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00 }; byte ackbuff[sizeof(Ack)]; // ATTENTION: Never read more than 6 bytes here! // The PN532 has a bug in SPI mode which results in the first byte of the response missing if more than 6 bytes are read here! - if (!ReadPacket(ackbuff, sizeof(ackbuff))) + if (!ReadPacket(ackbuff, sizeof(ackbuff))) { return false; // Timeout - - if (mu8_DebugLevel > 2) - { + } + if (mu8_DebugLevel > 2) { Utils::Print("Read ACK: "); Utils::PrintHexBuf(ackbuff, sizeof(ackbuff), LF); } - if (memcmp(ackbuff, Ack, sizeof(Ack)) != 0) - { + if (memcmp(ackbuff, Ack, sizeof(Ack)) != 0) { Utils::Print("*** No ACK frame received\r\n"); return false; } @@ -799,25 +815,25 @@ bool PN532::ReadAck() } /************************************************************************** - Reads n bytes of data from the PN532 via SPI or I2C and checks for valid data. - param buff Pointer to the buffer where data will be written - param len Number of bytes to read - returns the number of bytes that have been copied to buff (< len) or 0 on error +* Reads n bytes of data from the PN532 via SPI or I2C and checks for valid data. +* param buff Pointer to the buffer where data will be written +* param len Number of bytes to read +* returns the number of bytes that have been copied to buff (< len) or 0 on error **************************************************************************/ byte PN532::ReadData(byte *buff, byte len) { byte RxBuffer[PN532_PACKBUFFSIZE]; const byte MIN_PACK_LEN = 2 /*start bytes*/ + 2 /*length + length checksum */ + 1 /*checksum*/; - if (len < MIN_PACK_LEN || len > PN532_PACKBUFFSIZE) - { + + if (len < MIN_PACK_LEN || len > PN532_PACKBUFFSIZE) { Utils::Print("ReadData(): len is invalid\r\n"); return 0; } - if (!ReadPacket(RxBuffer, len)) + if (!ReadPacket(RxBuffer, len)) { return 0; // timeout - + } // The following important validity check was completely missing in Adafruit code (added by Elmü) // PN532 documentation says (chapter 6.2.1.6): // Before the start code (0x00 0xFF) there may be any number of additional bytes that must be ignored. @@ -838,21 +854,18 @@ byte PN532::ReadData(byte *buff, byte len) int Brace1 = -1; int Brace2 = -1; int dataLength = 0; - do - { + + do{ int startCode = -1; - for (int i = 0; i <= len - MIN_PACK_LEN; i++) - { + for (int i = 0; i <= len - MIN_PACK_LEN; i++) { if (RxBuffer[i] == PN532_STARTCODE1 && - RxBuffer[i + 1] == PN532_STARTCODE2) - { + RxBuffer[i + 1] == PN532_STARTCODE2) { startCode = i; break; } } - if (startCode < 0) - { + if (startCode < 0) { Error = "ReadData() -> No Start Code\r\n"; break; } @@ -860,54 +873,46 @@ byte PN532::ReadData(byte *buff, byte len) int pos = startCode + 2; dataLength = RxBuffer[pos++]; int lengthCheck = RxBuffer[pos++]; - if ((dataLength + lengthCheck) != 0x100) - { + if ((dataLength + lengthCheck) != 0x100) { Error = "ReadData() -> Invalid length checksum\r\n"; break; } - if (len < startCode + MIN_PACK_LEN + dataLength) - { + if (len < startCode + MIN_PACK_LEN + dataLength) { Error = "ReadData() -> Packet is longer than requested length\r\n"; break; } Brace1 = pos; - for (int i = 0; i < dataLength; i++) - { + for (int i = 0; i < dataLength; i++) { buff[i] = RxBuffer[pos++]; // copy the pure data bytes in the packet } Brace2 = pos; // All returned data blocks must start with PN532TOHOST (0xD5) - if (dataLength < 1 || buff[0] != PN532_PN532TOHOST) - { + if (dataLength < 1 || buff[0] != PN532_PN532TOHOST) { Error = "ReadData() -> Invalid data (no PN532TOHOST)\r\n"; break; } byte checkSum = 0; - for (int i = startCode; i < pos; i++) - { + for (int i = startCode; i < pos; i++) { checkSum += RxBuffer[i]; } - if (checkSum != (byte)(~RxBuffer[pos])) - { + if (checkSum != (byte)(~RxBuffer[pos])) { Error = "ReadData() -> Invalid checksum\r\n"; break; } } while (false); // This is not a loop. Avoids using goto by using break. // Always print the package, even if it was invalid. - if (mu8_DebugLevel > 1) - { + if (mu8_DebugLevel > 1) { Utils::Print("Response: "); Utils::PrintHexBuf(RxBuffer, len, LF, Brace1, Brace2); } - if (Error) - { + if (Error) { Utils::Print(Error); return 0; } @@ -916,26 +921,27 @@ byte PN532::ReadData(byte *buff, byte len) } /************************************************************************** - Reads n bytes of data from the PN532 via SPI or I2C and does NOT check for valid data. - param buff Pointer to the buffer where data will be written - param len Number of bytes to read +* Reads n bytes of data from the PN532 via SPI or I2C and does NOT check for valid data. +* param buff Pointer to the buffer where data will be written +* param len Number of bytes to read **************************************************************************/ bool PN532::ReadPacket(byte *buff, byte len) { - if (!WaitReady()) + if (!WaitReady()) { return false; + } #if (USE_HARDWARE_SPI || USE_SOFTWARE_SPI) { Utils::WritePin(mu8_SselPin, LOW); Utils::DelayMilli(2); // INDISPENSABLE!! Otherwise reads bullshit - if (mu8_DebugLevel > 2) + if (mu8_DebugLevel > 2) { Utils::Print("ReadPacket(): write DATAREAD\r\n"); + } SpiWrite(PN532_SPI_DATAREAD); - for (byte i = 0; i < len; i++) - { + for (byte i = 0; i < len; i++) { Utils::DelayMilli(1); buff[i] = SpiRead(); } @@ -954,14 +960,12 @@ bool PN532::ReadPacket(byte *buff, byte len) // PN532 Manual chapter 6.2.4: Before the data bytes the chip sends a Ready byte. // It is ignored here because it has been checked already in isready() byte u8_Ready = I2cClass::Read(); - if (mu8_DebugLevel > 2) - { + if (mu8_DebugLevel > 2) { Utils::Print("ReadPacket(): read "); Utils::PrintHex8(u8_Ready, LF); } - for (byte i = 0; i < len; i++) - { + for (byte i = 0; i < len; i++) { Utils::DelayMilli(1); buff[i] = I2cClass::Read(); } @@ -971,7 +975,7 @@ bool PN532::ReadPacket(byte *buff, byte len) } /************************************************************************** - SPI write one byte +* SPI write one byte **************************************************************************/ void PN532::SpiWrite(byte c) { @@ -984,8 +988,7 @@ void PN532::SpiWrite(byte c) Utils::WritePin(mu8_ClkPin, HIGH); Utils::DelayMicro(PN532_SOFT_SPI_DELAY); - for (int i = 1; i <= 128; i <<= 1) - { + for (int i = 1; i <= 128; i <<= 1) { Utils::WritePin(mu8_ClkPin, LOW); Utils::DelayMicro(PN532_SOFT_SPI_DELAY); @@ -1001,7 +1004,7 @@ void PN532::SpiWrite(byte c) } /************************************************************************** - SPI read one byte +* SPI read one byte **************************************************************************/ byte PN532::SpiRead(void) { @@ -1015,10 +1018,8 @@ byte PN532::SpiRead(void) Utils::DelayMicro(PN532_SOFT_SPI_DELAY); int x = 0; - for (int i = 1; i <= 128; i <<= 1) - { - if (Utils::ReadPin(mu8_MisoPin)) - { + for (int i = 1; i <= 128; i <<= 1) { + if (Utils::ReadPin(mu8_MisoPin)) { x |= i; } Utils::WritePin(mu8_ClkPin, LOW); diff --git a/src/PN532.h b/src/PN532.h index 18e208ba..ff88eace 100644 --- a/src/PN532.h +++ b/src/PN532.h @@ -1,4 +1,3 @@ - #ifndef ADAFRUIT_PN532_H #define ADAFRUIT_PN532_H @@ -88,11 +87,11 @@ #define PN532_GPIO_P35 (0x20) #define PN532_GPIO_VALIDATIONBIT (0x80) -#define CARD_TYPE_106KB_ISO14443A (0x00) // card baudrate 106 kB -#define CARD_TYPE_212KB_FELICA (0x01) // card baudrate 212 kB -#define CARD_TYPE_424KB_FELICA (0x02) // card baudrate 424 kB -#define CARD_TYPE_106KB_ISO14443B (0x03) // card baudrate 106 kB -#define CARD_TYPE_106KB_JEWEL (0x04) // card baudrate 106 kB +#define CARD_TYPE_106KB_ISO14443A (0x00) // card baudrate 106 kB +#define CARD_TYPE_212KB_FELICA (0x01) // card baudrate 212 kB +#define CARD_TYPE_424KB_FELICA (0x02) // card baudrate 424 kB +#define CARD_TYPE_106KB_ISO14443B (0x03) // card baudrate 106 kB +#define CARD_TYPE_106KB_JEWEL (0x04) // card baudrate 106 kB // Prefixes for NDEF Records (to identify record type), not used #define NDEF_URIPREFIX_NONE (0x00) @@ -132,11 +131,10 @@ #define NDEF_URIPREFIX_URN_EPC (0x22) #define NDEF_URIPREFIX_URN_NFC (0x23) -enum eCardType -{ - CARD_Unknown = 0, // Mifare Classic or other card - CARD_Desfire = 1, // A Desfire card with normal 7 byte UID (bit 0) - CARD_DesRandom = 3, // A Desfire card with 4 byte random UID (bit 0 + 1) +enum eCardType { + CARD_Unknown = 0, // Mifare Classic or other card + CARD_Desfire = 1, // A Desfire card with normal 7 byte UID (bit 0) + CARD_DesRandom = 3, // A Desfire card with 4 byte random UID (bit 0 + 1) }; class PN532 @@ -154,7 +152,7 @@ class PN532 void InitI2C(byte u8_Reset); #endif - // Generic PN532 functions +// Generic PN532 functions void begin(); void SetDebugLevel(byte level); bool SamConfig(); @@ -165,14 +163,14 @@ class PN532 bool ReleaseCard(); bool SelectCard(); - // This function is overridden in Desfire.cpp +// This function is overridden in Desfire.cpp virtual bool SwitchOffRfField(); - // ISO14443A functions +// ISO14443A functions bool ReadPassiveTargetID(byte *uidBuffer, byte *uidLength, eCardType *pe_CardType); protected: - // Low Level functions +// Low Level functions bool CheckPN532Status(byte u8_Status); bool SendCommandCheckAck(byte *cmd, byte cmdlen); byte ReadData(byte *buff, byte len); diff --git a/src/Utils.cpp b/src/Utils.cpp index a0b99e73..ef32746e 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,8 +1,8 @@ /************************************************************************** - - @author Elmü - class Utils: Some small functions. - +* +* @author Elmü +* class Utils: Some small functions. +* **************************************************************************/ #include "Utils.h" @@ -11,30 +11,35 @@ void Utils::Print(const char *s8_Text, const char *s8_LF) //=NULL { SerialClass::Print(s8_Text); - if (s8_LF) + if (s8_LF) { SerialClass::Print(s8_LF); + } } void Utils::PrintDec(int s32_Data, const char *s8_LF) // =NULL { char s8_Buf[20]; + sprintf(s8_Buf, "%d", s32_Data); Print(s8_Buf, s8_LF); } void Utils::PrintHex8(byte u8_Data, const char *s8_LF) // =NULL { char s8_Buf[20]; + sprintf(s8_Buf, "%02X", u8_Data); Print(s8_Buf, s8_LF); } void Utils::PrintHex16(uint16_t u16_Data, const char *s8_LF) // =NULL { char s8_Buf[20]; + sprintf(s8_Buf, "%04X", u16_Data); Print(s8_Buf, s8_LF); } void Utils::PrintHex32(uint32_t u32_Data, const char *s8_LF) // =NULL { char s8_Buf[20]; + sprintf(s8_Buf, "%08X", (unsigned int)u32_Data); Print(s8_Buf, s8_LF); } @@ -45,33 +50,39 @@ void Utils::PrintHex32(uint32_t u32_Data, const char *s8_LF) // =NULL // Output will look like: "00 00 FF 03 FD E0 00" // This is used to mark the data bytes in the packet. // If the parameters s32_Brace1, s32_Brace2 are -1, they do not appear -void Utils::PrintHexBuf(const byte *u8_Data, const uint32_t u32_DataLen, const char *s8_LF, int s32_Brace1, int s32_Brace2) +void Utils::PrintHexBuf(const byte *u8_Data, const uint32_t u32_DataLen, const char *s8_LF, int s32_Brace1, + int s32_Brace2) { - for (uint32_t i = 0; i < u32_DataLen; i++) - { - if ((int)i == s32_Brace1) + for (uint32_t i = 0; i < u32_DataLen; i++) { + if ((int)i == s32_Brace1) { Print(" <"); - else if ((int)i == s32_Brace2) + } else if ((int)i == s32_Brace2) { Print("> "); - else if (i > 0) + } else if (i > 0) { Print(" "); + } PrintHex8(u8_Data[i]); } - if (s8_LF) + if (s8_LF) { Print(s8_LF); + } } // Converts an interval in milliseconds into days, hours, minutes and prints it void Utils::PrintInterval(uint64_t u64_Time, const char *s8_LF) { char Buf[30]; + u64_Time /= 60 * 1000; int s32_Min = (int)(u64_Time % 60); + u64_Time /= 60; int s32_Hour = (int)(u64_Time % 24); + u64_Time /= 24; int s32_Days = (int)u64_Time; + sprintf(Buf, "%d days, %02d:%02d hours", s32_Days, s32_Hour, s32_Min); Print(Buf, s8_LF); } @@ -85,11 +96,13 @@ uint64_t Utils::GetMillis64() uint32_t u32_Now = GetMillis(); // starts at zero after CPU reset // Check for roll-over - if (u32_Now < u32_Last) + if (u32_Now < u32_Last) { u32_High++; + } u32_Last = u32_Now; uint64_t u64_Time = u32_High; + u64_Time <<= 32; u64_Time |= u32_Now; return u64_Time; @@ -99,8 +112,7 @@ uint64_t Utils::GetMillis64() // If u8_Out and u8_In are the same buffer use the other function below. void Utils::XorDataBlock(byte *u8_Out, const byte *u8_In, const byte *u8_Xor, int s32_Length) { - for (int B = 0; B < s32_Length; B++) - { + for (int B = 0; B < s32_Length; B++) { u8_Out[B] = u8_In[B] ^ u8_Xor[B]; } } @@ -108,8 +120,7 @@ void Utils::XorDataBlock(byte *u8_Out, const byte *u8_In, const byte *u8_Xor, in // Multi byte XOR operation in the same buffer void Utils::XorDataBlock(byte *u8_Data, const byte *u8_Xor, int s32_Length) { - for (int B = 0; B < s32_Length; B++) - { + for (int B = 0; B < s32_Length; B++) { u8_Data[B] ^= u8_Xor[B]; } } @@ -119,6 +130,7 @@ void Utils::XorDataBlock(byte *u8_Data, const byte *u8_Xor, int s32_Length) void Utils::RotateBlockLeft(byte *u8_Out, const byte *u8_In, int s32_Length) { int s32_Last = s32_Length - 1; + memcpy(u8_Out, u8_In + 1, s32_Last); u8_Out[s32_Last] = u8_In[0]; } @@ -126,8 +138,7 @@ void Utils::RotateBlockLeft(byte *u8_Out, const byte *u8_In, int s32_Length) // Logical Bit Shift Left. Shift MSB out, and place a 0 at LSB position void Utils::BitShiftLeft(uint8_t *u8_Data, int s32_Length) { - for (int n = 0; n < s32_Length - 1; n++) - { + for (int n = 0; n < s32_Length - 1; n++) { u8_Data[n] = (u8_Data[n] << 1) | (u8_Data[n + 1] >> 7); } u8_Data[s32_Length - 1] <<= 1; @@ -137,8 +148,8 @@ void Utils::BitShiftLeft(uint8_t *u8_Data, int s32_Length) void Utils::GenerateRandom(byte *u8_Random, int s32_Length) { uint32_t u32_Now = GetMillis(); - for (int i = 0; i < s32_Length; i++) - { + + for (int i = 0; i < s32_Length; i++) { u8_Random[i] = (byte)u32_Now; u32_Now *= 127773; u32_Now += 16807; @@ -150,8 +161,8 @@ void Utils::GenerateRandom(byte *u8_Random, int s32_Length) uint16_t Utils::CalcCrc16(const byte *u8_Data, int s32_Length) { uint16_t u16_Crc = 0x6363; - for (int i = 0; i < s32_Length; i++) - { + + for (int i = 0; i < s32_Length; i++) { byte ch = u8_Data[i]; ch = ch ^ (byte)u16_Crc; ch = ch ^ (ch << 4); @@ -163,10 +174,11 @@ uint16_t Utils::CalcCrc16(const byte *u8_Data, int s32_Length) // This CRC is used for ISO and AES authentication. // The new Desfire EV1 authentication calculates the CRC32 also over the command, but the command is not encrypted later. // This function allows to include the command into the calculation without the need to add the command to the same buffer that is later encrypted. -uint32_t Utils::CalcCrc32(const byte *u8_Data1, int s32_Length1, // data to process - const byte *u8_Data2, int s32_Length2) // optional additional data to process (these parameters may be omitted) +uint32_t Utils::CalcCrc32(const byte *u8_Data1, int s32_Length1, // data to process + const byte *u8_Data2, int s32_Length2) // optional additional data to process (these parameters may be omitted) { uint32_t u32_Crc = 0xFFFFFFFF; + u32_Crc = CalcCrc32(u8_Data1, s32_Length1, u32_Crc); u32_Crc = CalcCrc32(u8_Data2, s32_Length2, u32_Crc); return u32_Crc; @@ -175,15 +187,14 @@ uint32_t Utils::CalcCrc32(const byte *u8_Data1, int s32_Length1, // data to proc // private uint32_t Utils::CalcCrc32(const byte *u8_Data, int s32_Length, uint32_t u32_Crc) { - for (int i = 0; i < s32_Length; i++) - { + for (int i = 0; i < s32_Length; i++) { u32_Crc ^= u8_Data[i]; - for (int b = 0; b < 8; b++) - { + for (int b = 0; b < 8; b++) { bool b_Bit = (u32_Crc & 0x01) > 0; u32_Crc >>= 1; - if (b_Bit) + if (b_Bit) { u32_Crc ^= 0xEDB88320; + } } } return u32_Crc; @@ -201,21 +212,26 @@ int Utils::strnicmp(const char *str1, const char *str2, uint32_t u32_MaxCount) { byte c1 = 0; byte c2 = 0; - for (uint32_t i = 0; i < u32_MaxCount; i++) - { + + for (uint32_t i = 0; i < u32_MaxCount; i++) { c1 = str1[i]; c2 = str2[i]; - if (c1 >= 'a' && c1 <= 'z') + if (c1 >= 'a' && c1 <= 'z') { c1 -= 32; // make upper case - if (c2 >= 'a' && c2 <= 'z') + } + if (c2 >= 'a' && c2 <= 'z') { c2 -= 32; - if (c1 != c2 || c1 == 0) + } + if (c1 != c2 || c1 == 0) { break; + } } - if (c1 < c2) + if (c1 < c2) { return -1; - if (c1 > c2) + } + if (c1 > c2) { return 1; + } return 0; } -// ----------------------------------------------------------------------------------------------- \ No newline at end of file +// ----------------------------------------------------------------------------------------------- diff --git a/src/Utils.h b/src/Utils.h index 6e1967fe..28562645 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,4 +1,3 @@ - #ifndef UTILS_H #define UTILS_H @@ -21,15 +20,15 @@ // ATTENTION: Only one of the following defines must be set to true! // NOTE: In Software SPI mode there is no external libraray required. Only 4 regular digital pins are used. // If you want to transfer the code to another processor the easiest way will be to use Software SPI mode. -#define USE_SOFTWARE_SPI TRUE // Visual Studio needs this in upper case -#define USE_HARDWARE_SPI FALSE // Visual Studio needs this in upper case -#define USE_HARDWARE_I2C FALSE // Visual Studio needs this in upper case +#define USE_SOFTWARE_SPI TRUE // Visual Studio needs this in upper case +#define USE_HARDWARE_SPI FALSE // Visual Studio needs this in upper case +#define USE_HARDWARE_I2C FALSE // Visual Studio needs this in upper case // ********************************************************************************/ #if USE_HARDWARE_SPI -#include // Hardware SPI bus +#include // Hardware SPI bus #elif USE_HARDWARE_I2C -#include // Hardware I2C bus +#include // Hardware I2C bus #elif USE_SOFTWARE_SPI // no #include required #else @@ -53,25 +52,36 @@ class SerialClass { public: - // Create a COM connection via USB. - // Teensy ignores the baudrate parameter (only for older Arduino boards) + /* + * Create a COM connection via USB. + * Teensy ignores the baudrate parameter (only for older Arduino boards) + */ static inline void Begin(uint32_t u32_Baud) { Serial.begin(u32_Baud); } - // returns how many characters the user has typed in the Terminal program on the PC which have not yet been read with Read() + + /* + * returns how many characters the user has typed in the Terminal program on the PC which have not yet been read with Read() + */ static inline int Available() { return Serial.available(); } - // Get the next character from the Terminal program on the PC - // returns -1 if no character available + + /* + * Get the next character from the Terminal program on the PC + * returns -1 if no character available + */ static inline int Read() { return Serial.read(); } - // Print text to the Terminal program on the PC - // On Windows/Linux use printf() here to write debug output an errors to the Console. + + /* + * Print text to the Terminal program on the PC + * On Windows/Linux use printf() here to write debug output an errors to the Console. + */ static inline void Print(const char *s8_Text) { Serial.print(s8_Text); @@ -91,7 +101,10 @@ class SpiClass SPI.begin(); SPI.beginTransaction(SPISettings(u32_Clock, LSBFIRST, SPI_MODE0)); } - // Write one byte to the MOSI pin and at the same time receive one byte on the MISO pin. + + /* + * Write one byte to the MOSI pin and at the same time receive one byte on the MISO pin. + */ static inline byte Transfer(byte u8_Data) { return SPI.transfer(u8_Data); @@ -107,36 +120,52 @@ class SpiClass class I2cClass { public: - // Initialize the I2C pins + /* + * Initialize the I2C pins + */ static inline void Begin() { Wire.begin(); } - // --------------------- READ ------------------------- - // Read the requested amount of bytes at once from the I2C bus into an internal buffer. - // ATTENTION: The Arduino library is extremely primitive. A timeout has not been implemented. - // When the CLK line is permanently low this function hangs forever! + /* + * --------------------- READ ------------------------- + * Read the requested amount of bytes at once from the I2C bus into an internal buffer. + * ATTENTION: The Arduino library is extremely primitive. A timeout has not been implemented. + * When the CLK line is permanently low this function hangs forever! + */ static inline byte RequestFrom(byte u8_Address, byte u8_Quantity) { return Wire.requestFrom(u8_Address, u8_Quantity); } - // Read one byte from the buffer that has been read when calling RequestFrom() + + /* + * Read one byte from the buffer that has been read when calling RequestFrom() + */ static inline int Read() { return Wire.read(); } - // --------------------- WRITE ------------------------- - // Initiates a Send transmission + + /* + * --------------------- WRITE ------------------------- + * Initiates a Send transmission + */ static inline void BeginTransmission(byte u8_Address) { Wire.beginTransmission(u8_Address); } - // Write one byte to the I2C bus + + /* + * Write one byte to the I2C bus + */ static inline void Write(byte u8_Data) { Wire.write(u8_Data); } - // Ends a Send transmission + + /* + * Ends a Send transmission + */ static inline void EndTransmission() { Wire.endTransmission(); @@ -144,50 +173,62 @@ class I2cClass }; #endif -// ------------------------------------------------------------------------------------------------------------------- +// ------------------------------------------------------------------------------------------------------------------- class Utils { public: - // returns the current tick counter - // If you compile on Visual Studio see WinDefines.h + /* + * returns the current tick counter + * If you compile on Visual Studio see WinDefines.h + */ static inline uint32_t GetMillis() { return millis(); } - // If you compile on Visual Studio see WinDefines.h + /* + * If you compile on Visual Studio see WinDefines.h + */ static inline void DelayMilli(int s32_MilliSeconds) { delay(s32_MilliSeconds); } - // This function is only required for Software SPI mode. - // If you compile on Visual Studio see WinDefines.h + /* + * This function is only required for Software SPI mode. + * If you compile on Visual Studio see WinDefines.h + */ static inline void DelayMicro(int s32_MicroSeconds) { delayMicroseconds(s32_MicroSeconds); } - // Defines if a digital processor pin is used as input or output - // u8_Mode = INPUT or OUTPUT - // If you compile on Visual Studio see WinDefines.h + /* + * Defines if a digital processor pin is used as input or output + * u8_Mode = INPUT or OUTPUT + * If you compile on Visual Studio see WinDefines.h + */ static inline void SetPinMode(byte u8_Pin, byte u8_Mode) { pinMode(u8_Pin, u8_Mode); } - // Sets a digital processor pin high or low. - // u8_Status = HIGH or LOW - // If you compile on Visual Studio see WinDefines.h + /* + * Sets a digital processor pin high or low. + * u8_Status = HIGH or LOW + * If you compile on Visual Studio see WinDefines.h + */ static inline void WritePin(byte u8_Pin, byte u8_Status) { digitalWrite(u8_Pin, u8_Status); } - // reads the current state of a digital processor pin. - // returns HIGH or LOW - // If you compile on Visual Studio see WinDefines.h + /* + * reads the current state of a digital processor pin. + * returns HIGH or LOW + * If you compile on Visual Studio see WinDefines.h + */ static inline byte ReadPin(byte u8_Pin) { return digitalRead(u8_Pin); @@ -199,7 +240,9 @@ class Utils static void PrintHex8(byte u8_Data, const char *s8_LF = NULL); static void PrintHex16(uint16_t u16_Data, const char *s8_LF = NULL); static void PrintHex32(uint32_t u32_Data, const char *s8_LF = NULL); - static void PrintHexBuf(const byte *u8_Data, const uint32_t u32_DataLen, const char *s8_LF = NULL, int s32_Brace1 = -1, int S32_Brace2 = -1); + static void PrintHexBuf(const byte *u8_Data, const uint32_t u32_DataLen, const char *s8_LF = NULL, + int s32_Brace1 = -1, + int S32_Brace2 = -1); static void PrintInterval(uint64_t u64_Time, const char *s8_LF = NULL); static void GenerateRandom(byte *u8_Random, int s32_Length); static void RotateBlockLeft(byte *u8_Out, const byte *u8_In, int s32_Length); diff --git a/src/beeper.esp b/src/beeper.esp index a6686ad4..77242f71 100644 --- a/src/beeper.esp +++ b/src/beeper.esp @@ -3,67 +3,60 @@ unsigned int beeperOffTime = 0; void beeperBeep() { - if (config.beeperpin != 255) - { - if (currentMillis > beeperOffTime && digitalRead(config.beeperpin) == BEEPERon) - { - digitalWrite(config.beeperpin, BEEPERoff); + if (config.beeperpin != 255) { + if (currentMillis > beeperOffTime && digitalRead(config.beeperpin) == BEEPERon) { + digitalWrite(config.beeperpin, BEEPERoff); #ifdef DEBUG - Serial.println("Beeper OFF"); + Serial.println("Beeper OFF"); #endif - beeperInterval = 0; - } - else if (beeperInterval != 0) - { - int beeperState = digitalRead(config.beeperpin); - if (currentMillis - previousMillis >= beeperInterval) - { - previousMillis = currentMillis; - if (beeperState == BEEPERon) { - beeperState = BEEPERoff; + beeperInterval = 0; + } else if (beeperInterval != 0) { + int beeperState = digitalRead(config.beeperpin); + if (currentMillis - previousMillis >= beeperInterval) { + previousMillis = currentMillis; + if (beeperState == BEEPERon) { + beeperState = BEEPERoff; #ifdef DEBUG - Serial.println("Beeper OFF"); + Serial.println("Beeper OFF"); #endif - } else { - beeperState = BEEPERon; + } else { + beeperState = BEEPERon; #ifdef DEBUG - Serial.println("Beeper ON"); + Serial.println("Beeper ON"); #endif - } - digitalWrite(config.beeperpin, beeperState); - } - } - } + } + digitalWrite(config.beeperpin, beeperState); + } + } + } } void beeperValidAccess() { - if (config.beeperpin != 255) - { - beeperOffTime = currentMillis + 2000; - digitalWrite(config.beeperpin, BEEPERon); + if (config.beeperpin != 255) { + beeperOffTime = currentMillis + 2000; + digitalWrite(config.beeperpin, BEEPERon); #ifdef DEBUG - Serial.println("Beeper ON"); + Serial.println("Beeper ON"); #endif - } + } } void beeperAdminAccess() { - if (config.beeperpin != 255) { - beeperOffTime = currentMillis + 3000; - digitalWrite(config.beeperpin, BEEPERon); + if (config.beeperpin != 255) { + beeperOffTime = currentMillis + 3000; + digitalWrite(config.beeperpin, BEEPERon); #ifdef DEBUG - Serial.println("Beeper ON"); + Serial.println("Beeper ON"); #endif - } + } } void beeperAccessDenied() { - if (config.beeperpin != 255) - { - beeperOffTime = currentMillis + 1000; - beeperInterval = 200; - } + if (config.beeperpin != 255) { + beeperOffTime = currentMillis + 1000; + beeperInterval = 200; + } } diff --git a/src/config.esp b/src/config.esp index 181693d6..7af11d71 100644 --- a/src/config.esp +++ b/src/config.esp @@ -1,254 +1,225 @@ bool ICACHE_FLASH_ATTR loadConfiguration(Config &config) { - File configFile = SPIFFS.open("/config.json", "r"); - if (!configFile) - { + File configFile = SPIFFS.open("/config.json", "r"); + + if (!configFile) { #ifdef DEBUG - Serial.println(F("[ WARN ] Failed to open config file")); + Serial.println(F("[ WARN ] Failed to open config file")); #endif - return false; - } - size_t size = configFile.size(); - std::unique_ptr buf(new char[size]); - configFile.readBytes(buf.get(), size); - DynamicJsonDocument json(8192); - auto error = deserializeJson(json, buf.get()); - if (error) - { + return false; + } + size_t size = configFile.size(); + std::unique_ptr < char[] > buf(new char[size]); + configFile.readBytes(buf.get(), size); + DynamicJsonDocument json(8192); + auto error = deserializeJson(json, buf.get()); + if (error) { #ifdef DEBUG - Serial.println(F("[ WARN ] Failed to parse config file")); + Serial.println(F("[ WARN ] Failed to parse config file")); #endif - return false; - } + return false; + } #ifdef DEBUG - Serial.println(F("[ INFO ] Config file found")); + Serial.println(F("[ INFO ] Config file found")); #endif - JsonObject network = json["network"]; - JsonObject hardware = json["hardware"]; - JsonObject general = json["general"]; - JsonObject mqtt = json["mqtt"]; - JsonObject ntp = json["ntp"]; + JsonObject network = json["network"]; + JsonObject hardware = json["hardware"]; + JsonObject general = json["general"]; + JsonObject mqtt = json["mqtt"]; + JsonObject ntp = json["ntp"]; #ifdef DEBUG - Serial.println(F("[ INFO ] Trying to setup RFID Hardware")); + Serial.println(F("[ INFO ] Trying to setup RFID Hardware")); #endif - if (hardware.containsKey("wifipin")) - { - config.wifipin = hardware["wifipin"]; - if (config.wifipin != 255) - { - pinMode(config.wifipin, OUTPUT); - digitalWrite(config.wifipin, LEDoff); - } - } - - if (hardware.containsKey("doorstatpin")) - { - config.doorstatpin = hardware["doorstatpin"]; - if (config.doorstatpin != 255) - { - pinMode(config.doorstatpin, INPUT); - } - } - - if (hardware.containsKey("maxOpenDoorTime")) - { - config.maxOpenDoorTime = hardware["maxOpenDoorTime"]; - } - - if (hardware.containsKey("doorbellpin")) - { - config.doorbellpin = hardware["doorbellpin"]; - if (config.doorbellpin != 255) - { - pinMode(config.doorbellpin, INPUT); - } - } - - if (hardware.containsKey("accessdeniedpin")) - { - config.accessdeniedpin = hardware["accessdeniedpin"]; - if (config.accessdeniedpin != 255) - { - pinMode(config.accessdeniedpin, OUTPUT); - digitalWrite(config.accessdeniedpin, LOW); - } - } - - if (hardware.containsKey("beeperpin")) - { - config.beeperpin = hardware["beeperpin"]; - if (config.beeperpin != 255) - { - pinMode(config.beeperpin, OUTPUT); - digitalWrite(config.beeperpin, BEEPERoff); - } - } - - if (hardware.containsKey("ledwaitingpin")) - { - config.ledwaitingpin = hardware["ledwaitingpin"]; - if (config.ledwaitingpin != 255) - { - pinMode(config.ledwaitingpin, OUTPUT); - digitalWrite(config.ledwaitingpin, LEDoff); - } - } - - if (hardware.containsKey("openlockpin")) - { - config.openlockpin = hardware["openlockpin"]; - if (config.openlockpin != 255) - { - openLockButton = Bounce(); - openLockButton.attach(config.openlockpin, INPUT_PULLUP); - openLockButton.interval(30); - } - } - - if (hardware.containsKey("numrelays")) - { - config.numRelays = hardware["numrelays"]; - } - else - config.numRelays = 1; + if (hardware.containsKey("wifipin")) { + config.wifipin = hardware["wifipin"]; + if (config.wifipin != 255) { + pinMode(config.wifipin, OUTPUT); + digitalWrite(config.wifipin, LEDoff); + } + } + + if (hardware.containsKey("doorstatpin")) { + config.doorstatpin = hardware["doorstatpin"]; + if (config.doorstatpin != 255) { + pinMode(config.doorstatpin, INPUT); + } + } + + if (hardware.containsKey("maxOpenDoorTime")) { + config.maxOpenDoorTime = hardware["maxOpenDoorTime"]; + } + + if (hardware.containsKey("doorbellpin")) { + config.doorbellpin = hardware["doorbellpin"]; + if (config.doorbellpin != 255) { + pinMode(config.doorbellpin, INPUT); + } + } + + if (hardware.containsKey("accessdeniedpin")) { + config.accessdeniedpin = hardware["accessdeniedpin"]; + if (config.accessdeniedpin != 255) { + pinMode(config.accessdeniedpin, OUTPUT); + digitalWrite(config.accessdeniedpin, LOW); + } + } + + if (hardware.containsKey("beeperpin")) { + config.beeperpin = hardware["beeperpin"]; + if (config.beeperpin != 255) { + pinMode(config.beeperpin, OUTPUT); + digitalWrite(config.beeperpin, BEEPERoff); + } + } + + if (hardware.containsKey("ledwaitingpin")) { + config.ledwaitingpin = hardware["ledwaitingpin"]; + if (config.ledwaitingpin != 255) { + pinMode(config.ledwaitingpin, OUTPUT); + digitalWrite(config.ledwaitingpin, LEDoff); + } + } + + if (hardware.containsKey("openlockpin")) { + config.openlockpin = hardware["openlockpin"]; + if (config.openlockpin != 255) { + openLockButton = Bounce(); + openLockButton.attach(config.openlockpin, INPUT_PULLUP); + openLockButton.interval(30); + } + } + + if (hardware.containsKey("numrelays")) { + config.numRelays = hardware["numrelays"]; + } else { + config.numRelays = 1; + } #ifdef OFFICIALBOARD - config.pinCodeRequested = hardware["pincoderequested"]; - setupWiegandReader(5, 4); + config.pinCodeRequested = hardware["pincoderequested"]; + setupWiegandReader(5, 4); #endif #ifndef OFFICIALBOARD - config.readertype = hardware["readertype"]; - int rfidss; - if (config.readertype == READER_WIEGAND || config.readertype == READER_WIEGAND_RDM6300) - { - int wgd0pin = hardware["wgd0pin"]; - int wgd1pin = hardware["wgd1pin"]; - config.pinCodeRequested = hardware["pincoderequested"]; - setupWiegandReader(wgd0pin, wgd1pin); // also some other settings like weather to use keypad or not, LED pin, BUZZER pin, Wiegand 26/34 version - } - else if (config.readertype == READER_MFRC522 || config.readertype == READER_MFRC522_RDM6300) - { - rfidss = 15; - if (hardware.containsKey("sspin")) - { - rfidss = hardware["sspin"]; - } - int rfidgain = hardware["rfidgain"]; - setupMFRC522Reader(rfidss, rfidgain); - } - else if (config.readertype == READER_PN532 || config.readertype == READER_PN532_RDM6300) - { - rfidss = hardware["sspin"]; - setupPN532Reader(rfidss); - } + config.readertype = hardware["readertype"]; + int rfidss; + if (config.readertype == READER_WIEGAND || config.readertype == READER_WIEGAND_RDM6300) { + int wgd0pin = hardware["wgd0pin"]; + int wgd1pin = hardware["wgd1pin"]; + config.pinCodeRequested = hardware["pincoderequested"]; + setupWiegandReader(wgd0pin, wgd1pin); // also some other settings like weather to use keypad or not, LED pin, BUZZER pin, Wiegand 26/34 version + } else if (config.readertype == READER_MFRC522 || config.readertype == READER_MFRC522_RDM6300) { + rfidss = 15; + if (hardware.containsKey("sspin")) { + rfidss = hardware["sspin"]; + } + int rfidgain = hardware["rfidgain"]; + setupMFRC522Reader(rfidss, rfidgain); + } else if (config.readertype == READER_PN532 || config.readertype == READER_PN532_RDM6300) { + rfidss = hardware["sspin"]; + setupPN532Reader(rfidss); + } #ifndef DEBUG - if (config.readertype > 2) - Serial.begin(9600); + if (config.readertype > 2) { + Serial.begin(9600); + } #endif #endif - config.fallbackMode = network["fallbackmode"] == 1; - config.autoRestartIntervalSeconds = general["restart"]; - config.wifiTimeout = network["offtime"]; - const char *bssidmac = network["bssid"]; - if (strlen(bssidmac) > 0) - parseBytes(bssidmac, ':', config.bssid, 6, 16); - config.deviceHostname = strdup(general["hostnm"]); - config.ntpServer = strdup(ntp["server"]); - config.ntpInterval = ntp["interval"]; - config.timeZone = ntp["timezone"]; - config.activateTime[0] = hardware["rtime"]; - config.lockType[0] = hardware["ltype"]; - config.relayType[0] = hardware["rtype"]; + config.fallbackMode = network["fallbackmode"] == 1; + config.autoRestartIntervalSeconds = general["restart"]; + config.wifiTimeout = network["offtime"]; + const char *bssidmac = network["bssid"]; + if (strlen(bssidmac) > 0) { + parseBytes(bssidmac, ':', config.bssid, 6, 16); + } + config.deviceHostname = strdup(general["hostnm"]); + config.ntpServer = strdup(ntp["server"]); + config.ntpInterval = ntp["interval"]; + config.timeZone = ntp["timezone"]; + config.activateTime[0] = hardware["rtime"]; + config.lockType[0] = hardware["ltype"]; + config.relayType[0] = hardware["rtype"]; #ifndef OFFICIALBOARD - config.relayPin[0] = hardware["rpin"]; - pinMode(config.relayPin[0], OUTPUT); - digitalWrite(config.relayPin[0], !config.relayType[0]); - - for (int i = 1; i < config.numRelays; i++) - { - JsonObject relay = hardware["relay" + String((i + 1))]; - config.activateTime[i] = relay["rtime"]; - config.lockType[i] = relay["ltype"]; - config.relayType[i] = relay["rtype"]; - config.relayPin[i] = relay["rpin"]; - pinMode(config.relayPin[i], OUTPUT); - digitalWrite(config.relayPin[i], !config.relayType[i]); - } + config.relayPin[0] = hardware["rpin"]; + pinMode(config.relayPin[0], OUTPUT); + digitalWrite(config.relayPin[0], !config.relayType[0]); + + for (int i = 1; i < config.numRelays; i++) { + JsonObject relay = hardware["relay" + String((i + 1))]; + config.activateTime[i] = relay["rtime"]; + config.lockType[i] = relay["ltype"]; + config.relayType[i] = relay["rtype"]; + config.relayPin[i] = relay["rpin"]; + pinMode(config.relayPin[i], OUTPUT); + digitalWrite(config.relayPin[i], !config.relayType[i]); + } #endif - config.ssid = strdup(network["ssid"]); - config.wifiPassword = strdup(network["pswd"]); - config.accessPointMode = network["wmode"] == 1; - config.wifiApIp = strdup(network["apip"]); - config.wifiApSubnet = strdup(network["apsubnet"]); - config.networkHidden = network["hide"] == 1; - config.httpPass = strdup(general["pswd"]); - config.dhcpEnabled = network["dhcp"] == 1; - config.ipAddress.fromString(network["ip"].as()); - config.subnetIp.fromString(network["subnet"].as()); - config.gatewayIp.fromString(network["gateway"].as()); - config.dnsIp.fromString(network["dns"].as()); - - const char *apipch; - if (config.wifiApIp) - { - apipch = config.wifiApIp; - } - else - { - apipch = "192.168.4.1"; - } - const char *apsubnetch; - if (config.wifiApSubnet) - { - apsubnetch = config.wifiApSubnet; - } - else - { - apsubnetch = "255.255.255.0"; - } - config.accessPointIp.fromString(apipch); - config.accessPointSubnetIp.fromString(apsubnetch); - - ws.setAuthentication("admin", config.httpPass); - - if (general["openinghours"]) - { - for (int d=0; d<7; d++) - { - config.openingHours[d] = strdup(general["openinghours"][d].as()); - } - } - - config.mqttEnabled = mqtt["enabled"] == 1; - - if (config.mqttEnabled) - { - String mhsString = mqtt["host"]; - config.mqttHost = strdup(mhsString.c_str()); - config.mqttPort = mqtt["port"]; - String muserString = mqtt["user"]; - config.mqttUser = strdup(muserString.c_str()); - String mpasString = mqtt["pswd"]; - config.mqttPass = strdup(mpasString.c_str()); - String mqttTopicString = mqtt["topic"]; - config.mqttTopic = strdup(mqttTopicString.c_str()); - config.mqttInterval = mqtt["syncrate"]; - - if (mqtt["mqttlog"] == 1) - config.mqttEvents = true; - else - config.mqttEvents = false; - - if (mqtt["mqttha"] == 1) - config.mqttHA = true; - else - config.mqttHA = false; - } + config.ssid = strdup(network["ssid"]); + config.wifiPassword = strdup(network["pswd"]); + config.accessPointMode = network["wmode"] == 1; + config.wifiApIp = strdup(network["apip"]); + config.wifiApSubnet = strdup(network["apsubnet"]); + config.networkHidden = network["hide"] == 1; + config.httpPass = strdup(general["pswd"]); + config.dhcpEnabled = network["dhcp"] == 1; + config.ipAddress.fromString(network["ip"].as < const char * > ()); + config.subnetIp.fromString(network["subnet"].as < const char * > ()); + config.gatewayIp.fromString(network["gateway"].as < const char * > ()); + config.dnsIp.fromString(network["dns"].as < const char * > ()); + + const char *apipch; + if (config.wifiApIp) { + apipch = config.wifiApIp; + } else { + apipch = "192.168.4.1"; + } + const char *apsubnetch; + if (config.wifiApSubnet) { + apsubnetch = config.wifiApSubnet; + } else { + apsubnetch = "255.255.255.0"; + } + config.accessPointIp.fromString(apipch); + config.accessPointSubnetIp.fromString(apsubnetch); + + ws.setAuthentication("admin", config.httpPass); + + if (general["openinghours"]) { + for (int d = 0; d < 7; d++) { + config.openingHours[d] = strdup(general["openinghours"][d].as < const char * > ()); + } + } + + config.mqttEnabled = mqtt["enabled"] == 1; + + if (config.mqttEnabled) { + String mhsString = mqtt["host"]; + config.mqttHost = strdup(mhsString.c_str()); + config.mqttPort = mqtt["port"]; + String muserString = mqtt["user"]; + config.mqttUser = strdup(muserString.c_str()); + String mpasString = mqtt["pswd"]; + config.mqttPass = strdup(mpasString.c_str()); + String mqttTopicString = mqtt["topic"]; + config.mqttTopic = strdup(mqttTopicString.c_str()); + config.mqttInterval = mqtt["syncrate"]; + + if (mqtt["mqttlog"] == 1) { + config.mqttEvents = true; + } else { + config.mqttEvents = false; + } + + if (mqtt["mqttha"] == 1) { + config.mqttHA = true; + } else { + config.mqttHA = false; + } + } #ifdef DEBUG - Serial.println(F("[ INFO ] Configuration done.")); + Serial.println(F("[ INFO ] Configuration done.")); #endif - config.present = true; - return true; + config.present = true; + return true; } diff --git a/src/config.h b/src/config.h index c0a6d0f3..28c822c4 100644 --- a/src/config.h +++ b/src/config.h @@ -1,56 +1,56 @@ struct Config { #ifdef OFFICIALBOARD - int relayPin[MAX_NUM_RELAYS] = {13}; + int relayPin[MAX_NUM_RELAYS] = { 13 }; #else - int relayPin[MAX_NUM_RELAYS]; + int relayPin[MAX_NUM_RELAYS]; #endif - uint8_t accessdeniedpin = 255; - bool accessPointMode = false; - IPAddress accessPointIp; - IPAddress accessPointSubnetIp; - unsigned long activateTime[MAX_NUM_RELAYS]; - unsigned long autoRestartIntervalSeconds = 0; - unsigned long beeperInterval = 0; - unsigned long beeperOffTime = 0; - uint8_t beeperpin = 255; - byte bssid[6] = {0, 0, 0, 0, 0, 0}; - char *deviceHostname = NULL; - bool dhcpEnabled = true; - IPAddress dnsIp; - uint8_t doorbellpin = 255; - uint8_t doorstatpin = 255; - bool fallbackMode = false; - IPAddress gatewayIp; - char *httpPass = NULL; - IPAddress ipAddress; - uint8_t ledwaitingpin = 255; - int lockType[MAX_NUM_RELAYS]; - uint8_t maxOpenDoorTime = 0; - bool mqttEnabled = false; - bool mqttEvents = false; // Sends events over MQTT disables SPIFFS file logging - bool mqttHA = false; // Sends events over simple MQTT topics and AutoDiscovery - char *mqttHost = NULL; - unsigned long mqttInterval = 180; // Add to GUI & json config - char *mqttPass = NULL; - int mqttPort; - char *mqttTopic = NULL; - char *mqttUser = NULL; - bool networkHidden = false; - char *ntpServer = NULL; - int ntpInterval = 0; - int numRelays = 1; - char *openingHours[7]; - uint8_t openlockpin = 255; - bool pinCodeRequested; - bool present = false; - int readertype; - int relayType[MAX_NUM_RELAYS]; - IPAddress subnetIp; - const char *ssid; - int timeZone = 0; - const char *wifiApIp = NULL; - const char *wifiApSubnet = NULL; - uint8_t wifipin = 255; - const char *wifiPassword = NULL; - unsigned long wifiTimeout = 0; + uint8_t accessdeniedpin = 255; + bool accessPointMode = false; + IPAddress accessPointIp; + IPAddress accessPointSubnetIp; + unsigned long activateTime[MAX_NUM_RELAYS]; + unsigned long autoRestartIntervalSeconds = 0; + unsigned long beeperInterval = 0; + unsigned long beeperOffTime = 0; + uint8_t beeperpin = 255; + byte bssid[6] = { 0, 0, 0, 0, 0, 0 }; + char * deviceHostname = NULL; + bool dhcpEnabled = true; + IPAddress dnsIp; + uint8_t doorbellpin = 255; + uint8_t doorstatpin = 255; + bool fallbackMode = false; + IPAddress gatewayIp; + char * httpPass = NULL; + IPAddress ipAddress; + uint8_t ledwaitingpin = 255; + int lockType[MAX_NUM_RELAYS]; + uint8_t maxOpenDoorTime = 0; + bool mqttEnabled = false; + bool mqttEvents = false; // Sends events over MQTT disables SPIFFS file logging + bool mqttHA = false; // Sends events over simple MQTT topics and AutoDiscovery + char * mqttHost = NULL; + unsigned long mqttInterval = 180; // Add to GUI & json config + char * mqttPass = NULL; + int mqttPort; + char * mqttTopic = NULL; + char * mqttUser = NULL; + bool networkHidden = false; + char * ntpServer = NULL; + int ntpInterval = 0; + int numRelays = 1; + char * openingHours[7]; + uint8_t openlockpin = 255; + bool pinCodeRequested; + bool present = false; + int readertype; + int relayType[MAX_NUM_RELAYS]; + IPAddress subnetIp; + const char * ssid; + int timeZone = 0; + const char * wifiApIp = NULL; + const char * wifiApSubnet = NULL; + uint8_t wifipin = 255; + const char * wifiPassword = NULL; + unsigned long wifiTimeout = 0; }; diff --git a/src/door.esp b/src/door.esp index 54b9cf7d..aab56af7 100644 --- a/src/door.esp +++ b/src/door.esp @@ -4,59 +4,50 @@ // door status void doorStatus(/* arguments */) { - if (config.doorstatpin == 255) - { - return; - } - - // if this changes and if mqtt and mqtt logging enabled, push the message, also to a web socket! - if ((digitalRead(config.doorstatpin) == HIGH) && (lastDoorState == 0)) - { - writeEvent("INFO", "door", "Door Closed", ""); - if (lastTamperState == 1) - { - lastTamperState = 0; - mqttPublishIo("tamper", "OFF"); + if (config.doorstatpin == 255) { + return; } - mqttPublishIo("door", "OFF"); - lastDoorState = 1; - } - if ((digitalRead(config.doorstatpin) == LOW) && (lastDoorState == 1)) - { - writeEvent("INFO", "door", "Door Open", ""); - if (digitalRead(config.relayPin[0]) == !config.relayType[0]) - { - writeEvent("WARN", "tamper", "Door was tampered!", ""); - lastTamperState = 1; - mqttPublishIo("tamper", "ON"); + // if this changes and if mqtt and mqtt logging enabled, push the message, also to a web socket! + if ((digitalRead(config.doorstatpin) == HIGH) && (lastDoorState == 0)) { + writeEvent("INFO", "door", "Door Closed", ""); + if (lastTamperState == 1) { + lastTamperState = 0; + mqttPublishIo("tamper", "OFF"); + } + mqttPublishIo("door", "OFF"); + lastDoorState = 1; } - else - { - openDoorMillis = currentMillis; + + if ((digitalRead(config.doorstatpin) == LOW) && (lastDoorState == 1)) { + writeEvent("INFO", "door", "Door Open", ""); + if (digitalRead(config.relayPin[0]) == !config.relayType[0]) { + writeEvent("WARN", "tamper", "Door was tampered!", ""); + lastTamperState = 1; + mqttPublishIo("tamper", "ON"); + } else { + openDoorMillis = currentMillis; #ifdef DEBUG - Serial.print("openDoorMillis : "); - Serial.println(openDoorMillis); + Serial.print("openDoorMillis : "); + Serial.println(openDoorMillis); #endif + } + mqttPublishIo("door", "ON"); + lastDoorState = 0; } - mqttPublishIo("door", "ON"); - lastDoorState = 0; - } - if (config.maxOpenDoorTime != 0 && (lastDoorState == 0) && (lastTamperState == 0)) - { - if (currentMillis - openDoorMillis >= config.maxOpenDoorTime*1000) - { + if (config.maxOpenDoorTime != 0 && (lastDoorState == 0) && (lastTamperState == 0)) { + if (currentMillis - openDoorMillis >= config.maxOpenDoorTime * 1000) { #ifdef DEBUG - Serial.print("currentMillis : "); - Serial.println(currentMillis); - Serial.print("delta millis : "); - Serial.println(currentMillis - openDoorMillis); + Serial.print("currentMillis : "); + Serial.println(currentMillis); + Serial.print("delta millis : "); + Serial.println(currentMillis - openDoorMillis); #endif - writeEvent("WARN", "tamper", "Door wasn't closed within max open time!", ""); - lastTamperState = 1; - mqttPublishIo("tamper", "ON"); - } - } - delayMicroseconds(500); + writeEvent("WARN", "tamper", "Door wasn't closed within max open time!", ""); + lastTamperState = 1; + mqttPublishIo("tamper", "ON"); + } + } + delayMicroseconds(500); } diff --git a/src/doorbell.esp b/src/doorbell.esp index 15002df8..ab6b6830 100644 --- a/src/doorbell.esp +++ b/src/doorbell.esp @@ -2,22 +2,19 @@ void doorbellStatus() { - if (config.doorbellpin == 255) - { - return; - } - // if this changes and if mqtt and mqtt logging enabled, push the message, also to a web socket! - if ((digitalRead(config.doorbellpin) == HIGH) && (lastDoorbellState == 0)) - { - writeEvent("INFO", "doorbell", "Doorbell ringing", ""); - mqttPublishIo("doorbell", "ON"); - lastDoorbellState = 1; - } + if (config.doorbellpin == 255) { + return; + } + // if this changes and if mqtt and mqtt logging enabled, push the message, also to a web socket! + if ((digitalRead(config.doorbellpin) == HIGH) && (lastDoorbellState == 0)) { + writeEvent("INFO", "doorbell", "Doorbell ringing", ""); + mqttPublishIo("doorbell", "ON"); + lastDoorbellState = 1; + } - if ((digitalRead(config.doorbellpin) == LOW) && (lastDoorbellState == 1)) - { - mqttPublishIo("doorbell", "OFF"); - lastDoorbellState = 0; - } - delayMicroseconds(500); + if ((digitalRead(config.doorbellpin) == LOW) && (lastDoorbellState == 1)) { + mqttPublishIo("doorbell", "OFF"); + lastDoorbellState = 0; + } + delayMicroseconds(500); } diff --git a/src/helpers.esp b/src/helpers.esp index 9003fa59..fde1ace8 100644 --- a/src/helpers.esp +++ b/src/helpers.esp @@ -1,43 +1,37 @@ String ICACHE_FLASH_ATTR printIP(IPAddress adress) { - return (String)adress[0] + "." + (String)adress[1] + "." + (String)adress[2] + "." + (String)adress[3]; + return (String)adress[0] + "." + (String)adress[1] + "." + (String)adress[2] + "." + (String)adress[3]; } void ICACHE_FLASH_ATTR parseBytes(const char *str, char sep, byte *bytes, int maxBytes, int base) { - for (int i = 0; i < maxBytes; i++) - { - bytes[i] = strtoul(str, NULL, base); // Convert byte - str = strchr(str, sep); // Find next separator - if (str == NULL || *str == '\0') - { - break; // No more separators, exit - } - str++; // Point to next character after separator - } + for (int i = 0; i < maxBytes; i++) { + bytes[i] = strtoul(str, NULL, base); // Convert byte + str = strchr(str, sep); // Find next separator + if (str == NULL || *str == '\0') { + break; // No more separators, exit + } + str++; // Point to next character after separator + } } String ICACHE_FLASH_ATTR generateUid(int type = 0, int length = 12) { + // nardev: this could be implemented in config, to choose default type of UID; - // nardev: this could be implemented in config, to choose default type of UID; + String uid; - String uid; - if (type) - { - uid = now(); - } - else - { - // char *characters = "abcdefghijklmnopqrstuvwxyz0123456789"; small letters, ordered - // char *characters = "ABSDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; uppercase, ordered - const char *characters = "SN07YXRGP9DBOUVLJK6IEH1FWMT8Q4SA3Z52"; // randomized, uppercase + if (type) { + uid = now(); + } else { + // char *characters = "abcdefghijklmnopqrstuvwxyz0123456789"; small letters, ordered + // char *characters = "ABSDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; uppercase, ordered + const char *characters = "SN07YXRGP9DBOUVLJK6IEH1FWMT8Q4SA3Z52"; // randomized, uppercase - for (int i = 0; i < length; i++) - { - uid = uid + characters[random(0, 36)]; - } - } + for (int i = 0; i < length; i++) { + uid = uid + characters[random(0, 36)]; + } + } - return uid; + return uid; } diff --git a/src/led.esp b/src/led.esp index 241c9d18..cc054a45 100644 --- a/src/led.esp +++ b/src/led.esp @@ -2,88 +2,80 @@ unsigned long accessdeniedOffTime = 0; void ledWaitingOn() { - if (config.ledwaitingpin != 255) - { - digitalWrite(config.ledwaitingpin, LEDon); + if (config.ledwaitingpin != 255) { + digitalWrite(config.ledwaitingpin, LEDon); #ifdef DEBUG - Serial.println("LED waiting ON"); + Serial.println("LED waiting ON"); #endif - } + } } void ledWaitingOff() { - if (config.ledwaitingpin != 255) - { - digitalWrite(config.ledwaitingpin, HIGH); + if (config.ledwaitingpin != 255) { + digitalWrite(config.ledwaitingpin, HIGH); #ifdef DEBUG - Serial.println("LED waiting OFF"); + Serial.println("LED waiting OFF"); #endif - } + } } void ledWifiOn() { - if (config.wifipin != 255) - { - digitalWrite(config.wifipin, LEDon); + if (config.wifipin != 255) { + digitalWrite(config.wifipin, LEDon); #ifdef DEBUG - Serial.println("LED WiFi ON"); + Serial.println("LED WiFi ON"); #endif - } + } } void ledWifiOff() { - if (config.wifipin != 255) - { - digitalWrite(config.wifipin, LEDoff); + if (config.wifipin != 255) { + digitalWrite(config.wifipin, LEDoff); #ifdef DEBUG - Serial.println("LED WiFi OFF"); + Serial.println("LED WiFi OFF"); #endif - } + } } // blink when not connected, on when connected void ledWifiStatus() { - if (config.wifipin != 255 && !config.accessPointMode) - { - if (!WiFi.isConnected()) - { - if ((currentMillis - wifiPinBlink) > 500) - { - wifiPinBlink = currentMillis; - digitalWrite(config.wifipin, !digitalRead(config.wifipin)); - } - } - else - { - if (!(digitalRead(config.wifipin) == LEDon)) - digitalWrite(config.wifipin, LEDon); - } - } + if (config.wifipin != 255 && !config.accessPointMode) { + if (!WiFi.isConnected()) { + if ((currentMillis - wifiPinBlink) > 500) { + wifiPinBlink = currentMillis; + digitalWrite(config.wifipin, !digitalRead(config.wifipin)); + } + } else { + if (!(digitalRead(config.wifipin) == LEDon)) { + digitalWrite(config.wifipin, LEDon); + } + } + } } void ledAccessDeniedOff() { - if (config.accessdeniedpin != 255 && currentMillis > accessdeniedOffTime && digitalRead(config.accessdeniedpin) == LEDon) - { - digitalWrite(config.accessdeniedpin, LEDoff); + if (config.accessdeniedpin != 255 + && currentMillis > accessdeniedOffTime + && digitalRead(config.accessdeniedpin) == LEDon) { + digitalWrite(config.accessdeniedpin, LEDoff); #ifdef DEBUG - Serial.println("LED access denied OFF"); + Serial.println("LED access denied OFF"); #endif - } + } } void ledAccessDeniedOn() { - if (config.accessdeniedpin != 255) - { - accessdeniedOffTime = currentMillis + 1000; - digitalWrite(config.accessdeniedpin, LEDon); + if (config.accessdeniedpin != 255) { + accessdeniedOffTime = currentMillis + 1000; + digitalWrite(config.accessdeniedpin, LEDon); #ifdef DEBUG - Serial.println("LED access denied ON"); + Serial.println("LED access denied ON"); #endif - } + } } diff --git a/src/log.esp b/src/log.esp index 55421bc8..4110d9d6 100644 --- a/src/log.esp +++ b/src/log.esp @@ -2,41 +2,41 @@ void extern mqttPublishEvent(JsonDocument *root); void ICACHE_FLASH_ATTR writeEvent(String type, String src, String desc, String data) { - DynamicJsonDocument root(512); - root["type"] = type; - root["src"] = src; - root["desc"] = desc; - root["data"] = data; - root["time"] = now(); - if (config.mqttEvents && config.mqttEnabled) // log to MQTT - { - root["cmd"] = "event"; - root["hostname"] = config.deviceHostname; - mqttPublishEvent(&root); - } - else // log to file - { - File eventlog = SPIFFS.open("/eventlog.json", "a"); - serializeJson(root, eventlog); - eventlog.print("\n"); - eventlog.close(); - } + DynamicJsonDocument root(512); + + root["type"] = type; + root["src"] = src; + root["desc"] = desc; + root["data"] = data; + root["time"] = now(); + if (config.mqttEvents && config.mqttEnabled) { // log to MQTT + root["cmd"] = "event"; + root["hostname"] = config.deviceHostname; + mqttPublishEvent(&root); + } else { // log to file + File eventlog = SPIFFS.open("/eventlog.json", "a"); + serializeJson(root, eventlog); + eventlog.print("\n"); + eventlog.close(); + } #ifdef DEBUG - Serial.println("[ " + type + " ] " + src + " | " + desc + " | " + data); + Serial.println("[ " + type + " ] " + src + " | " + desc + " | " + data); #endif } void ICACHE_FLASH_ATTR writeLatest(String uid, String username, int acctype) { - DynamicJsonDocument root(512); - root["uid"] = uid; - root["username"] = username; - root["acctype"] = acctype; - root["timestamp"] = now(); - File latestlog = SPIFFS.open("/latestlog.json", "a"); - serializeJson(root, latestlog); - latestlog.print("\n"); - latestlog.close(); + DynamicJsonDocument root(512); + + root["uid"] = uid; + root["username"] = username; + root["acctype"] = acctype; + root["timestamp"] = now(); + File latestlog = SPIFFS.open("/latestlog.json", "a"); + + serializeJson(root, latestlog); + latestlog.print("\n"); + latestlog.close(); } size_t lastPos; // position counter for fast seek @@ -48,222 +48,219 @@ size_t lastPos; // position counter for fast seek void ICACHE_FLASH_ATTR sendLogFile(int page, String fileName, int logFileType) { - - // if we are reading the first page then we reset - // the position counter - - if (page == 1) - lastPos = 0; - float pages; - DynamicJsonDocument root(2048); - if (logFileType == LOGTYPE_EVENTLOG) - root["command"] = "eventlist"; - if (logFileType == LOGTYPE_LATESTLOG) - root["command"] = "latestlist"; - root["page"] = page; - JsonArray items = root.createNestedArray("list"); - - File logFile; - - if (!SPIFFS.exists(fileName)) - { - logFile = SPIFFS.open(fileName, "w"); - logFile.close(); - } - - logFile = SPIFFS.open(fileName, "r"); - - // move the file pointer to the last known position - - logFile.seek(lastPos); - int numLines = 0; - - // read in 10 lines or until EOF whatever happens first - - while (logFile.available() && (numLines < ITEMS_PER_PAGE)) - { - String item = String(); - item = logFile.readStringUntil('\n'); - items.add(item); - numLines++; - } - - // remember the last position - - lastPos = logFile.position(); - - // calculate the number of remaining pages - - if (logFile.available()) // tell bootstrap footable on the client side that there are more pages to come - { - float bytesPerPageRoughly = (lastPos / page); - float totalPagesRoughly = logFile.size() / bytesPerPageRoughly; - pages = totalPagesRoughly <= page ? page + 1 : totalPagesRoughly; - } - else - pages = page; // this was the last page - - logFile.close(); - root["haspages"] = ceil(pages); - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - if (logFileType == LOGTYPE_EVENTLOG) - ws.textAll("{\"command\":\"result\",\"resultof\":\"eventlist\",\"result\": true}"); - if (logFileType == LOGTYPE_LATESTLOG) - ws.textAll("{\"command\":\"result\",\"resultof\":\"latestlist\",\"result\": true}"); - } + // if we are reading the first page then we reset + // the position counter + + if (page == 1) { + lastPos = 0; + } + float pages; + + DynamicJsonDocument root(2048); + + if (logFileType == LOGTYPE_EVENTLOG) { + root["command"] = "eventlist"; + } + if (logFileType == LOGTYPE_LATESTLOG) { + root["command"] = "latestlist"; + } + root["page"] = page; + JsonArray items = root.createNestedArray("list"); + + File logFile; + + if (!SPIFFS.exists(fileName)) { + logFile = SPIFFS.open(fileName, "w"); + logFile.close(); + } + + logFile = SPIFFS.open(fileName, "r"); + + // move the file pointer to the last known position + + logFile.seek(lastPos); + int numLines = 0; + + // read in 10 lines or until EOF whatever happens first + + while (logFile.available() && (numLines < ITEMS_PER_PAGE)) { + String item = String(); + item = logFile.readStringUntil('\n'); + items.add(item); + numLines++; + } + + // remember the last position + + lastPos = logFile.position(); + + // calculate the number of remaining pages + + if (logFile.available()) { // tell bootstrap footable on the client side that there are more pages to come + float bytesPerPageRoughly = (lastPos / page); + float totalPagesRoughly = logFile.size() / bytesPerPageRoughly; + pages = totalPagesRoughly <= page ? page + 1 : totalPagesRoughly; + } else { + pages = page; // this was the last page + } + logFile.close(); + root["haspages"] = ceil(pages); + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); + + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + if (logFileType == LOGTYPE_EVENTLOG) { + ws.textAll("{\"command\":\"result\",\"resultof\":\"eventlist\",\"result\": true}"); + } + if (logFileType == LOGTYPE_LATESTLOG) { + ws.textAll("{\"command\":\"result\",\"resultof\":\"latestlist\",\"result\": true}"); + } + } } void ICACHE_FLASH_ATTR logMaintenance(String action, String filename) { #ifdef DEBUG - Serial.printf("[DEBUG] Log Maintenance Action: %s on %s\n", action.c_str(), filename.c_str()); + Serial.printf("[DEBUG] Log Maintenance Action: %s on %s\n", action.c_str(), filename.c_str()); #endif - // delete a file - - if (action == "delete") - { - SPIFFS.remove(filename); - } - - // rollover a file, i.e. rename - - if (action == "rollover") - { - size_t rolloverExtension = 1; - while (SPIFFS.exists(filename + "." + rolloverExtension)) - rolloverExtension++; - SPIFFS.rename(filename, filename + "." + rolloverExtension); - } - - // split a file, i.e. create two new files of roughly the same size - // or at least as big as SPIFFS free space allows - - if (action == "split") - { - size_t rolloverExtension1 = 1; - while (SPIFFS.exists(filename + ".split." + rolloverExtension1)) - rolloverExtension1++; - size_t rolloverExtension2 = rolloverExtension1 + 1; - while (SPIFFS.exists(filename + ".split." + rolloverExtension2)) - rolloverExtension2++; - - File logFile = SPIFFS.open(filename, "r"); - File newFile1 = SPIFFS.open(filename + ".split." + rolloverExtension1, "w"); - File newFile2 = SPIFFS.open(filename + ".split." + rolloverExtension2, "w"); - - FSInfo fs_info; - SPIFFS.info(fs_info); - - size_t truncatePosition = logFile.size() / 2; - logFile.seek(truncatePosition); - logFile.readStringUntil('\n'); - truncatePosition = logFile.position(); - logFile.seek(0); - - // check if we have enough space for the split operation - - if ((fs_info.totalBytes - fs_info.usedBytes) < (logFile.size() + MIN_SPIFF_BYTES)) - { - ws.textAll("{\"command\":\"result\",\"resultof\":\"logfileMaintenance\",\"result\": false,\"message\":\"Not enough space on SPIFF Filesystem\"}"); - } - else - { - - // mind the watchdog timer - this may take a couple of seconds... - - ESP.wdtDisable(); - ESP.wdtEnable(1500); - - // read the first half of the file - - while (logFile.available() && logFile.position() < truncatePosition) - { - String item = String(); - item = logFile.readStringUntil('\n'); - newFile1.println(item); - ESP.wdtFeed(); // tell the watchdog we're still doing stuff - } - - // read the rest - - while (logFile.available()) - { - String item = String(); - item = logFile.readStringUntil('\n'); - newFile2.println(item); - ESP.wdtFeed(); // no reset please ;-) - } - - logFile.close(); - newFile1.close(); - newFile2.close(); - } - } - - ESP.wdtEnable(5000); - ws.textAll("{\"command\":\"result\",\"resultof\":\"logfileMaintenance\",\"result\": true}"); + // delete a file + + if (action == "delete") { + SPIFFS.remove(filename); + } + + // rollover a file, i.e. rename + + if (action == "rollover") { + size_t rolloverExtension = 1; + while (SPIFFS.exists(filename + "." + rolloverExtension)) { + rolloverExtension++; + } + SPIFFS.rename(filename, filename + "." + rolloverExtension); + } + + // split a file, i.e. create two new files of roughly the same size + // or at least as big as SPIFFS free space allows + + if (action == "split") { + size_t rolloverExtension1 = 1; + while (SPIFFS.exists(filename + ".split." + rolloverExtension1)) { + rolloverExtension1++; + } + size_t rolloverExtension2 = rolloverExtension1 + 1; + while (SPIFFS.exists(filename + ".split." + rolloverExtension2)) { + rolloverExtension2++; + } + + File logFile = SPIFFS.open(filename, "r"); + File newFile1 = SPIFFS.open(filename + ".split." + rolloverExtension1, "w"); + File newFile2 = SPIFFS.open(filename + ".split." + rolloverExtension2, "w"); + + FSInfo fs_info; + SPIFFS.info(fs_info); + + size_t truncatePosition = logFile.size() / 2; + logFile.seek(truncatePosition); + logFile.readStringUntil('\n'); + truncatePosition = logFile.position(); + logFile.seek(0); + + // check if we have enough space for the split operation + + if ((fs_info.totalBytes - fs_info.usedBytes) < (logFile.size() + MIN_SPIFF_BYTES)) { + ws.textAll( + "{\"command\":\"result\",\"resultof\":\"logfileMaintenance\",\"result\": false,\"message\":\"Not enough space on SPIFF Filesystem\"}"); + } else { + // mind the watchdog timer - this may take a couple of seconds... + + ESP.wdtDisable(); + ESP.wdtEnable(1500); + + // read the first half of the file + + while (logFile.available() && logFile.position() < truncatePosition) { + String item = String(); + item = logFile.readStringUntil('\n'); + newFile1.println(item); + ESP.wdtFeed(); // tell the watchdog we're still doing stuff + } + + // read the rest + + while (logFile.available()) { + String item = String(); + item = logFile.readStringUntil('\n'); + newFile2.println(item); + ESP.wdtFeed(); // no reset please ;-) + } + + logFile.close(); + newFile1.close(); + newFile2.close(); + } + } + + ESP.wdtEnable(5000); + ws.textAll("{\"command\":\"result\",\"resultof\":\"logfileMaintenance\",\"result\": true}"); } void ICACHE_FLASH_ATTR sendFileList(int page) { + DynamicJsonDocument root(512); + + root["command"] = "listfiles"; + root["page"] = page; + JsonArray items = root.createNestedArray("list"); + + size_t first = (page - 1) * FILES_PER_PAGE; + size_t last = page * FILES_PER_PAGE; + size_t numFiles = 0; + + Dir dir = SPIFFS.openDir("/"); + + while (dir.next()) { + // if (dir.isFile()) // isFile is implemented in Arduino Core 2.5.1 - We'll have to wait for the ISR not in IRAM fix + + String thisFileName = dir.fileName(); + if ((thisFileName.indexOf("latestlog") >= 0) || (thisFileName.indexOf("eventlog") >= 0)) { // for the time being we just check filenames + if (numFiles >= first && numFiles < last) { + JsonObject item = items.createNestedObject(); + item["filename"] = dir.fileName(); + item["filesize"] = dir.fileSize(); + } // first, last + numFiles++; + } // isFile + } // dir next + + float pages = numFiles / FILES_PER_PAGE; + + root["haspages"] = ceil(pages); + + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - DynamicJsonDocument root(512); - root["command"] = "listfiles"; - root["page"] = page; - JsonArray items = root.createNestedArray("list"); - - size_t first = (page - 1) * FILES_PER_PAGE; - size_t last = page * FILES_PER_PAGE; - size_t numFiles = 0; - - Dir dir = SPIFFS.openDir("/"); - while (dir.next()) - { - - // if (dir.isFile()) // isFile is implemented in Arduino Core 2.5.1 - We'll have to wait for the ISR not in IRAM fix - - String thisFileName = dir.fileName(); - if ((thisFileName.indexOf("latestlog") >= 0) || (thisFileName.indexOf("eventlog") >= 0)) // for the time being we just check filenames - { - if (numFiles >= first && numFiles < last) - { - JsonObject item = items.createNestedObject(); - item["filename"] = dir.fileName(); - item["filesize"] = dir.fileSize(); - } // first, last - numFiles++; - } // isFile - } // dir next - - float pages = numFiles / FILES_PER_PAGE; - root["haspages"] = ceil(pages); - - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - ws.textAll("{\"command\":\"result\",\"resultof\":\"listfiles\",\"result\": true}"); - } + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + ws.textAll("{\"command\":\"result\",\"resultof\":\"listfiles\",\"result\": true}"); + } } void ICACHE_FLASH_ATTR sendEventLog(int page, String fileName) { - if (fileName.length() == 0) - fileName = "/eventlog.json"; - sendLogFile(page, fileName, LOGTYPE_EVENTLOG); + if (fileName.length() == 0) { + fileName = "/eventlog.json"; + } + sendLogFile(page, fileName, LOGTYPE_EVENTLOG); } void ICACHE_FLASH_ATTR sendLatestLog(int page, String fileName) { - if (fileName.length() == 0) - fileName = "/latestlog.json"; - sendLogFile(page, fileName, LOGTYPE_LATESTLOG); + if (fileName.length() == 0) { + fileName = "/latestlog.json"; + } + sendLogFile(page, fileName, LOGTYPE_LATESTLOG); } diff --git a/src/magicnumbers.h b/src/magicnumbers.h index 1c20dd37..759e7296 100644 --- a/src/magicnumbers.h +++ b/src/magicnumbers.h @@ -10,8 +10,8 @@ // timing constants -#define COOLDOWN_MILIS 2000 // Milliseconds the RFID reader will be blocked between inputs -#define KEYBOARD_TIMEOUT_MILIS 10000 // timeout in milis for keyboard input +#define COOLDOWN_MILIS 2000 // Milliseconds the RFID reader will be blocked between inputs +#define KEYBOARD_TIMEOUT_MILIS 10000 // timeout in milis for keyboard input // user related numbers diff --git a/src/main.cpp b/src/main.cpp index 6fe4c2bb..d10f1c28 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,26 +1,26 @@ /* -MIT License - -Copyright (c) 2018 esp-rfid Community -Copyright (c) 2017 Ömer Şiar Baysal - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. + * MIT License + * + * Copyright (c) 2018 esp-rfid Community + * Copyright (c) 2017 Ömer Şiar Baysal + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #define VERSION "1.3.5" @@ -47,8 +47,8 @@ Config config; #include WIEGAND wg; -bool activateRelay[MAX_NUM_RELAYS] = {false}; -bool deactivateRelay[MAX_NUM_RELAYS] = {false}; +bool activateRelay[MAX_NUM_RELAYS] = { false }; +bool deactivateRelay[MAX_NUM_RELAYS] = { false }; #endif @@ -65,8 +65,8 @@ WIEGAND wg; RFID_Reader RFIDr; // relay specific variables -bool activateRelay[MAX_NUM_RELAYS] = {false, false, false, false}; -bool deactivateRelay[MAX_NUM_RELAYS] = {false, false, false, false}; +bool activateRelay[MAX_NUM_RELAYS] = { false, false, false, false }; +bool deactivateRelay[MAX_NUM_RELAYS] = { false, false, false, false }; #endif @@ -133,206 +133,178 @@ unsigned long wiFiUptimeMillis = 0; void ICACHE_FLASH_ATTR setup() { #ifdef OFFICIALBOARD - // Set relay pin to LOW signal as early as possible - pinMode(13, OUTPUT); - digitalWrite(13, LOW); - delay(200); + // Set relay pin to LOW signal as early as possible + pinMode(13, OUTPUT); + digitalWrite(13, LOW); + delay(200); #endif #ifdef DEBUG - Serial.begin(9600); - Serial.println(); - - Serial.print(F("[ INFO ] ESP RFID v")); - Serial.println(VERSION); - - uint32_t realSize = ESP.getFlashChipRealSize(); - uint32_t ideSize = ESP.getFlashChipSize(); - FlashMode_t ideMode = ESP.getFlashChipMode(); - Serial.printf("Flash real id: %08X\n", ESP.getFlashChipId()); - Serial.printf("Flash real size: %u\n\n", realSize); - Serial.printf("Flash ide size: %u\n", ideSize); - Serial.printf("Flash ide speed: %u\n", ESP.getFlashChipSpeed()); - Serial.printf("Flash ide mode: %s\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" - : ideMode == FM_DIO ? "DIO" - : ideMode == FM_DOUT ? "DOUT" - : "UNKNOWN")); - if (ideSize != realSize) - { - Serial.println("Flash Chip configuration wrong!\n"); - } - else - { - Serial.println("Flash Chip configuration ok.\n"); - } + Serial.begin(9600); + Serial.println(); + + Serial.print(F("[ INFO ] ESP RFID v")); + Serial.println(VERSION); + + uint32_t realSize = ESP.getFlashChipRealSize(); + uint32_t ideSize = ESP.getFlashChipSize(); + FlashMode_t ideMode = ESP.getFlashChipMode(); + Serial.printf("Flash real id: %08X\n", ESP.getFlashChipId()); + Serial.printf("Flash real size: %u\n\n", realSize); + Serial.printf("Flash ide size: %u\n", ideSize); + Serial.printf("Flash ide speed: %u\n", ESP.getFlashChipSpeed()); + Serial.printf("Flash ide mode: %s\n", (ideMode == FM_QIO ? "QIO" : ideMode == FM_QOUT ? "QOUT" + : ideMode == FM_DIO ? "DIO" + : ideMode == FM_DOUT ? "DOUT" + : "UNKNOWN")); + if (ideSize != realSize) { + Serial.println("Flash Chip configuration wrong!\n"); + } else { + Serial.println("Flash Chip configuration ok.\n"); + } #endif - if (!SPIFFS.begin()) - { - if (SPIFFS.format()) - { - writeEvent("WARN", "sys", "Filesystem formatted", ""); - } - else - { + if (!SPIFFS.begin()) { + if (SPIFFS.format()) { + writeEvent("WARN", "sys", "Filesystem formatted", ""); + } else { #ifdef DEBUG - Serial.println(F(" failed!")); - Serial.println(F("[ WARN ] Could not format filesystem!")); + Serial.println(F(" failed!")); + Serial.println(F("[ WARN ] Could not format filesystem!")); #endif - } - } - - bool configured = false; - configured = loadConfiguration(config); - setupMqtt(); - setupWebServer(); - setupWifi(configured); - writeEvent("INFO", "sys", "System setup completed, running", ""); + } + } + + bool configured = false; + configured = loadConfiguration(config); + setupMqtt(); + setupWebServer(); + setupWifi(configured); + writeEvent("INFO", "sys", "System setup completed, running", ""); } void ICACHE_RAM_ATTR loop() { - currentMillis = millis(); - deltaTime = currentMillis - previousLoopMillis; - uptime = NTP.getUptimeSec(); - previousLoopMillis = currentMillis; - - openLockButton.update(); - if (openLockButton.fell()) - { - writeLatest(" ", "Button", 1); - mqttPublishAccess(now(), "true", "Always", "Button", " "); - activateRelay[0] = true; - } - - ledWifiStatus(); - ledAccessDeniedOff(); - beeperBeep(); - doorStatus(); - doorbellStatus(); - - if (currentMillis >= cooldown) - { - rfidLoop(); - } - - for (int currentRelay = 0; currentRelay < config.numRelays; currentRelay++) - { - if (config.lockType[currentRelay] == LOCKTYPE_CONTINUOUS) // Continuous relay mode - { - if (activateRelay[currentRelay]) - { - if (digitalRead(config.relayPin[currentRelay]) == !config.relayType[currentRelay]) // currently OFF, need to switch ON - { - mqttPublishIo("lock", "UNLOCKED"); + currentMillis = millis(); + deltaTime = currentMillis - previousLoopMillis; + uptime = NTP.getUptimeSec(); + previousLoopMillis = currentMillis; + + openLockButton.update(); + if (openLockButton.fell()) { + writeLatest(" ", "Button", 1); + mqttPublishAccess(now(), "true", "Always", "Button", " "); + activateRelay[0] = true; + } + + ledWifiStatus(); + ledAccessDeniedOff(); + beeperBeep(); + doorStatus(); + doorbellStatus(); + + if (currentMillis >= cooldown) { + rfidLoop(); + } + + for (int currentRelay = 0; currentRelay < config.numRelays; currentRelay++) { + if (config.lockType[currentRelay] == LOCKTYPE_CONTINUOUS) { // Continuous relay mode + if (activateRelay[currentRelay]) { + if (digitalRead(config.relayPin[currentRelay]) == !config.relayType[currentRelay]) { // currently OFF, need to switch ON + mqttPublishIo("lock", "UNLOCKED"); #ifdef DEBUG - Serial.print("mili : "); - Serial.println(millis()); - Serial.printf("activating relay %d now\n", currentRelay); + Serial.print("mili : "); + Serial.println(millis()); + Serial.printf("activating relay %d now\n", currentRelay); #endif - digitalWrite(config.relayPin[currentRelay], config.relayType[currentRelay]); - } - else // currently ON, need to switch OFF - { - mqttPublishIo("lock", "LOCKED"); + digitalWrite(config.relayPin[currentRelay], config.relayType[currentRelay]); + } else { // currently ON, need to switch OFF + mqttPublishIo("lock", "LOCKED"); #ifdef DEBUG - Serial.print("mili : "); - Serial.println(millis()); - Serial.printf("deactivating relay %d now\n", currentRelay); + Serial.print("mili : "); + Serial.println(millis()); + Serial.printf("deactivating relay %d now\n", currentRelay); #endif - digitalWrite(config.relayPin[currentRelay], !config.relayType[currentRelay]); - } - activateRelay[currentRelay] = false; - } - } - else if (config.lockType[currentRelay] == LOCKTYPE_MOMENTARY) // Momentary relay mode - { - if (activateRelay[currentRelay]) - { - mqttPublishIo("lock", "UNLOCKED"); + digitalWrite(config.relayPin[currentRelay], !config.relayType[currentRelay]); + } + activateRelay[currentRelay] = false; + } + } else if (config.lockType[currentRelay] == LOCKTYPE_MOMENTARY) { // Momentary relay mode + if (activateRelay[currentRelay]) { + mqttPublishIo("lock", "UNLOCKED"); #ifdef DEBUG - Serial.print("mili : "); - Serial.println(millis()); - Serial.printf("activating relay %d now\n", currentRelay); + Serial.print("mili : "); + Serial.println(millis()); + Serial.printf("activating relay %d now\n", currentRelay); #endif - digitalWrite(config.relayPin[currentRelay], config.relayType[currentRelay]); - previousMillis = millis(); - activateRelay[currentRelay] = false; - deactivateRelay[currentRelay] = true; - } - else if ((currentMillis - previousMillis >= config.activateTime[currentRelay]) && (deactivateRelay[currentRelay])) - { - mqttPublishIo("lock", "LOCKED"); + digitalWrite(config.relayPin[currentRelay], config.relayType[currentRelay]); + previousMillis = millis(); + activateRelay[currentRelay] = false; + deactivateRelay[currentRelay] = true; + } else if ((currentMillis - previousMillis >= config.activateTime[currentRelay]) + && (deactivateRelay[currentRelay])) { + mqttPublishIo("lock", "LOCKED"); #ifdef DEBUG - Serial.println(currentMillis); - Serial.println(previousMillis); - Serial.println(config.activateTime[currentRelay]); - Serial.println(activateRelay[currentRelay]); - Serial.println("deactivate relay after this"); - Serial.print("mili : "); - Serial.println(millis()); + Serial.println(currentMillis); + Serial.println(previousMillis); + Serial.println(config.activateTime[currentRelay]); + Serial.println(activateRelay[currentRelay]); + Serial.println("deactivate relay after this"); + Serial.print("mili : "); + Serial.println(millis()); #endif - digitalWrite(config.relayPin[currentRelay], !config.relayType[currentRelay]); - deactivateRelay[currentRelay] = false; - } - } - } - if (formatreq) - { + digitalWrite(config.relayPin[currentRelay], !config.relayType[currentRelay]); + deactivateRelay[currentRelay] = false; + } + } + } + if (formatreq) { #ifdef DEBUG - Serial.println(F("[ WARN ] Factory reset initiated...")); + Serial.println(F("[ WARN ] Factory reset initiated...")); #endif - SPIFFS.end(); - ws.enable(false); - SPIFFS.format(); - ESP.restart(); - } - - if (config.autoRestartIntervalSeconds > 0 && uptime > config.autoRestartIntervalSeconds * 1000) - { - writeEvent("WARN", "sys", "Auto restarting...", ""); - shouldReboot = true; - } - - if (shouldReboot) - { - writeEvent("INFO", "sys", "System is going to reboot", ""); - ESP.restart(); - } - - if (WiFi.isConnected()) - { - wiFiUptimeMillis += deltaTime; - } - - if (config.wifiTimeout > 0 && wiFiUptimeMillis > (config.wifiTimeout * 1000) && WiFi.isConnected()) - { - writeEvent("INFO", "wifi", "WiFi is going to be disabled", ""); - disableWifi(); - } - - // don't try connecting to WiFi when waiting for pincode - if (doEnableWifi == true && keyTimer == 0) - { - if (!WiFi.isConnected()) - { - enableWifi(); - writeEvent("INFO", "wifi", "Enabling WiFi", ""); - doEnableWifi = false; - } - } - - if (config.mqttEnabled && mqttClient.connected()) - { - if ((unsigned)now() > nextbeat) - { - mqttPublishHeartbeat(now(), uptime); - nextbeat = (unsigned)now() + config.mqttInterval; + SPIFFS.end(); + ws.enable(false); + SPIFFS.format(); + ESP.restart(); + } + + if (config.autoRestartIntervalSeconds > 0 && uptime > config.autoRestartIntervalSeconds * 1000) { + writeEvent("WARN", "sys", "Auto restarting...", ""); + shouldReboot = true; + } + + if (shouldReboot) { + writeEvent("INFO", "sys", "System is going to reboot", ""); + ESP.restart(); + } + + if (WiFi.isConnected()) { + wiFiUptimeMillis += deltaTime; + } + + if (config.wifiTimeout > 0 && wiFiUptimeMillis > (config.wifiTimeout * 1000) && WiFi.isConnected()) { + writeEvent("INFO", "wifi", "WiFi is going to be disabled", ""); + disableWifi(); + } + + // don't try connecting to WiFi when waiting for pincode + if (doEnableWifi == true && keyTimer == 0) { + if (!WiFi.isConnected()) { + enableWifi(); + writeEvent("INFO", "wifi", "Enabling WiFi", ""); + doEnableWifi = false; + } + } + + if (config.mqttEnabled && mqttClient.connected()) { + if ((unsigned)now() > nextbeat) { + mqttPublishHeartbeat(now(), uptime); + nextbeat = (unsigned)now() + config.mqttInterval; #ifdef DEBUG - Serial.print("[ INFO ] Nextbeat="); - Serial.println(nextbeat); + Serial.print("[ INFO ] Nextbeat="); + Serial.println(nextbeat); #endif - } - processMqttQueue(); - } + } + processMqttQueue(); + } } diff --git a/src/mqtt.esp b/src/mqtt.esp index 56fc72af..b4ba894e 100644 --- a/src/mqtt.esp +++ b/src/mqtt.esp @@ -1,11 +1,11 @@ char mqttBuffer[512]; struct MqttMessage { - char command[20]; - char uid[20]; - char user[64]; - char serializedMessage[512]; - MqttMessage *nextMessage = NULL; + char command[20]; + char uid[20]; + char user[64]; + char serializedMessage[512]; + MqttMessage * nextMessage = NULL; }; MqttMessage *messageQueue = NULL; @@ -13,562 +13,531 @@ MqttMessage *messageQueue = NULL; void connectToMqtt() { #ifdef DEBUG - Serial.println("[ INFO ] Connecting MQTT"); + Serial.println("[ INFO ] Connecting MQTT"); #endif - mqttClient.connect(); + mqttClient.connect(); } void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) { - String reasonstr = ""; - switch (reason) - { - case (AsyncMqttClientDisconnectReason::TCP_DISCONNECTED): - reasonstr = "TCP_DISCONNECTED"; - break; - case (AsyncMqttClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION): - reasonstr = "MQTT_UNACCEPTABLE_PROTOCOL_VERSION"; - break; - case (AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED): - reasonstr = "MQTT_IDENTIFIER_REJECTED"; - break; - case (AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE): - reasonstr = "MQTT_SERVER_UNAVAILABLE"; - break; - case (AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS): - reasonstr = "MQTT_MALFORMED_CREDENTIALS"; - break; - case (AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED): - reasonstr = "MQTT_NOT_AUTHORIZED"; - break; - case (AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE): - reasonstr = "ESP8266_NOT_ENOUGH_SPACE"; - break; - default: - reasonstr = "Unknown"; - break; - } - writeEvent("WARN", "mqtt", "Disconnected from MQTT server", reasonstr); - - if (WiFi.isConnected()) - { - mqttReconnectTimer.once(60, connectToMqtt); - } + String reasonstr = ""; + + switch (reason) { + case (AsyncMqttClientDisconnectReason::TCP_DISCONNECTED): + reasonstr = "TCP_DISCONNECTED"; + break; + case (AsyncMqttClientDisconnectReason::MQTT_UNACCEPTABLE_PROTOCOL_VERSION): + reasonstr = "MQTT_UNACCEPTABLE_PROTOCOL_VERSION"; + break; + case (AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED): + reasonstr = "MQTT_IDENTIFIER_REJECTED"; + break; + case (AsyncMqttClientDisconnectReason::MQTT_SERVER_UNAVAILABLE): + reasonstr = "MQTT_SERVER_UNAVAILABLE"; + break; + case (AsyncMqttClientDisconnectReason::MQTT_MALFORMED_CREDENTIALS): + reasonstr = "MQTT_MALFORMED_CREDENTIALS"; + break; + case (AsyncMqttClientDisconnectReason::MQTT_NOT_AUTHORIZED): + reasonstr = "MQTT_NOT_AUTHORIZED"; + break; + case (AsyncMqttClientDisconnectReason::ESP8266_NOT_ENOUGH_SPACE): + reasonstr = "ESP8266_NOT_ENOUGH_SPACE"; + break; + default: + reasonstr = "Unknown"; + break; + } + writeEvent("WARN", "mqtt", "Disconnected from MQTT server", reasonstr); + + if (WiFi.isConnected()) { + mqttReconnectTimer.once(60, connectToMqtt); + } } void mqttPublishEvent(JsonDocument *root, String topic) { - if (config.mqttEnabled && mqttClient.connected()) - { - String stopic(config.mqttTopic); - stopic = stopic + topic; - String mqttBuffer; - serializeJson(*root, mqttBuffer); - mqttClient.publish(stopic.c_str(), 0, false, mqttBuffer.c_str()); + if (config.mqttEnabled && mqttClient.connected()) { + String stopic(config.mqttTopic); + stopic = stopic + topic; + String mqttBuffer; + serializeJson(*root, mqttBuffer); + mqttClient.publish(stopic.c_str(), 0, false, mqttBuffer.c_str()); #ifdef DEBUG - Serial.print("[ INFO ] Mqtt Publish:"); - Serial.println(mqttBuffer); + Serial.print("[ INFO ] Mqtt Publish:"); + Serial.println(mqttBuffer); #endif - } + } } void mqttPublishEvent(JsonDocument *root) { - mqttPublishEvent(root, "/send"); + mqttPublishEvent(root, "/send"); } void mqttPublishAck(String command) { - DynamicJsonDocument root(512); - root["type"] = command; - root["ip"] = WiFi.localIP().toString(); - root["hostname"] = config.deviceHostname; - mqttPublishEvent(&root); + DynamicJsonDocument root(512); + + root["type"] = command; + root["ip"] = WiFi.localIP().toString(); + root["hostname"] = config.deviceHostname; + mqttPublishEvent(&root); } void mqttPublishBoot(time_t boot_time) { - DynamicJsonDocument root(512); - root["type"] = "boot"; - root["time"] = boot_time; - root["uptime"] = "0"; - root["ip"] = WiFi.localIP().toString(); - root["hostname"] = config.deviceHostname; - mqttPublishEvent(&root); + DynamicJsonDocument root(512); + + root["type"] = "boot"; + root["time"] = boot_time; + root["uptime"] = "0"; + root["ip"] = WiFi.localIP().toString(); + root["hostname"] = config.deviceHostname; + mqttPublishEvent(&root); } void mqttPublishDiscovery() { - String mtopic(config.mqttTopic); - String topic; - String deviceName = config.deviceHostname; - DynamicJsonDocument via(512); - via["ids"] = WiFi.macAddress(); - - for (int i = 0; i < 6; i++) - { - switch (i) - { - case 0: - { - DynamicJsonDocument dev(512); - dev["ids"] = WiFi.macAddress(); - dev["name"] = config.deviceHostname; - dev["mf"] = "esp-rfid"; - dev["sw"] = VERSION; - DynamicJsonDocument root(512); - topic = "homeassistant/lock/" + deviceName + "/config"; - root["name"] = "Lock"; - root["uniq_id"] = deviceName + "/lock"; - root["stat_t"] = mtopic + "/io/lock"; - root["cmd_t"] = mtopic + "/cmd"; - root["pl_unlk"] = "{cmd:'opendoor'}"; - root["pl_lock"] = "{cmd:'opendoor'}"; - root["avty_t"] = mtopic + "/avty"; - root["dev"] = dev; - mqttPublishEvent(&root, topic); - break; - } - case 1: - { - DynamicJsonDocument door(512); - topic = "homeassistant/binary_sensor/" + deviceName + "/door/config"; - door["name"] = "Door"; - door["uniq_id"] = deviceName + "/door"; - door["stat_t"] = mtopic + "/io/door"; - door["avty_t"] = mtopic + "/avty"; - door["dev_cla"] = "door"; - door["dev"] = via; - mqttPublishEvent(&door, topic); - break; - } - case 2: - { - DynamicJsonDocument doorbell(512); - topic = "homeassistant/binary_sensor/" + deviceName + "/doorbell/config"; - doorbell["name"] = "Doorbell"; - doorbell["uniq_id"] = deviceName + "/doorbell"; - doorbell["stat_t"] = mtopic + "/io/doorbell"; - doorbell["avty_t"] = mtopic + "/avty"; - doorbell["dev_cla"] = "sound"; - doorbell["icon"] = "mdi:bell"; - doorbell["dev"] = via; - mqttPublishEvent(&doorbell, topic); - break; - } - case 3: - { - DynamicJsonDocument tag(512); - topic = "homeassistant/sensor/" + deviceName + "/tag/config"; - tag["name"] = "Tag"; - tag["uniq_id"] = deviceName + "/tag"; - tag["stat_t"] = mtopic + "/tag"; - tag["avty_t"] = mtopic + "/avty"; - tag["val_tpl"] = "{{ value_json.uid }}"; - tag["json_attr_t"] = mtopic + "/tag"; - tag["icon"] = "mdi:key"; - tag["dev"] = via; - mqttPublishEvent(&tag, topic); - break; - } - case 4: - { - DynamicJsonDocument user(512); - topic = "homeassistant/sensor/" + deviceName + "/user/config"; - user["name"] = "User"; - user["uniq_id"] = deviceName + "/name"; - user["stat_t"] = mtopic + "/tag"; - user["avty_t"] = mtopic + "/avty"; - user["val_tpl"] = "{{ value_json.username }}"; - user["json_attr_t"] = mtopic + "/tag"; - user["icon"] = "mdi:human"; - user["dev"] = via; - mqttPublishEvent(&user, topic); - break; - } - case 5: - { - DynamicJsonDocument tamper(512); - topic = "homeassistant/binary_sensor/" + deviceName + "/tamper/config"; - tamper["name"] = "Door tamper"; - tamper["uniq_id"] = deviceName + "/tamper"; - tamper["stat_t"] = mtopic + "/io/tamper"; - tamper["avty_t"] = mtopic + "/avty"; - tamper["dev_cla"] = "safety"; - tamper["dev"] = via; - mqttPublishEvent(&tamper, topic); - break; - } - } - } + String mtopic(config.mqttTopic); + String topic; + String deviceName = config.deviceHostname; + + DynamicJsonDocument via(512); + + via["ids"] = WiFi.macAddress(); + + for (int i = 0; i < 6; i++) { + switch (i) { + case 0: + { + DynamicJsonDocument dev(512); + dev["ids"] = WiFi.macAddress(); + dev["name"] = config.deviceHostname; + dev["mf"] = "esp-rfid"; + dev["sw"] = VERSION; + DynamicJsonDocument root(512); + topic = "homeassistant/lock/" + deviceName + "/config"; + root["name"] = "Lock"; + root["uniq_id"] = deviceName + "/lock"; + root["stat_t"] = mtopic + "/io/lock"; + root["cmd_t"] = mtopic + "/cmd"; + root["pl_unlk"] = "{cmd:'opendoor'}"; + root["pl_lock"] = "{cmd:'opendoor'}"; + root["avty_t"] = mtopic + "/avty"; + root["dev"] = dev; + mqttPublishEvent(&root, topic); + break; + } + case 1: + { + DynamicJsonDocument door(512); + topic = "homeassistant/binary_sensor/" + deviceName + "/door/config"; + door["name"] = "Door"; + door["uniq_id"] = deviceName + "/door"; + door["stat_t"] = mtopic + "/io/door"; + door["avty_t"] = mtopic + "/avty"; + door["dev_cla"] = "door"; + door["dev"] = via; + mqttPublishEvent(&door, topic); + break; + } + case 2: + { + DynamicJsonDocument doorbell(512); + topic = "homeassistant/binary_sensor/" + deviceName + "/doorbell/config"; + doorbell["name"] = "Doorbell"; + doorbell["uniq_id"] = deviceName + "/doorbell"; + doorbell["stat_t"] = mtopic + "/io/doorbell"; + doorbell["avty_t"] = mtopic + "/avty"; + doorbell["dev_cla"] = "sound"; + doorbell["icon"] = "mdi:bell"; + doorbell["dev"] = via; + mqttPublishEvent(&doorbell, topic); + break; + } + case 3: + { + DynamicJsonDocument tag(512); + topic = "homeassistant/sensor/" + deviceName + "/tag/config"; + tag["name"] = "Tag"; + tag["uniq_id"] = deviceName + "/tag"; + tag["stat_t"] = mtopic + "/tag"; + tag["avty_t"] = mtopic + "/avty"; + tag["val_tpl"] = "{{ value_json.uid }}"; + tag["json_attr_t"] = mtopic + "/tag"; + tag["icon"] = "mdi:key"; + tag["dev"] = via; + mqttPublishEvent(&tag, topic); + break; + } + case 4: + { + DynamicJsonDocument user(512); + topic = "homeassistant/sensor/" + deviceName + "/user/config"; + user["name"] = "User"; + user["uniq_id"] = deviceName + "/name"; + user["stat_t"] = mtopic + "/tag"; + user["avty_t"] = mtopic + "/avty"; + user["val_tpl"] = "{{ value_json.username }}"; + user["json_attr_t"] = mtopic + "/tag"; + user["icon"] = "mdi:human"; + user["dev"] = via; + mqttPublishEvent(&user, topic); + break; + } + case 5: + { + DynamicJsonDocument tamper(512); + topic = "homeassistant/binary_sensor/" + deviceName + "/tamper/config"; + tamper["name"] = "Door tamper"; + tamper["uniq_id"] = deviceName + "/tamper"; + tamper["stat_t"] = mtopic + "/io/tamper"; + tamper["avty_t"] = mtopic + "/avty"; + tamper["dev_cla"] = "safety"; + tamper["dev"] = via; + mqttPublishEvent(&tamper, topic); + break; + } + } + } } void mqttPublishAvty() { - String mtopic(config.mqttTopic); - String avty_topic = mtopic + "/avty"; - String payloadString = "online"; - mqttClient.publish(avty_topic.c_str(), 0, true, payloadString.c_str()); + String mtopic(config.mqttTopic); + String avty_topic = mtopic + "/avty"; + String payloadString = "online"; + + mqttClient.publish(avty_topic.c_str(), 0, true, payloadString.c_str()); #ifdef DEBUG - Serial.println("[ INFO ] Mqtt Publish online @ avty"); + Serial.println("[ INFO ] Mqtt Publish online @ avty"); #endif } void mqttPublishHeartbeat(time_t heartbeat, time_t uptime) { - DynamicJsonDocument root(512); - root["type"] = "heartbeat"; - root["time"] = heartbeat; - root["uptime"] = uptime; - root["ip"] = WiFi.localIP().toString(); - root["hostname"] = config.deviceHostname; - mqttPublishEvent(&root); + DynamicJsonDocument root(512); + + root["type"] = "heartbeat"; + root["time"] = heartbeat; + root["uptime"] = uptime; + root["ip"] = WiFi.localIP().toString(); + root["hostname"] = config.deviceHostname; + mqttPublishEvent(&root); } -void mqttPublishAccess(time_t accesstime, String const &isknown, String const &type, String const &user, String const &uid) +void mqttPublishAccess(time_t accesstime, String const &isknown, String const &type, String const &user, + String const &uid) { - DynamicJsonDocument root(512); - // log to MQTT adding cmd command - if (config.mqttEvents) - { - root["cmd"] = "log"; - } - - if (!config.mqttHA) - { - root["type"] = "access"; - root["time"] = accesstime; - root["isKnown"] = isknown; - root["access"] = type; - root["username"] = user; - root["uid"] = uid; - root["hostname"] = config.deviceHostname; - } - else - { - root["uid"] = uid; - root["username"] = user; - root["access"] = type; - root["time"] = accesstime; - } - - if (!config.mqttHA) - { - mqttPublishEvent(&root); - } - else - { - mqttPublishEvent(&root, "/tag"); - } + DynamicJsonDocument root(512); + + // log to MQTT adding cmd command + if (config.mqttEvents) { + root["cmd"] = "log"; + } + + if (!config.mqttHA) { + root["type"] = "access"; + root["time"] = accesstime; + root["isKnown"] = isknown; + root["access"] = type; + root["username"] = user; + root["uid"] = uid; + root["hostname"] = config.deviceHostname; + } else { + root["uid"] = uid; + root["username"] = user; + root["access"] = type; + root["time"] = accesstime; + } + + if (!config.mqttHA) { + mqttPublishEvent(&root); + } else { + mqttPublishEvent(&root, "/tag"); + } } void mqttPublishIo(String const &io, String const &state) { - if (config.mqttHA && config.mqttEnabled && mqttClient.connected()) - { - String stopic(config.mqttTopic); - stopic = stopic + "/io/" + io; + if (config.mqttHA && config.mqttEnabled && mqttClient.connected()) { + String stopic(config.mqttTopic); + stopic = stopic + "/io/" + io; - mqttClient.publish(stopic.c_str(), 0, false, state.c_str()); + mqttClient.publish(stopic.c_str(), 0, false, state.c_str()); #ifdef DEBUG - Serial.print("[ INFO ] Mqtt Publish:"); - Serial.println(state + " @ " + stopic); + Serial.print("[ INFO ] Mqtt Publish:"); + Serial.println(state + " @ " + stopic); #endif - } + } } void onMqttPublish(uint16_t packetId) { - writeEvent("INFO", "mqtt", "MQTT publish acknowledged", String(packetId)); + writeEvent("INFO", "mqtt", "MQTT publish acknowledged", String(packetId)); } void getUserList() { - DynamicJsonDocument root(512); - JsonArray users = root.createNestedArray("list"); - Dir dir = SPIFFS.openDir("/P/"); + DynamicJsonDocument root(512); + JsonArray users = root.createNestedArray("list"); + Dir dir = SPIFFS.openDir("/P/"); + #ifdef DEBUG - Serial.println("[ INFO ] getUserList"); + Serial.println("[ INFO ] getUserList"); #endif - while (dir.next()) - { - JsonObject item = users.createNestedObject(); - String uid = dir.fileName(); - uid.remove(0, 3); - item["uid"] = uid; - File f = SPIFFS.open(dir.fileName(), "r"); - size_t size = f.size(); - std::unique_ptr buf(new char[size]); - f.readBytes(buf.get(), size); - DynamicJsonDocument json(512); - auto error = deserializeJson(json, buf.get()); - if (!error) - { - mqttPublishEvent(&root); - } - } + while (dir.next()) { + JsonObject item = users.createNestedObject(); + String uid = dir.fileName(); + uid.remove(0, 3); + item["uid"] = uid; + File f = SPIFFS.open(dir.fileName(), "r"); + size_t size = f.size(); + std::unique_ptr < char[] > buf(new char[size]); + f.readBytes(buf.get(), size); + DynamicJsonDocument json(512); + auto error = deserializeJson(json, buf.get()); + if (!error) { + mqttPublishEvent(&root); + } + } } void deleteAllUserFiles() { - Dir dir = SPIFFS.openDir("/P/"); - while (dir.next()) - { - String uid = dir.fileName(); - uid.remove(0, 3); - SPIFFS.remove(dir.fileName()); - } + Dir dir = SPIFFS.openDir("/P/"); + + while (dir.next()) { + String uid = dir.fileName(); + uid.remove(0, 3); + SPIFFS.remove(dir.fileName()); + } } void deleteUserID(const char *uid) { - // only do this if a user id has been provided - if (uid) - { - Dir dir = SPIFFS.openDir("/P/"); - while (dir.next()) - { - String user_id = dir.fileName(); - String myuid = uid; - user_id.remove(0, 3); - if (myuid == user_id) - { - SPIFFS.remove(dir.fileName()); - } - } - } + // only do this if a user id has been provided + if (uid) { + Dir dir = SPIFFS.openDir("/P/"); + while (dir.next()) { + String user_id = dir.fileName(); + String myuid = uid; + user_id.remove(0, 3); + if (myuid == user_id) { + SPIFFS.remove(dir.fileName()); + } + } + } } -void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total) +void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, + size_t total) { - size_t n = 0; - size_t i = index; - while(n < len) { - mqttBuffer[i] = payload[n]; - n++; - i++; - } - if(index + len == total) { - mqttBuffer[i] = '\0'; - } else { - return; - } + size_t n = 0; + size_t i = index; + + while (n < len) { + mqttBuffer[i] = payload[n]; + n++; + i++; + } + if (index + len == total) { + mqttBuffer[i] = '\0'; + } else { + return; + } #ifdef DEBUG - Serial.print("[ INFO ] JSON msg: "); - Serial.println(mqttBuffer); + Serial.print("[ INFO ] JSON msg: "); + Serial.println(mqttBuffer); #endif - StaticJsonDocument<512> mqttIncomingJson; - auto error = deserializeJson(mqttIncomingJson, mqttBuffer); - if (error) - { + StaticJsonDocument < 512 > mqttIncomingJson; + auto error = deserializeJson(mqttIncomingJson, mqttBuffer); + if (error) { #ifdef DEBUG - Serial.print("[ INFO ] Failed parse MQTT message: "); - Serial.println(mqttBuffer); + Serial.print("[ INFO ] Failed parse MQTT message: "); + Serial.println(mqttBuffer); #endif - return; - } - - // Check if IP was sent with command because we only - // accept commands where sent IP is equal to device IP - if (!mqttIncomingJson.containsKey("doorip")) - { - return; - } - - const char *ipadr = mqttIncomingJson["doorip"]; - String espIp = WiFi.localIP().toString(); - if (!((strcmp(ipadr, espIp.c_str()) == 0) && (ipadr != NULL))) - { + return; + } + + // Check if IP was sent with command because we only + // accept commands where sent IP is equal to device IP + if (!mqttIncomingJson.containsKey("doorip")) { + return; + } + + const char *ipadr = mqttIncomingJson["doorip"]; + String espIp = WiFi.localIP().toString(); + if (!((strcmp(ipadr, espIp.c_str()) == 0) && (ipadr != NULL))) { #ifdef DEBUG - Serial.print("[ INFO ] ESP IP: "); - Serial.println(espIp); - Serial.print("[ INFO ] recv IP: "); - Serial.println(ipadr); + Serial.print("[ INFO ] ESP IP: "); + Serial.println(espIp); + Serial.print("[ INFO ] recv IP: "); + Serial.println(ipadr); #endif - return; - } + return; + } - if(ESP.getFreeHeap() < 2000) - { + if (ESP.getFreeHeap() < 2000) { #ifdef DEBUG - Serial.println("Dropping MQTT message, out of memory"); + Serial.println("Dropping MQTT message, out of memory"); #endif - writeEvent("ERRO", "mqtt", "Dropping MQTT message, out of memory", ""); - return; - } - - MqttMessage* incomingMessage = new MqttMessage; - - strlcpy(incomingMessage->command, mqttIncomingJson["cmd"], sizeof(incomingMessage->command)); - if (mqttIncomingJson.containsKey("uid")) { - strlcpy(incomingMessage->uid, mqttIncomingJson["uid"], sizeof(incomingMessage->uid)); - } - if (mqttIncomingJson.containsKey("user")) { - strlcpy(incomingMessage->user, mqttIncomingJson["user"], sizeof(incomingMessage->user)); - } - serializeJson(mqttIncomingJson, incomingMessage->serializedMessage); - - MqttMessage* lastMessage = messageQueue; - if(lastMessage == NULL) - { - messageQueue = incomingMessage; - } - else { - while(lastMessage->nextMessage != NULL) - { - lastMessage = lastMessage->nextMessage; - } - lastMessage->nextMessage = incomingMessage; - } + writeEvent("ERRO", "mqtt", "Dropping MQTT message, out of memory", ""); + return; + } + + MqttMessage *incomingMessage = new MqttMessage; + + strlcpy(incomingMessage->command, mqttIncomingJson["cmd"], sizeof(incomingMessage->command)); + if (mqttIncomingJson.containsKey("uid")) { + strlcpy(incomingMessage->uid, mqttIncomingJson["uid"], sizeof(incomingMessage->uid)); + } + if (mqttIncomingJson.containsKey("user")) { + strlcpy(incomingMessage->user, mqttIncomingJson["user"], sizeof(incomingMessage->user)); + } + serializeJson(mqttIncomingJson, incomingMessage->serializedMessage); + + MqttMessage *lastMessage = messageQueue; + if (lastMessage == NULL) { + messageQueue = incomingMessage; + } else { + while (lastMessage->nextMessage != NULL) { + lastMessage = lastMessage->nextMessage; + } + lastMessage->nextMessage = incomingMessage; + } } void processMqttMessage(MqttMessage *incomingMessage) { - char *command = incomingMessage->command; - if (strcmp(command, "getuserlist") == 0) - { + char *command = incomingMessage->command; + + if (strcmp(command, "getuserlist") == 0) { #ifdef DEBUG - Serial.println("[ INFO ] Get User List"); + Serial.println("[ INFO ] Get User List"); #endif - getUserList(); - } - - else if (strcmp(command, "opendoor") == 0) - { + getUserList(); + } else if (strcmp(command, "opendoor") == 0) { #ifdef DEBUG - Serial.println("[ INFO ] Door open"); + Serial.println("[ INFO ] Door open"); #endif - writeLatest(" ", "MQTT", 1); - mqttPublishAccess(now(), "true", "Always", "MQTT", " "); - for (int currentRelay = 0; currentRelay < config.numRelays; currentRelay++) - { - activateRelay[currentRelay] = true; - } - previousMillis = millis(); - } - - else if (strcmp(command, "deletusers") == 0) - { + writeLatest(" ", "MQTT", 1); + mqttPublishAccess(now(), "true", "Always", "MQTT", " "); + for (int currentRelay = 0; currentRelay < config.numRelays; currentRelay++) { + activateRelay[currentRelay] = true; + } + previousMillis = millis(); + } else if (strcmp(command, "deletusers") == 0) { #ifdef DEBUG - Serial.println("[ INFO ] Delete all users"); + Serial.println("[ INFO ] Delete all users"); #endif - deleteAllUserFiles(); - mqttPublishAck(command); - } - - else if (strcmp(command, "deletuid") == 0) - { + deleteAllUserFiles(); + mqttPublishAck(command); + } else if (strcmp(command, "deletuid") == 0) { #ifdef DEBUG - Serial.println("[ INFO ] Delete a single user by uid"); + Serial.println("[ INFO ] Delete a single user by uid"); #endif - const char *uid = incomingMessage->uid; - deleteUserID(uid); - mqttPublishAck(command); - } - - else if (strcmp(command, "adduser") == 0) - { + const char *uid = incomingMessage->uid; + deleteUserID(uid); + mqttPublishAck(command); + } else if (strcmp(command, "adduser") == 0) { #ifdef DEBUG - Serial.print("[ INFO ] Add Users: "); - const char *name = incomingMessage->user; - Serial.println(name); + Serial.print("[ INFO ] Add Users: "); + const char *name = incomingMessage->user; + Serial.println(name); #endif - const char *uid = incomingMessage->uid; - String filename = "/P/"; - filename += uid; - File f = SPIFFS.open(filename, "w+"); - // Check if we created the file - if (f) - { - f.println(incomingMessage->serializedMessage); - } - f.close(); - mqttPublishAck(command); - } - - free(incomingMessage); - return; + const char *uid = incomingMessage->uid; + String filename = "/P/"; + filename += uid; + File f = SPIFFS.open(filename, "w+"); + // Check if we created the file + if (f) { + f.println(incomingMessage->serializedMessage); + } + f.close(); + mqttPublishAck(command); + } + + free(incomingMessage); + return; } void onMqttSubscribe(uint16_t packetId, uint8_t qos) { #ifdef DEBUG - Serial.println("[ INFO ] Subscribe acknowledged."); - Serial.print("[ INFO ] packetId: "); - Serial.println(packetId); - Serial.print("[ INFO ] qos: "); - Serial.println(qos); + Serial.println("[ INFO ] Subscribe acknowledged."); + Serial.print("[ INFO ] packetId: "); + Serial.println(packetId); + Serial.print("[ INFO ] qos: "); + Serial.println(qos); #endif } void onMqttConnect(bool sessionPresent) { #ifdef DEBUG - Serial.println("[ INFO ] MQTT Connected session"); + Serial.println("[ INFO ] MQTT Connected session"); #endif - if (sessionPresent == true) - { + if (sessionPresent == true) { #ifdef DEBUG - Serial.println("[ INFO ] MQTT session Present: True"); + Serial.println("[ INFO ] MQTT session Present: True"); #endif - writeEvent("INFO", "mqtt", "Connected to MQTT Server", "Session Present"); - } - mqttPublishBoot(now()); + writeEvent("INFO", "mqtt", "Connected to MQTT Server", "Session Present"); + } + mqttPublishBoot(now()); - String stopic(config.mqttTopic); - stopic = stopic + "/cmd"; - uint16_t packetIdSub = mqttClient.subscribe(stopic.c_str(), 2); + String stopic(config.mqttTopic); + stopic = stopic + "/cmd"; + uint16_t packetIdSub = mqttClient.subscribe(stopic.c_str(), 2); #ifdef DEBUG - Serial.print("[ INFO ] Subscribing at QoS 2, packetId: "); - Serial.println(packetIdSub); + Serial.print("[ INFO ] Subscribing at QoS 2, packetId: "); + Serial.println(packetIdSub); #endif - if (config.mqttHA) - { - mqttPublishIo("door", digitalRead(config.doorstatpin) == HIGH ? "OFF" : "ON"); - mqttPublishIo("doorbell", digitalRead(config.doorbellpin) == HIGH ? "ON" :"OFF"); - mqttPublishIo("lock", "LOCKED"); - mqttPublishDiscovery(); - mqttPublishAvty(); - } + if (config.mqttHA) { + mqttPublishIo("door", digitalRead(config.doorstatpin) == HIGH ? "OFF" : "ON"); + mqttPublishIo("doorbell", digitalRead(config.doorbellpin) == HIGH ? "ON" :"OFF"); + mqttPublishIo("lock", "LOCKED"); + mqttPublishDiscovery(); + mqttPublishAvty(); + } } void processMqttQueue() { - while(messageQueue != NULL) { - MqttMessage *messageToProcess = messageQueue; - messageQueue = messageToProcess->nextMessage; - processMqttMessage(messageToProcess); - } + while (messageQueue != NULL) { + MqttMessage *messageToProcess = messageQueue; + messageQueue = messageToProcess->nextMessage; + processMqttMessage(messageToProcess); + } } void setupMqtt() { - if (!config.mqttEnabled) - { - return; - } + if (!config.mqttEnabled) { + return; + } #ifdef DEBUG - Serial.println("[ INFO ] Trying to setup MQTT"); + Serial.println("[ INFO ] Trying to setup MQTT"); #endif - if (config.mqttHA) - { - String mtopic(config.mqttTopic); - String topicString = mtopic + "/avty"; - String payloadString = "offline"; - char *topicLWT = strdup(topicString.c_str()); - char *payloadLWT = strdup(payloadString.c_str()); - mqttClient.setWill(topicLWT, 2, true, payloadLWT); - } - mqttClient.setServer(config.mqttHost, config.mqttPort); - mqttClient.setCredentials(config.mqttUser, config.mqttPass); - mqttClient.onDisconnect(onMqttDisconnect); - mqttClient.onPublish(onMqttPublish); - mqttClient.onSubscribe(onMqttSubscribe); - mqttClient.onConnect(onMqttConnect); - mqttClient.onMessage(onMqttMessage); + if (config.mqttHA) { + String mtopic(config.mqttTopic); + String topicString = mtopic + "/avty"; + String payloadString = "offline"; + char *topicLWT = strdup(topicString.c_str()); + char *payloadLWT = strdup(payloadString.c_str()); + mqttClient.setWill(topicLWT, 2, true, payloadLWT); + } + mqttClient.setServer(config.mqttHost, config.mqttPort); + mqttClient.setCredentials(config.mqttUser, config.mqttPass); + mqttClient.onDisconnect(onMqttDisconnect); + mqttClient.onPublish(onMqttPublish); + mqttClient.onSubscribe(onMqttSubscribe); + mqttClient.onConnect(onMqttConnect); + mqttClient.onMessage(onMqttMessage); } diff --git a/src/rfid.esp b/src/rfid.esp index 04ed61ab..93741fb5 100644 --- a/src/rfid.esp +++ b/src/rfid.esp @@ -17,491 +17,442 @@ RfidProcessingStates processingState = waiting; void loadWiegandData() { - wiegandAvailable = false; - // wg.available checks if there's new info and populates all the internal data - // so it should be called only once per loop - wiegandAvailable = wg.available(); + wiegandAvailable = false; + // wg.available checks if there's new info and populates all the internal data + // so it should be called only once per loop + wiegandAvailable = wg.available(); } void rfidPrepareRead() { #ifdef OFFICIALBOARD - loadWiegandData(); + loadWiegandData(); #else - if (config.readertype == READER_WIEGAND) - { - loadWiegandData(); - } + if (config.readertype == READER_WIEGAND) { + loadWiegandData(); + } #endif } void wiegandRead() { - if (wiegandAvailable && rfidState == waitingCard) - { - // if we get 26 or 34 bit burst then we have a scanned PICC - if (wg.getWiegandType() == WIEGANDTYPE_PICC26 || wg.getWiegandType() == WIEGANDTYPE_PICC34) - { - #ifdef DEBUG - Serial.print(F("[ INFO ] PICC's UID: ")); - Serial.println(wg.getCode(),HEX); - #endif - uid = String(wg.getCode(), HEX); - type = String(wg.getWiegandType(), DEC); - - File f = SPIFFS.open("/P/" + uid, "r"); - // user exists, we should wait for pincode - if (f) - { - if (config.pinCodeRequested) - { - keyTimer = millis(); - ledWaitingOn(); - rfidState = waitingForPincode; - } else - { - rfidState = cardSwiped; - } - } else - { - cooldown = millis() + COOLDOWN_MILIS; - rfidState = waitingCard; - processingState = unknown; - } - } - } + if (wiegandAvailable && rfidState == waitingCard) { + // if we get 26 or 34 bit burst then we have a scanned PICC + if (wg.getWiegandType() == WIEGANDTYPE_PICC26 || wg.getWiegandType() == WIEGANDTYPE_PICC34) { +#ifdef DEBUG + Serial.print(F("[ INFO ] PICC's UID: ")); + Serial.println(wg.getCode(), HEX); +#endif + uid = String(wg.getCode(), HEX); + type = String(wg.getWiegandType(), DEC); + + File f = SPIFFS.open("/P/" + uid, "r"); + // user exists, we should wait for pincode + if (f) { + if (config.pinCodeRequested) { + keyTimer = millis(); + ledWaitingOn(); + rfidState = waitingForPincode; + } else { + rfidState = cardSwiped; + } + } else { + cooldown = millis() + COOLDOWN_MILIS; + rfidState = waitingCard; + processingState = unknown; + } + } + } } #ifndef OFFICIALBOARD void mfrc522Read() { - if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) - { - return; - } - mfrc522.PICC_HaltA(); - cooldown = millis() + COOLDOWN_MILIS; + if (!mfrc522.PICC_IsNewCardPresent() || !mfrc522.PICC_ReadCardSerial()) { + return; + } + mfrc522.PICC_HaltA(); + cooldown = millis() + COOLDOWN_MILIS; #ifdef DEBUG - Serial.print(F("[ INFO ] PICC's UID: ")); + Serial.print(F("[ INFO ] PICC's UID: ")); #endif - for (int i = 0; i < mfrc522.uid.size; ++i) - { - uid += String(mfrc522.uid.uidByte[i], HEX); - } + for (int i = 0; i < mfrc522.uid.size; ++i) { + uid += String(mfrc522.uid.uidByte[i], HEX); + } #ifdef DEBUG - Serial.print(uid); + Serial.print(uid); #endif - MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); - type = mfrc522.PICC_GetTypeName(piccType); + MFRC522::PICC_Type piccType = mfrc522.PICC_GetType(mfrc522.uid.sak); + type = mfrc522.PICC_GetTypeName(piccType); #ifdef DEBUG - Serial.print(" " + type); + Serial.print(" " + type); #endif } void pn532Read() { - bool found = false; - byte pnuid[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - eCardType e_CardType; - byte u8_UidLength = 0x00; // UID = 4 or 7 bytes - found = pn532.ReadPassiveTargetID(pnuid, &u8_UidLength, &e_CardType); - if (found && u8_UidLength >= 4) - { + bool found = false; + byte pnuid[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + eCardType e_CardType; + byte u8_UidLength = 0x00; // UID = 4 or 7 bytes + + found = pn532.ReadPassiveTargetID(pnuid, &u8_UidLength, &e_CardType); + if (found && u8_UidLength >= 4) { #ifdef DEBUG - Serial.print(F("[ INFO ] PICC's UID: ")); + Serial.print(F("[ INFO ] PICC's UID: ")); #endif - for (uint8_t i = 0; i < u8_UidLength; i++) - { - uid += String(pnuid[i], HEX); - } + for (uint8_t i = 0; i < u8_UidLength; i++) { + uid += String(pnuid[i], HEX); + } #ifdef DEBUG - Serial.print(uid); + Serial.print(uid); #endif - cooldown = millis() + COOLDOWN_MILIS; - } + cooldown = millis() + COOLDOWN_MILIS; + } } void genericRead() { - while (Serial.available() > 0) - { - RFIDr.rfidSerial(Serial.read()); - } - if (RFIDr.Available()) - { - uid = RFIDr.GetHexID(); - type = RFIDr.GetTagType(); - cooldown = millis() + COOLDOWN_MILIS; + while (Serial.available() > 0) { + RFIDr.rfidSerial(Serial.read()); + } + if (RFIDr.Available()) { + uid = RFIDr.GetHexID(); + type = RFIDr.GetTagType(); + cooldown = millis() + COOLDOWN_MILIS; #ifdef DEBUG - Serial.print(F("[ INFO ] PICC's UID: ")); - Serial.print(uid); + Serial.print(F("[ INFO ] PICC's UID: ")); + Serial.print(uid); #endif - } - - if (config.readertype == READER_MFRC522_RDM6300 && uid.length() == 0) - { - mfrc522Read(); - } - - else if (config.readertype == READER_WIEGAND_RDM6300 && uid.length() == 0) - { - wiegandRead(); - } - - else if (config.readertype == READER_PN532_RDM6300 && uid.length() == 0) - { - pn532Read(); - } + } + + if (config.readertype == READER_MFRC522_RDM6300 && uid.length() == 0) { + mfrc522Read(); + } else if (config.readertype == READER_WIEGAND_RDM6300 && uid.length() == 0) { + wiegandRead(); + } else if (config.readertype == READER_PN532_RDM6300 && uid.length() == 0) { + pn532Read(); + } } #endif void rfidRead() { - if (rfidState == cardSwiped) - { - return; - } + if (rfidState == cardSwiped) { + return; + } #ifdef OFFICIALBOARD - wiegandRead(); + wiegandRead(); #endif #ifndef OFFICIALBOARD - if (config.readertype == READER_MFRC522) - { - mfrc522Read(); - } - else if (config.readertype == READER_WIEGAND) - { - wiegandRead(); - } - else if (config.readertype == READER_PN532) - { - pn532Read(); - } - else if (config.readertype > READER_PN532) - { - genericRead(); - } + if (config.readertype == READER_MFRC522) { + mfrc522Read(); + } else if (config.readertype == READER_WIEGAND) { + wiegandRead(); + } else if (config.readertype == READER_PN532) { + pn532Read(); + } else if (config.readertype > READER_PN532) { + genericRead(); + } #endif } void pinCodeRead() { #ifndef OFFICIALBOARD - if (config.readertype != READER_WIEGAND) - { - return; - } + if (config.readertype != READER_WIEGAND) { + return; + } #endif - if (rfidState != waitingForPincode || !config.pinCodeRequested || !wiegandAvailable) - { - return; - } - - // if we get a 4 bit burst then a key has been pressed - // add the key to the current input and reset the Waiting time - // for the next key unless * or # have been pressed - // we do not require * as the first character because some - // readers use this as special admin code and would hence require *#PIN# - if (wg.getWiegandType() == WIEGANDTYPE_KEYPRESS4 || wg.getWiegandType() == WIEGANDTYPE_KEYPRESS8) - { - if (wg.getCode() != WIEGAND_ENT && wg.getCode() != WIEGAND_ESC) // normal key entry, add to currentInput - { + if (rfidState != waitingForPincode || !config.pinCodeRequested || !wiegandAvailable) { + return; + } + + // if we get a 4 bit burst then a key has been pressed + // add the key to the current input and reset the Waiting time + // for the next key unless * or # have been pressed + // we do not require * as the first character because some + // readers use this as special admin code and would hence require *#PIN# + if (wg.getWiegandType() == WIEGANDTYPE_KEYPRESS4 || wg.getWiegandType() == WIEGANDTYPE_KEYPRESS8) { + if (wg.getCode() != WIEGAND_ENT && wg.getCode() != WIEGAND_ESC) { // normal key entry, add to currentInput #ifdef DEBUG - Serial.println("Keycode captured. . ."); + Serial.println("Keycode captured. . ."); #endif - currentInput = currentInput + String(wg.getCode()); - keyTimer = millis(); - } else if (keyTimer > 0) // if we are waiting on input still - { - if(wg.getCode() == WIEGAND_ESC) // esc, abort pincode - { + currentInput = currentInput + String(wg.getCode()); + keyTimer = millis(); + } else if (keyTimer > 0) { // if we are waiting on input still + if (wg.getCode() == WIEGAND_ESC) { // esc, abort pincode #ifdef DEBUG - Serial.println("Keycode escape, aborting pincode entry"); + Serial.println("Keycode escape, aborting pincode entry"); #endif - rfidState = waitingCard; - processingState = unknown; - cooldown = millis() + COOLDOWN_MILIS; - } - if(wg.getCode() == WIEGAND_ENT) // enter, process pincode - { - pinCode = currentInput; - rfidState = cardAndPincodePresented; + rfidState = waitingCard; + processingState = unknown; + cooldown = millis() + COOLDOWN_MILIS; + } + if (wg.getCode() == WIEGAND_ENT) { // enter, process pincode + pinCode = currentInput; + rfidState = cardAndPincodePresented; #ifdef DEBUG - Serial.println("Stop capture keycode . . ."); - Serial.print(F("[ INFO ] PICC's pin code: ")); - Serial.println(currentInput); + Serial.println("Stop capture keycode . . ."); + Serial.print(F("[ INFO ] PICC's pin code: ")); + Serial.println(currentInput); #endif - currentInput = ""; - keyTimer = 0; - cooldown = millis() + COOLDOWN_MILIS; - } - } - } + currentInput = ""; + keyTimer = 0; + cooldown = millis() + COOLDOWN_MILIS; + } + } + } } -int weekdayFromMonday(int weekdayFromSunday) { - // we expect weeks starting from Sunday equals to 1 - // we return week day starting from Monday equals to 0 - return ( weekdayFromSunday + 5 ) % 7; +int weekdayFromMonday(int weekdayFromSunday) +{ + // we expect weeks starting from Sunday equals to 1 + // we return week day starting from Monday equals to 0 + return (weekdayFromSunday + 5) % 7; } void rfidProcess() { - if ((config.pinCodeRequested && rfidState != cardAndPincodePresented) || (!config.pinCodeRequested && rfidState != cardSwiped)) - { - return; - } - - File f = SPIFFS.open("/P/" + uid, "r"); - if (!f) - { - processingState = unknown; - return; - } - - size_t size = f.size(); - std::unique_ptr buf(new char[size]); - f.readBytes(buf.get(), size); - f.close(); - DynamicJsonDocument json(512); - auto error = deserializeJson(json, buf.get()); - if (error) - { - processingState = notValid; + if ((config.pinCodeRequested && rfidState != cardAndPincodePresented) || + (!config.pinCodeRequested && rfidState != cardSwiped)) { + return; + } + + File f = SPIFFS.open("/P/" + uid, "r"); + + if (!f) { + processingState = unknown; + return; + } + + size_t size = f.size(); + + std::unique_ptr < char[] > buf(new char[size]); + + f.readBytes(buf.get(), size); + f.close(); + DynamicJsonDocument json(512); + auto error = deserializeJson(json, buf.get()); + + if (error) { + processingState = notValid; #ifdef DEBUG - Serial.println(""); - Serial.println(F("[ WARN ] Failed to parse User Data")); + Serial.println(""); + Serial.println(F("[ WARN ] Failed to parse User Data")); #endif - return; - } + return; + } - // if the pin code is wrong we deny access - if(config.pinCodeRequested && pinCode != json["pincode"]) - { - processingState = wrongPincode; + // if the pin code is wrong we deny access + if (config.pinCodeRequested && pinCode != json["pincode"]) { + processingState = wrongPincode; #ifdef DEBUG - Serial.println("Wrong pin code"); + Serial.println("Wrong pin code"); #endif - return; - } + return; + } - accountType = json["acctype"]; - username = json["user"].as(); + accountType = json["acctype"]; + username = json["user"].as < String > (); #ifdef DEBUG - Serial.println(" = known PICC"); - Serial.print("[ INFO ] User Name: "); - if (username == "undefined") - Serial.print(uid); - else - Serial.print(username); + Serial.println(" = known PICC"); + Serial.print("[ INFO ] User Name: "); + if (username == "undefined") { + Serial.print(uid); + } else { + Serial.print(username); + } #endif - if (accountType == ACCESS_GRANTED) - { - unsigned long validL = json["validuntil"]; - unsigned long nowL = now(); - int hourTz = hour() + config.timeZone; - bool officeHour = config.openingHours[weekdayFromMonday(weekday())][hourTz] == '1'; - if (validL < nowL) - { - processingState = expired; - } else if (!officeHour) - { - processingState = notValid; - } else - { - processingState = valid; - } - } else if (accountType == ACCESS_ADMIN) - { - doEnableWifi = true; - processingState = validAdmin; - } else { - processingState = notValid; - } - - if (processingState == valid || processingState == validAdmin) - { - for (int currentRelay = 0; currentRelay < config.numRelays; currentRelay++) - { - if (currentRelay == 0) { - activateRelay[currentRelay] = true; - } else { - bool isRelayActive = json["acctype" + String(currentRelay + 1)] == ACCESS_GRANTED; - activateRelay[currentRelay] = isRelayActive; - } - if (processingState == validAdmin) - { - activateRelay[currentRelay] = true; - } - } - } + if (accountType == ACCESS_GRANTED) { + unsigned long validL = json["validuntil"]; + unsigned long nowL = now(); + int hourTz = hour() + config.timeZone; + bool officeHour = config.openingHours[weekdayFromMonday(weekday())][hourTz] == '1'; + if (validL < nowL) { + processingState = expired; + } else if (!officeHour) { + processingState = notValid; + } else { + processingState = valid; + } + } else if (accountType == ACCESS_ADMIN) { + doEnableWifi = true; + processingState = validAdmin; + } else { + processingState = notValid; + } + + if (processingState == valid || processingState == validAdmin) { + for (int currentRelay = 0; currentRelay < config.numRelays; currentRelay++) { + if (currentRelay == 0) { + activateRelay[currentRelay] = true; + } else { + bool isRelayActive = json["acctype" + String(currentRelay + 1)] == ACCESS_GRANTED; + activateRelay[currentRelay] = isRelayActive; + } + if (processingState == validAdmin) { + activateRelay[currentRelay] = true; + } + } + } } void rfidOutsideMessaging() { - if (processingState == valid) - { - ws.textAll("{\"command\":\"giveAccess\"}"); + if (processingState == valid) { + ws.textAll("{\"command\":\"giveAccess\"}"); #ifdef DEBUG - Serial.printf(" has access relay"); + Serial.printf(" has access relay"); #endif - mqttPublishAccess(now(), "true", "Always", username, uid); - beeperValidAccess(); - } - if (processingState == validAdmin) - { - ws.textAll("{\"command\":\"giveAccess\"}"); + mqttPublishAccess(now(), "true", "Always", username, uid); + beeperValidAccess(); + } + if (processingState == validAdmin) { + ws.textAll("{\"command\":\"giveAccess\"}"); #ifdef DEBUG - Serial.println(" has admin access, enable wifi"); + Serial.println(" has admin access, enable wifi"); #endif - mqttPublishAccess(now(), "true", "Admin", username, uid); - beeperAdminAccess(); - } - if (processingState == expired) - { + mqttPublishAccess(now(), "true", "Admin", username, uid); + beeperAdminAccess(); + } + if (processingState == expired) { #ifdef DEBUG - Serial.println(" expired"); + Serial.println(" expired"); #endif - mqttPublishAccess(now(), "true", "Expired", username, uid); - ledAccessDeniedOn(); - beeperAccessDenied(); - } - if (processingState == wrongPincode) - { - mqttPublishAccess(now(), "true", "Wrong pin code", username, uid); - ledAccessDeniedOn(); - beeperAccessDenied(); - } - if (processingState == notValid) - { + mqttPublishAccess(now(), "true", "Expired", username, uid); + ledAccessDeniedOn(); + beeperAccessDenied(); + } + if (processingState == wrongPincode) { + mqttPublishAccess(now(), "true", "Wrong pin code", username, uid); + ledAccessDeniedOn(); + beeperAccessDenied(); + } + if (processingState == notValid) { #ifdef DEBUG - Serial.println(" does not have access"); + Serial.println(" does not have access"); #endif - mqttPublishAccess(now(), "true", "Disabled", username, uid); - ledAccessDeniedOn(); - beeperAccessDenied(); - } - if (processingState == unknown) - { - String data = String(uid) += " " + String(type); - writeEvent("WARN", "rfid", "Unknown rfid tag is scanned", data); - writeLatest(uid, "Unknown", 98); - DynamicJsonDocument root(512); - root["command"] = "piccscan"; - root["uid"] = uid; - root["type"] = type; - root["known"] = 0; - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - } - mqttPublishAccess(now(), "false", "Denied", "Unknown", uid); - ledAccessDeniedOn(); - beeperAccessDenied(); - } - if (uid != "") - { - writeLatest(uid, username, accountType); - DynamicJsonDocument root(512); - root["command"] = "piccscan"; - root["uid"] = uid; - root["type"] = type; - root["known"] = 1; - root["acctype"] = accountType; - root["user"] = username; - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - } - } + mqttPublishAccess(now(), "true", "Disabled", username, uid); + ledAccessDeniedOn(); + beeperAccessDenied(); + } + if (processingState == unknown) { + String data = String(uid) += " " + String(type); + writeEvent("WARN", "rfid", "Unknown rfid tag is scanned", data); + writeLatest(uid, "Unknown", 98); + DynamicJsonDocument root(512); + root["command"] = "piccscan"; + root["uid"] = uid; + root["type"] = type; + root["known"] = 0; + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + } + mqttPublishAccess(now(), "false", "Denied", "Unknown", uid); + ledAccessDeniedOn(); + beeperAccessDenied(); + } + if (uid != "") { + writeLatest(uid, username, accountType); + DynamicJsonDocument root(512); + root["command"] = "piccscan"; + root["uid"] = uid; + root["type"] = type; + root["known"] = 1; + root["acctype"] = accountType; + root["user"] = username; + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + } + } } void cleanRfidLoop() { - if (rfidState == waitingCard) - { - delay(50); - } - // Keep an eye on timeout waiting for keypress - // Clear code and timer when timeout is reached - if ((keyTimer > 0 && millis() - keyTimer >= KEYBOARD_TIMEOUT_MILIS) || processingState != waiting) - { + if (rfidState == waitingCard) { + delay(50); + } + // Keep an eye on timeout waiting for keypress + // Clear code and timer when timeout is reached + if ((keyTimer > 0 && millis() - keyTimer >= KEYBOARD_TIMEOUT_MILIS) || processingState != waiting) { #ifdef DEBUG - Serial.println("[ INFO ] Read timeout or clean after read"); + Serial.println("[ INFO ] Read timeout or clean after read"); #endif - keyTimer = 0; - currentInput = ""; - type = ""; - uid = ""; - rfidState = waitingCard; - processingState = waiting; - ledWaitingOff(); - } + keyTimer = 0; + currentInput = ""; + type = ""; + uid = ""; + rfidState = waitingCard; + processingState = waiting; + ledWaitingOff(); + } } void rfidLoop() { - rfidPrepareRead(); - rfidRead(); - pinCodeRead(); - rfidProcess(); - rfidOutsideMessaging(); - cleanRfidLoop(); + rfidPrepareRead(); + rfidRead(); + pinCodeRead(); + rfidProcess(); + rfidOutsideMessaging(); + cleanRfidLoop(); } #ifndef OFFICIALBOARD #ifdef DEBUG void ICACHE_FLASH_ATTR ShowMFRC522ReaderDetails() { - // Get the MFRC522 software version - byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); - Serial.print(F("[ INFO ] MFRC522 Version: 0x")); - Serial.print(v, HEX); - if (v == 0x91) - Serial.print(F(" = v1.0")); - else if (v == 0x92) - Serial.print(F(" = v2.0")); - else if (v == 0x88) - Serial.print(F(" = clone")); - else - Serial.print(F(" (unknown)")); - Serial.println(""); - // When 0x00 or 0xFF is returned, communication probably failed - if ((v == 0x00) || (v == 0xFF)) - { - Serial.println(F("[ WARN ] Communication failure, check if MFRC522 properly connected")); - } + // Get the MFRC522 software version + byte v = mfrc522.PCD_ReadRegister(mfrc522.VersionReg); + + Serial.print(F("[ INFO ] MFRC522 Version: 0x")); + Serial.print(v, HEX); + if (v == 0x91) { + Serial.print(F(" = v1.0")); + } else if (v == 0x92) { + Serial.print(F(" = v2.0")); + } else if (v == 0x88) { + Serial.print(F(" = clone")); + } else { + Serial.print(F(" (unknown)")); + } + Serial.println(""); + // When 0x00 or 0xFF is returned, communication probably failed + if ((v == 0x00) || (v == 0xFF)) { + Serial.println(F("[ WARN ] Communication failure, check if MFRC522 properly connected")); + } } #endif #endif void ICACHE_FLASH_ATTR setupWiegandReader(int d0, int d1) { - wg.begin(d0, d1); + wg.begin(d0, d1); } #ifndef OFFICIALBOARD void ICACHE_FLASH_ATTR setupMFRC522Reader(int rfidss, int rfidgain) { - SPI.begin(); // MFRC522 Hardware uses SPI protocol - mfrc522.PCD_Init(rfidss, UINT8_MAX); // Initialize MFRC522 Hardware - // Set RFID Hardware Antenna Gain - // This may not work with some boards - mfrc522.PCD_SetAntennaGain(rfidgain); + SPI.begin(); // MFRC522 Hardware uses SPI protocol + mfrc522.PCD_Init(rfidss, UINT8_MAX); // Initialize MFRC522 Hardware + // Set RFID Hardware Antenna Gain + // This may not work with some boards + mfrc522.PCD_SetAntennaGain(rfidgain); #ifdef DEBUG - Serial.printf("[ INFO ] RFID SS_PIN: %u and Gain Factor: %u", rfidss, rfidgain); - Serial.println(""); + Serial.printf("[ INFO ] RFID SS_PIN: %u and Gain Factor: %u", rfidss, rfidgain); + Serial.println(""); #endif #ifdef DEBUG - ShowMFRC522ReaderDetails(); // Show details of PCD - MFRC522 Card Reader details + ShowMFRC522ReaderDetails(); // Show details of PCD - MFRC522 Card Reader details #endif } #endif @@ -509,35 +460,33 @@ void ICACHE_FLASH_ATTR setupMFRC522Reader(int rfidss, int rfidgain) #ifndef OFFICIALBOARD void ICACHE_FLASH_ATTR setupPN532Reader(int rfidss) { - // init controller - pn532.InitSoftwareSPI(14, 12, 13, rfidss, 0); - do - { // pseudo loop (just used for aborting with break;) - // Reset the PN532 - pn532.begin(); // delay > 400 ms - byte IC, VersionHi, VersionLo, Flags; - if (!pn532.GetFirmwareVersion(&IC, &VersionHi, &VersionLo, &Flags)) - break; + // init controller + pn532.InitSoftwareSPI(14, 12, 13, rfidss, 0); + do{ // pseudo loop (just used for aborting with break;) + // Reset the PN532 + pn532.begin(); // delay > 400 ms + byte IC, VersionHi, VersionLo, Flags; + if (!pn532.GetFirmwareVersion(&IC, &VersionHi, &VersionLo, &Flags)) { + break; + } #ifdef DEBUG - char Buf[80]; - sprintf(Buf, "Chip: PN5%02X, Firmware version: %d.%d\r\n", IC, VersionHi, VersionLo); - Utils::Print(Buf); - sprintf(Buf, "Supports ISO 14443A:%s, ISO 14443B:%s, ISO 18092:%s\r\n", (Flags & 1) ? "Yes" : "No", - (Flags & 2) ? "Yes" : "No", - (Flags & 4) ? "Yes" : "No"); - Utils::Print(Buf); + char Buf[80]; + sprintf(Buf, "Chip: PN5%02X, Firmware version: %d.%d\r\n", IC, VersionHi, VersionLo); + Utils::Print(Buf); + sprintf(Buf, "Supports ISO 14443A:%s, ISO 14443B:%s, ISO 18092:%s\r\n", (Flags & 1) ? "Yes" : "No", + (Flags & 2) ? "Yes" : "No", + (Flags & 4) ? "Yes" : "No"); + Utils::Print(Buf); #endif - // Set the max number of retry attempts to read from a card. - // This prevents us from waiting forever for a card, which is the default behaviour of the PN532. - if (!pn532.SetPassiveActivationRetries()) - { - break; - } - // configure the PN532 to read RFID tags - if (!pn532.SamConfig()) - { - break; - } - } while (false); + // Set the max number of retry attempts to read from a card. + // This prevents us from waiting forever for a card, which is the default behaviour of the PN532. + if (!pn532.SetPassiveActivationRetries()) { + break; + } + // configure the PN532 to read RFID tags + if (!pn532.SamConfig()) { + break; + } + } while (false); } #endif diff --git a/src/rfid125kHz.cpp b/src/rfid125kHz.cpp index 77c18474..667ce2df 100644 --- a/src/rfid125kHz.cpp +++ b/src/rfid125kHz.cpp @@ -1,222 +1,205 @@ /* -RFID reader. -Based on the "RFID_Readerer" library (https://github.com/travisfarmer) from Travis Farmer. - -================================================================== -Copyright (c) 2018 Lubos Ruckl - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -================================================================== - -Hardware: RDM6300 or RF125-PS or Gwiot 7941E -Uses 125KHz RFID tags. -*/ + * RFID reader. + * Based on the "RFID_Readerer" library (https://github.com/travisfarmer) from Travis Farmer. + * + * ================================================================== + * Copyright (c) 2018 Lubos Ruckl + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * ================================================================== + * + * Hardware: RDM6300 or RF125-PS or Gwiot 7941E + * Uses 125KHz RFID tags. + */ #include "Arduino.h" #include "rfid125kHz.h" char *RFID_Reader::ulltostr(unsigned long long value, char *ptr, int base) { - unsigned long long t = 0, res = 0; - unsigned long long tmp = value; - int count = 0; - if (NULL == ptr) - { - return NULL; - } - if (tmp == 0) - { - count++; - } - while (tmp > 0) - { - tmp = tmp / base; - count++; - } - ptr += count; - *ptr = '\0'; - do - { - res = value - base * (t = value / base); - if (res < 10) - { - *--ptr = '0' + res; + unsigned long long t = 0, res = 0; + unsigned long long tmp = value; + int count = 0; + + if (NULL == ptr) { + return NULL; + } + if (tmp == 0) { + count++; } - else if ((res >= 10) && (res < 16)) - { - *--ptr = 'A' - 10 + res; + while (tmp > 0) { + tmp = tmp / base; + count++; } - } while ((value = t) != 0); - return (ptr); + ptr += count; + *ptr = '\0'; + do{ + res = value - base * (t = value / base); + if (res < 10) { + *--ptr = '0' + res; + } else if ((res >= 10) && (res < 16)) { + *--ptr = 'A' - 10 + res; + } + } while ((value = t) != 0); + return ptr; } /* -this is to simply return true when there is RFID data available. -it is a function to prevent external manipulation of the boolean variable. -*/ + * this is to simply return true when there is RFID data available. + * it is a function to prevent external manipulation of the boolean variable. + */ bool RFID_Reader::Available() { - return (data_available); + return data_available; } /* -Returns the ID hexadecimal representation, and resets the Available flag. -*/ + * Returns the ID hexadecimal representation, and resets the Available flag. + */ String RFID_Reader::GetHexID() { - if (data_available) - { - uint8_t b[5]; - memcpy(b, &new_ID, 5); - char buf[11]; - sprintf(buf, "%02x%02x%02x%02x%02x", b[4], b[3], b[2], b[1], b[0]); - lasttagtype = tagtype; - data_available = false; - return String(buf); - } - return "None"; + if (data_available) { + uint8_t b[5]; + memcpy(b, &new_ID, 5); + char buf[11]; + sprintf(buf, "%02x%02x%02x%02x%02x", b[4], b[3], b[2], b[1], b[0]); + lasttagtype = tagtype; + data_available = false; + return String(buf); + } + return "None"; } /* -Returns Tag type. -*/ + * Returns Tag type. + */ String RFID_Reader::GetTagType() { - for (uint8_t x = 0; x < 12; x++) - { - if (typeDict[x].itype == lasttagtype) - return String(typeDict[x].stype); - } - return "Unknown"; + for (uint8_t x = 0; x < 12; x++) { + if (typeDict[x].itype == lasttagtype) { + return String(typeDict[x].stype); + } + } + return "Unknown"; } /* -Returns the ID decimal representation, and resets the Available flag. -*/ + * Returns the ID decimal representation, and resets the Available flag. + */ String RFID_Reader::GetDecID() { - if (data_available) - { - char ptr[128]; - ulltostr(new_ID, ptr, 10); - lasttagtype = tagtype; - data_available = false; - return String(ptr); - } - return "None"; + if (data_available) { + char ptr[128]; + ulltostr(new_ID, ptr, 10); + lasttagtype = tagtype; + data_available = false; + return String(ptr); + } + return "None"; } void RFID_Reader::rfidSerial(char x) { - //if (x == StartByte && (ix==0 || ix > 1)) - if (x == StartByte && ix != 1) - { - ix = 0; - } - else if (x == EndByte) - { - msg[ix] = '\0'; - msgLen = ix; - parse(); - ix = 0; - } - else - { - msg[ix] = x; - ix++; - } + //if (x == StartByte && (ix==0 || ix > 1)) + if (x == StartByte && ix != 1) { + ix = 0; + } else if (x == EndByte) { + msg[ix] = '\0'; + msgLen = ix; + parse(); + ix = 0; + } else { + msg[ix] = x; + ix++; + } } uint8_t RFID_Reader::get_checksum(unsigned long long data) { - uint8_t b[5]; - memcpy(b, &data, 5); - return b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4]; + uint8_t b[5]; + + memcpy(b, &data, 5); + return b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4]; } uint8_t RFID_Reader::char2int(char c) { - c -= asciiNum_diff; - if (c > 9) - c -= asciiUpp_diff; - return c; + c -= asciiNum_diff; + if (c > 9) { + c -= asciiUpp_diff; + } + return c; } /* -the module spits out HEX values, we need to convert them to an unsigned long. -*/ + * the module spits out HEX values, we need to convert them to an unsigned long. + */ void RFID_Reader::parse() { - uint8_t lshift = 40; - unsigned long long val = 0; - unsigned long long tagIdValue = 0; - uint8_t i; - uint8_t checksum = 0; - uint8_t recChecksum = 0; - if ((msgLen + 2) == msg[0]) //Gwiot 7941E - { - for (i = 0; i < msgLen - 1; i++) - { - val = msg[i]; - checksum = checksum ^ val; - if (i > 1) - { - //lshift = 8 * (msgLen - 2 - i); - lshift = (msgLen - 2 - i) << 3; - tagIdValue |= val << lshift; - } + uint8_t lshift = 40; + unsigned long long val = 0; + unsigned long long tagIdValue = 0; + uint8_t i; + uint8_t checksum = 0; + uint8_t recChecksum = 0; + + if ((msgLen + 2) == msg[0]) { //Gwiot 7941E + for (i = 0; i < msgLen - 1; i++) { + val = msg[i]; + checksum = checksum ^ val; + if (i > 1) { + //lshift = 8 * (msgLen - 2 - i); + lshift = (msgLen - 2 - i) << 3; + tagIdValue |= val << lshift; + } + } + recChecksum = (uint8_t)msg[i]; + tagtype = (uint8_t)msg[1]; + } else { + for (i = 0; i < 10; i++) { + val = char2int(msg[i]); + //lshift = 4 * (9 - i); + lshift -= 4; + tagIdValue |= val << lshift; + } + checksum = get_checksum(tagIdValue); + new_ID = 0ULL; + if (msgLen == 12) { + recChecksum = char2int(msg[i + 1]) | char2int(msg[i]) << 4; + } //RDM6300 + else if (msgLen == 11) { + recChecksum = (uint8_t)msg[i]; + } //RF125-PS + tagtype = 2; } - recChecksum = (uint8_t)msg[i]; - tagtype = (uint8_t)msg[1]; - } - else - { - for (i = 0; i < 10; i++) - { - val = char2int(msg[i]); - //lshift = 4 * (9 - i); - lshift -= 4; - tagIdValue |= val << lshift; + if (checksum != recChecksum) { + return; + } + unsigned long _now = millis(); + + if ((_now - LastRFID > 3000) || (tagIdValue != last_ID)) { + new_ID = tagIdValue; + last_ID = tagIdValue; + data_available = true; + LastRFID = _now; } - checksum = get_checksum(tagIdValue); - new_ID = 0ULL; - if (msgLen == 12) - { - recChecksum = char2int(msg[i + 1]) | char2int(msg[i]) << 4; - } //RDM6300 - else if (msgLen == 11) - { - recChecksum = (uint8_t)msg[i]; - } //RF125-PS - tagtype = 2; - } - if (checksum != recChecksum) - return; - unsigned long _now = millis(); - if ((_now - LastRFID > 3000) || (tagIdValue != last_ID)) - { - new_ID = tagIdValue; - last_ID = tagIdValue; - data_available = true; - LastRFID = _now; - } } diff --git a/src/rfid125kHz.h b/src/rfid125kHz.h index 1c6566a3..1f4fc5d0 100644 --- a/src/rfid125kHz.h +++ b/src/rfid125kHz.h @@ -1,35 +1,35 @@ /* -RFID reader. -Based on the "rfid_reader" library (https://github.com/travisfarmer) from Travis Farmer. - -================================================================== -Copyright (c) 2018 Lubos Ruckl - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. -================================================================== - -Hardware: RDM6300 or RF125-PS or Gwiot 7941E -Uses 125KHz RFID tags. -*/ + * RFID reader. + * Based on the "rfid_reader" library (https://github.com/travisfarmer) from Travis Farmer. + * + * ================================================================== + * Copyright (c) 2018 Lubos Ruckl + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * ================================================================== + * + * Hardware: RDM6300 or RF125-PS or Gwiot 7941E + * Uses 125KHz RFID tags. + */ #ifndef rfid125kHz_h #define rfid125kHz_h @@ -63,24 +63,23 @@ class RFID_Reader byte ix = 0; byte StartByte = 0x02; byte EndByte = 0x03; - typedef struct - { + typedef struct { uint8_t itype; - char *stype; + char * stype; } typeDictionary; const typeDictionary typeDict[12]{ - {0x01, (char *)"MIFARE 1K"}, - {0x02, (char *)"EM4100"}, - {0x03, (char *)"MIFARE 4K"}, - {0x10, (char *)"HID card"}, - {0x11, (char *)"T5567"}, - {0x20, (char *)"2G certificate"}, - {0x21, (char *)"IS014443B"}, - {0x22, (char *)"FELICA"}, - {0x30, (char *)"15693 tag"}, - {0x50, (char *)"CPU card"}, - {0x51, (char *)"sector information"}, - {0xFF, (char *)"keyboard data"}}; + { 0x01, (char *)"MIFARE 1K" }, + { 0x02, (char *)"EM4100" }, + { 0x03, (char *)"MIFARE 4K" }, + { 0x10, (char *)"HID card" }, + { 0x11, (char *)"T5567" }, + { 0x20, (char *)"2G certificate" }, + { 0x21, (char *)"IS014443B" }, + { 0x22, (char *)"FELICA" }, + { 0x30, (char *)"15693 tag" }, + { 0x50, (char *)"CPU card" }, + { 0x51, (char *)"sector information" }, + { 0xFF, (char *)"keyboard data" } }; }; #endif diff --git a/src/webserver.esp b/src/webserver.esp index 16ceb8b5..8de4e66c 100644 --- a/src/webserver.esp +++ b/src/webserver.esp @@ -1,96 +1,103 @@ -void ICACHE_FLASH_ATTR setupWebServer() { - server.addHandler(&ws); - ws.onEvent(onWsEvent); - server.onNotFound([](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse(404, "text/plain", "Not found"); - request->send(response); - }); - server.on("/update", HTTP_POST, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse * response = request->beginResponse(200, "text/plain", shouldReboot ? "OK" : "FAIL"); - response->addHeader("Connection", "close"); - request->send(response); - }, [](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { - if (!request->authenticate(httpUsername, config.httpPass)) { - return; - } - if (!index) { - writeEvent("INFO", "updt", "Firmware update started", filename.c_str()); - Update.runAsync(true); - if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) { - writeEvent("ERRO", "updt", "Not enough space to update",""); - #ifdef DEBUG - Update.printError(Serial); - #endif - } - } - if (!Update.hasError()) { - if (Update.write(data, len) != len) { - writeEvent("ERRO", "updt", "Writing to flash is failed", filename.c_str()); - #ifdef DEBUG - Update.printError(Serial); - #endif - } - } - if (final) { - if (Update.end(true)) { - writeEvent("INFO", "updt", "Firmware update is finished", ""); +void ICACHE_FLASH_ATTR setupWebServer() +{ + server.addHandler(&ws); + ws.onEvent(onWsEvent); + server.onNotFound([] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse(404, "text/plain", "Not found"); + request->send(response); + }); + server.on("/update", HTTP_POST, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse(200, "text/plain", shouldReboot ? "OK" : "FAIL"); + response->addHeader("Connection", "close"); + request->send(response); + }, [] (AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) { + if (!request->authenticate(httpUsername, config.httpPass)) { + return; + } + if (!index) { + writeEvent("INFO", "updt", "Firmware update started", filename.c_str()); + Update.runAsync(true); + if (!Update.begin((ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000)) { + writeEvent("ERRO", "updt", "Not enough space to update", ""); #ifdef DEBUG - Serial.printf("[ UPDT ] Firmware update finished: %uB\n", index + len); + Update.printError(Serial); #endif - shouldReboot = !Update.hasError(); - } else { - writeEvent("ERRO", "updt", "Update is failed", ""); - #ifdef DEBUG - Update.printError(Serial); - #endif - } - } - }); - server.on("/fonts/glyphicons-halflings-regular.woff", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "font/woff", glyphicons_halflings_regular_woff_gz, glyphicons_halflings_regular_woff_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); - server.on("/css/required.css", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/css", required_css_gz, required_css_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); - server.on("/js/required.js", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/javascript", required_js_gz, required_js_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); - server.on("/js/esprfid.js", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/javascript", esprfid_js_gz, esprfid_js_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); + } + } + if (!Update.hasError()) { + if (Update.write(data, len) != len) { + writeEvent("ERRO", "updt", "Writing to flash is failed", filename.c_str()); +#ifdef DEBUG + Update.printError(Serial); +#endif + } + } + if (final) { + if (Update.end(true)) { + writeEvent("INFO", "updt", "Firmware update is finished", ""); +#ifdef DEBUG + Serial.printf("[ UPDT ] Firmware update finished: %uB\n", index + len); +#endif + shouldReboot = !Update.hasError(); + } else { + writeEvent("ERRO", "updt", "Update is failed", ""); +#ifdef DEBUG + Update.printError(Serial); +#endif + } + } + }); + server.on("/fonts/glyphicons-halflings-regular.woff", HTTP_GET, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = + request->beginResponse_P(200, "font/woff", glyphicons_halflings_regular_woff_gz, + glyphicons_halflings_regular_woff_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); + server.on("/css/required.css", HTTP_GET, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/css", required_css_gz, required_css_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); + server.on("/js/required.js", HTTP_GET, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/javascript", required_js_gz, required_js_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); + server.on("/js/esprfid.js", HTTP_GET, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = + request->beginResponse_P(200, "text/javascript", esprfid_js_gz, esprfid_js_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); - server.on("/index.html", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, index_html_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); + server.on("/index.html", HTTP_GET, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", index_html_gz, index_html_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); - server.on("/esprfid.htm", HTTP_GET, [](AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", esprfid_htm_gz, esprfid_htm_gz_len); - response->addHeader("Content-Encoding", "gzip"); - request->send(response); - }); + server.on("/esprfid.htm", HTTP_GET, [] (AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", esprfid_htm_gz, + esprfid_htm_gz_len); + response->addHeader("Content-Encoding", "gzip"); + request->send(response); + }); - if (config.httpPass == NULL) { - config.httpPass = strdup("admin"); - } - server.on("/login", HTTP_GET, [](AsyncWebServerRequest *request) { - String remoteIP = printIP(request->client()->remoteIP()); - if (!request->authenticate(httpUsername, config.httpPass)) { - writeEvent("WARN", "websrv", "New login attempt", remoteIP); - return request->requestAuthentication(); - } - request->send(200, "text/plain", "Success"); - writeEvent("INFO", "websrv", "Login success!", remoteIP); - }); - server.rewrite("/", "/index.html"); - server.begin(); -} \ No newline at end of file + if (config.httpPass == NULL) { + config.httpPass = strdup("admin"); + } + server.on("/login", HTTP_GET, [] (AsyncWebServerRequest *request) { + String remoteIP = printIP(request->client()->remoteIP()); + if (!request->authenticate(httpUsername, config.httpPass)) { + writeEvent("WARN", "websrv", "New login attempt", remoteIP); + return request->requestAuthentication(); + } + request->send(200, "text/plain", "Success"); + writeEvent("INFO", "websrv", "Login success!", remoteIP); + }); + server.rewrite("/", "/index.html"); + server.begin(); +} diff --git a/src/websocket.esp b/src/websocket.esp index 0b794d17..d161c87f 100644 --- a/src/websocket.esp +++ b/src/websocket.esp @@ -1,217 +1,165 @@ void ICACHE_FLASH_ATTR procMsg(AsyncWebSocketClient *client, size_t sz) { - // We should always get a JSON object (stringfied) from browser, so parse it - DynamicJsonDocument root(8192); - char json[sz + 1]; - memcpy(json, (char *)(client->_tempObject), sz); - json[sz] = '\0'; - auto error = deserializeJson(root, json); - if (error) - { + // We should always get a JSON object (stringfied) from browser, so parse it + DynamicJsonDocument root(8192); + char json[sz + 1]; + + memcpy(json, (char *)(client->_tempObject), sz); + json[sz] = '\0'; + auto error = deserializeJson(root, json); + + if (error) { #ifdef DEBUG - Serial.println(F("[ WARN ] Couldn't parse WebSocket message")); + Serial.println(F("[ WARN ] Couldn't parse WebSocket message")); #endif - free(client->_tempObject); - client->_tempObject = NULL; - return; - } - // Web Browser sends some commands, check which command is given - const char *command = root["command"]; - // Check whatever the command is and act accordingly - if (strcmp(command, "remove") == 0) - { - const char *uid = root["uid"]; - String filename = "/P/"; - filename += uid; - SPIFFS.remove(filename); - } - else if (strcmp(command, "configfile") == 0) - { - File f = SPIFFS.open("/config.json", "w+"); - if (f) - { - size_t len = measureJsonPretty(root); - serializeJsonPretty(root, f); - //f.print(msg); - f.close(); - shouldReboot = true; - //ESP.restart(); - writeEvent("INFO", "sys", "Config stored in the SPIFFS", String(len) + " bytes"); - } - } - else if (strcmp(command, "userlist") == 0) - { - int page = root["page"]; - sendUserList(page, client); - } - else if (strcmp(command, "status") == 0) - { - sendStatus(); - } - else if (strcmp(command, "restart") == 0) - { - shouldReboot = true; - } - else if (strcmp(command, "destroy") == 0) - { - formatreq = true; - } - else if (strcmp(command, "geteventlog") == 0) - { - int page = root["page"]; - const char *xfileName = root["filename"]; - sendEventLog(page,xfileName); - } - else if (strcmp(command, "getlatestlog") == 0) - { - int page = root["page"]; - const char *xfileName = root["filename"]; - sendLatestLog(page,xfileName); - } - else if (strcmp(command, "listfiles") == 0) - { - int page = root["page"]; - sendFileList(page); - } - else if (strcmp(command, "logMaintenance") == 0) - { - logMaintenance(root["action"],root["filename"]); - } - else if (strcmp(command, "clearevent") == 0) - { - SPIFFS.remove("/eventlog.json"); - writeEvent("WARN", "sys", "Event log cleared!", ""); - } - else if (strcmp(command, "clearlatest") == 0) - { - SPIFFS.remove("/latestlog.json"); - writeEvent("WARN", "sys", "Latest Access log cleared!", ""); - } - else if (strcmp(command, "userfile") == 0) - { + free(client->_tempObject); + client->_tempObject = NULL; + return; + } + // Web Browser sends some commands, check which command is given + const char *command = root["command"]; + // Check whatever the command is and act accordingly + if (strcmp(command, "remove") == 0) { + const char *uid = root["uid"]; + String filename = "/P/"; + filename += uid; + SPIFFS.remove(filename); + } else if (strcmp(command, "configfile") == 0) { + File f = SPIFFS.open("/config.json", "w+"); + if (f) { + size_t len = measureJsonPretty(root); + serializeJsonPretty(root, f); + //f.print(msg); + f.close(); + shouldReboot = true; + //ESP.restart(); + writeEvent("INFO", "sys", "Config stored in the SPIFFS", String(len) + " bytes"); + } + } else if (strcmp(command, "userlist") == 0) { + int page = root["page"]; + sendUserList(page, client); + } else if (strcmp(command, "status") == 0) { + sendStatus(); + } else if (strcmp(command, "restart") == 0) { + shouldReboot = true; + } else if (strcmp(command, "destroy") == 0) { + formatreq = true; + } else if (strcmp(command, "geteventlog") == 0) { + int page = root["page"]; + const char *xfileName = root["filename"]; + sendEventLog(page, xfileName); + } else if (strcmp(command, "getlatestlog") == 0) { + int page = root["page"]; + const char *xfileName = root["filename"]; + sendLatestLog(page, xfileName); + } else if (strcmp(command, "listfiles") == 0) { + int page = root["page"]; + sendFileList(page); + } else if (strcmp(command, "logMaintenance") == 0) { + logMaintenance(root["action"], root["filename"]); + } else if (strcmp(command, "clearevent") == 0) { + SPIFFS.remove("/eventlog.json"); + writeEvent("WARN", "sys", "Event log cleared!", ""); + } else if (strcmp(command, "clearlatest") == 0) { + SPIFFS.remove("/latestlog.json"); + writeEvent("WARN", "sys", "Latest Access log cleared!", ""); + } else if (strcmp(command, "userfile") == 0) { #ifdef DEBUG - Serial.println(F("[ DEBUG ] userfile received")); - serializeJson(root, Serial); + Serial.println(F("[ DEBUG ] userfile received")); + serializeJson(root, Serial); #endif - const char *uid = root["uid"]; - String filename = "/P/"; - filename += uid; - File f = SPIFFS.open(filename, "w+"); - // Check if we created the file - if (f) - { - serializeJson(root, f); + const char *uid = root["uid"]; + String filename = "/P/"; + filename += uid; + File f = SPIFFS.open(filename, "w+"); + // Check if we created the file + if (f) { + serializeJson(root, f); #ifdef DEBUG - Serial.println(F("[ DEBUG ] userfile saved")); + Serial.println(F("[ DEBUG ] userfile saved")); #endif - } - f.close(); - ws.textAll("{\"command\":\"result\",\"resultof\":\"userfile\",\"result\": true}"); - } - else if (strcmp(command, "testrelay1") == 0) - { - activateRelay[0] = true; - previousMillis = millis(); - ws.textAll("{\"command\":\"giveAccess\"}"); - } -#ifndef OFFICIALBOARD - else if (strcmp(command, "testrelay2") == 0) - { - activateRelay[1] = true; - previousMillis = millis(); - ws.textAll("{\"command\":\"giveAccess\"}"); - } - else if (strcmp(command, "testrelay3") == 0) - { - activateRelay[2] = true; - previousMillis = millis(); - ws.textAll("{\"command\":\"giveAccess\"}"); - } - else if (strcmp(command, "testrelay4") == 0) - { - activateRelay[3] = true; - previousMillis = millis(); - ws.textAll("{\"command\":\"giveAccess\"}"); - } + } + f.close(); + ws.textAll("{\"command\":\"result\",\"resultof\":\"userfile\",\"result\": true}"); + } else if (strcmp(command, "testrelay1") == 0) { + activateRelay[0] = true; + previousMillis = millis(); + ws.textAll("{\"command\":\"giveAccess\"}"); + } +#ifndef OFFICIALBOARD + else if (strcmp(command, "testrelay2") == 0) { + activateRelay[1] = true; + previousMillis = millis(); + ws.textAll("{\"command\":\"giveAccess\"}"); + } else if (strcmp(command, "testrelay3") == 0) { + activateRelay[2] = true; + previousMillis = millis(); + ws.textAll("{\"command\":\"giveAccess\"}"); + } else if (strcmp(command, "testrelay4") == 0) { + activateRelay[3] = true; + previousMillis = millis(); + ws.textAll("{\"command\":\"giveAccess\"}"); + } #endif - else if (strcmp(command, "scan") == 0) - { - WiFi.scanNetworksAsync(printScanResult, true); - } - else if (strcmp(command, "gettime") == 0) - { - sendTime(); - } - else if (strcmp(command, "settime") == 0) - { - time_t t = root["epoch"]; - setTime(t); - sendTime(); - } - else if (strcmp(command, "getconf") == 0) - { - File configFile = SPIFFS.open("/config.json", "r"); - if (configFile) - { - size_t len = configFile.size(); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); // creates a buffer (len + 1) for you. - if (buffer) - { - configFile.readBytes((char *)buffer->get(), len + 1); - ws.textAll(buffer); - } - configFile.close(); - } - } - free(client->_tempObject); - client->_tempObject = NULL; + else if (strcmp(command, "scan") == 0) { + WiFi.scanNetworksAsync(printScanResult, true); + } else if (strcmp(command, "gettime") == 0) { + sendTime(); + } else if (strcmp(command, "settime") == 0) { + time_t t = root["epoch"]; + setTime(t); + sendTime(); + } else if (strcmp(command, "getconf") == 0) { + File configFile = SPIFFS.open("/config.json", "r"); + if (configFile) { + size_t len = configFile.size(); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); // creates a buffer (len + 1) for you. + if (buffer) { + configFile.readBytes((char *)buffer->get(), len + 1); + ws.textAll(buffer); + } + configFile.close(); + } + } + free(client->_tempObject); + client->_tempObject = NULL; } // Handles WebSocket Events -void ICACHE_FLASH_ATTR onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) +void ICACHE_FLASH_ATTR onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, + uint8_t *data, size_t len) { - if (type == WS_EVT_ERROR) - { + if (type == WS_EVT_ERROR) { #ifdef DEBUG - Serial.printf("[ WARN ] WebSocket[%s][%u] error(%u): %s\r\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data); + Serial.printf("[ WARN ] WebSocket[%s][%u] error(%u): %s\r\n", server->url(), client->id(), *((uint16_t *)arg), + (char *)data); #endif - } - else if (type == WS_EVT_DATA) - { - AwsFrameInfo *info = (AwsFrameInfo *)arg; - uint64_t index = info->index; - uint64_t infolen = info->len; - if (info->final && info->index == 0 && infolen == len) - { - //the whole message is in a single frame and we got all of it's data - client->_tempObject = malloc(len); - if (client->_tempObject != NULL) - { - memcpy((uint8_t *)(client->_tempObject), data, len); - } - procMsg(client, infolen); - } - else - { - //message is comprised of multiple frames or the frame is split into multiple packets - if (index == 0) - { - if (info->num == 0 && client->_tempObject == NULL) - { - client->_tempObject = malloc(infolen); - } - } - if (client->_tempObject != NULL) - { - memcpy((uint8_t *)(client->_tempObject) + index, data, len); - } - if ((index + len) == infolen) - { - if (info->final) - { - procMsg(client, infolen); - } - } - } - } + } else if (type == WS_EVT_DATA) { + AwsFrameInfo *info = (AwsFrameInfo *)arg; + uint64_t index = info->index; + uint64_t infolen = info->len; + if (info->final && info->index == 0 && infolen == len) { + //the whole message is in a single frame and we got all of it's data + client->_tempObject = malloc(len); + if (client->_tempObject != NULL) { + memcpy((uint8_t *)(client->_tempObject), data, len); + } + procMsg(client, infolen); + } else { + //message is comprised of multiple frames or the frame is split into multiple packets + if (index == 0) { + if (info->num == 0 && client->_tempObject == NULL) { + client->_tempObject = malloc(infolen); + } + } + if (client->_tempObject != NULL) { + memcpy((uint8_t *)(client->_tempObject) + index, data, len); + } + if ((index + len) == infolen) { + if (info->final) { + procMsg(client, infolen); + } + } + } + } } diff --git a/src/wifi.esp b/src/wifi.esp index a08c4fd1..e831e0ce 100644 --- a/src/wifi.esp +++ b/src/wifi.esp @@ -1,207 +1,192 @@ void setEnableWifi() { - doEnableWifi = true; + doEnableWifi = true; } void onWifiDisconnect(const WiFiEventStationModeDisconnected &event) { #ifdef DEBUG - Serial.println(F("[ INFO ] WiFi STA Disconnected")); + Serial.println(F("[ INFO ] WiFi STA Disconnected")); #endif - mqttReconnectTimer.detach(); - if (!wifiReconnectTimer.active() && !config.fallbackMode) - { - wifiReconnectTimer.once(300, setEnableWifi); - } - ledWifiOff(); + mqttReconnectTimer.detach(); + if (!wifiReconnectTimer.active() && !config.fallbackMode) { + wifiReconnectTimer.once(300, setEnableWifi); + } + ledWifiOff(); } void onWifiGotIP(const WiFiEventStationModeGotIP &event) { #ifdef DEBUG - Serial.println("[ INFO ] WiFi IP Connected"); + Serial.println("[ INFO ] WiFi IP Connected"); #endif - wifiReconnectTimer.detach(); - ledWifiOn(); + wifiReconnectTimer.detach(); + ledWifiOn(); } -bool ICACHE_FLASH_ATTR startAP(IPAddress apip, IPAddress apsubnet, bool hidden, const char *ssid, const char *password = NULL) +bool ICACHE_FLASH_ATTR startAP(IPAddress apip, IPAddress apsubnet, bool hidden, const char *ssid, + const char *password = NULL) { #ifdef DEBUG - Serial.println(F("[ INFO ] ESP-RFID is running in AP Mode ")); + Serial.println(F("[ INFO ] ESP-RFID is running in AP Mode ")); #endif - WiFi.mode(WIFI_AP); + WiFi.mode(WIFI_AP); #ifdef DEBUG - Serial.print(F("[ INFO ] Configuring access point... ")); + Serial.print(F("[ INFO ] Configuring access point... ")); #endif - WiFi.softAPConfig(apip, apip, apsubnet); - - bool success; - if (hidden) - { - success = WiFi.softAP(ssid, password, 3, true); - } - else - { - success = WiFi.softAP(ssid, password); - } + WiFi.softAPConfig(apip, apip, apsubnet); + + bool success; + if (hidden) { + success = WiFi.softAP(ssid, password, 3, true); + } else { + success = WiFi.softAP(ssid, password); + } #ifdef DEBUG - Serial.println(success ? F("Ready") : F("Failed!")); + Serial.println(success ? F("Ready") : F("Failed!")); #endif - if (success) - { - ledWifiOn(); - } + if (success) { + ledWifiOn(); + } #ifdef DEBUG - IPAddress myIP = WiFi.softAPIP(); + IPAddress myIP = WiFi.softAPIP(); - Serial.print(F("[ INFO ] AP IP address: ")); - Serial.println(myIP); - Serial.printf("[ INFO ] AP SSID: %s\n", ssid); + Serial.print(F("[ INFO ] AP IP address: ")); + Serial.println(myIP); + Serial.printf("[ INFO ] AP SSID: %s\n", ssid); #endif - return success; + return success; } // Fallback to AP Mode, so we can connect to ESP if there is no Internet connection void ICACHE_FLASH_ATTR fallbacktoAPMode() { - config.accessPointMode = true; + config.accessPointMode = true; #ifdef DEBUG - Serial.println(F("[ INFO ] ESP-RFID is running in Fallback AP Mode")); + Serial.println(F("[ INFO ] ESP-RFID is running in Fallback AP Mode")); #endif - WiFi.mode(WIFI_AP); - uint8_t macAddr[6]; - WiFi.softAPmacAddress(macAddr); - char ssid[15]; - sprintf(ssid, "ESP-RFID-%02x%02x%02x", macAddr[3], macAddr[4], macAddr[5]); - if (WiFi.softAP(ssid)) - { - ledWifiOn(); - } + WiFi.mode(WIFI_AP); + uint8_t macAddr[6]; + WiFi.softAPmacAddress(macAddr); + char ssid[15]; + sprintf(ssid, "ESP-RFID-%02x%02x%02x", macAddr[3], macAddr[4], macAddr[5]); + if (WiFi.softAP(ssid)) { + ledWifiOn(); + } } // Try to connect Wi-Fi bool ICACHE_FLASH_ATTR connectSTA(const char *ssid, const char *password, byte bssid[6]) { - bool useBSSID = false; - WiFi.mode(WIFI_STA); - WiFi.persistent(false); - - if (!config.dhcpEnabled) - { - WiFi.config(config.ipAddress, config.gatewayIp, config.subnetIp, config.dnsIp); - } + bool useBSSID = false; + + WiFi.mode(WIFI_STA); + WiFi.persistent(false); + + if (!config.dhcpEnabled) { + WiFi.config(config.ipAddress, config.gatewayIp, config.subnetIp, config.dnsIp); + } #ifdef DEBUG - Serial.print(F("[ INFO ] Trying to connect WiFi: ")); - Serial.println(ssid); - Serial.print(F("[ INFO ] WiFi BSSID: ")); + Serial.print(F("[ INFO ] Trying to connect WiFi: ")); + Serial.println(ssid); + Serial.print(F("[ INFO ] WiFi BSSID: ")); #endif - for (int i = 0; i < 6; i++) - { + for (int i = 0; i < 6; i++) { #ifdef DEBUG - Serial.print(bssid[i]); - if (i < 5) - Serial.print(F(":")); - else - Serial.println(); + Serial.print(bssid[i]); + if (i < 5) { + Serial.print(F(":")); + } else { + Serial.println(); + } #endif - if (bssid[i] != 0) - useBSSID = true; - } - if (useBSSID) - { + if (bssid[i] != 0) { + useBSSID = true; + } + } + if (useBSSID) { #ifdef DEBUG - Serial.println(F("[ INFO ] BSSID locked")); + Serial.println(F("[ INFO ] BSSID locked")); #endif - WiFi.begin(ssid, password, 0, bssid); - } - else - { + WiFi.begin(ssid, password, 0, bssid); + } else { #ifdef DEBUG - Serial.println(F("[ INFO ] any BSSID")); + Serial.println(F("[ INFO ] any BSSID")); #endif - WiFi.begin(ssid, password); - } - unsigned long now = millis(); - uint8_t timeout = 15; // define when to time out in seconds - do - { - ledWifiStatus(); - delay(500); + WiFi.begin(ssid, password); + } + unsigned long now = millis(); + uint8_t timeout = 15; // define when to time out in seconds + do{ + ledWifiStatus(); + delay(500); #ifdef DEBUG - if (!WiFi.isConnected()) - Serial.print(F(".")); + if (!WiFi.isConnected()) { + Serial.print(F(".")); + } #endif - if (WiFi.isConnected()) - break; - } while (millis() - now < timeout * 1000); - - // We now out of the while loop, either time is out or we connected. check what happened - if (WiFi.isConnected()) - { - String data = ssid; - data += " " + WiFi.localIP().toString(); - writeEvent("INFO", "wifi", "WiFi is connected", data); - Serial.println("[ INFO ] Trying to setup NTP Server"); - NTP.Ntp(config.ntpServer, config.timeZone, config.ntpInterval * 60); - connectToMqtt(); - return true; - } - else - { + if (WiFi.isConnected()) { + break; + } + } while (millis() - now < timeout * 1000); + + // We now out of the while loop, either time is out or we connected. check what happened + if (WiFi.isConnected()) { + String data = ssid; + data += " " + WiFi.localIP().toString(); + writeEvent("INFO", "wifi", "WiFi is connected", data); + Serial.println("[ INFO ] Trying to setup NTP Server"); + NTP.Ntp(config.ntpServer, config.timeZone, config.ntpInterval * 60); + connectToMqtt(); + return true; + } else { #ifdef DEBUG - Serial.println(); - Serial.println(F("[ WARN ] Couldn't connect in time")); + Serial.println(); + Serial.println(F("[ WARN ] Couldn't connect in time")); #endif - if (!config.fallbackMode) - { - wifiReconnectTimer.once(300, setEnableWifi); - } - return false; - } + if (!config.fallbackMode) { + wifiReconnectTimer.once(300, setEnableWifi); + } + return false; + } } void ICACHE_FLASH_ATTR disableWifi() { - wiFiUptimeMillis = 0; - WiFi.disconnect(true); - WiFi.softAPdisconnect(true); + wiFiUptimeMillis = 0; + WiFi.disconnect(true); + WiFi.softAPdisconnect(true); #ifdef DEBUG - Serial.println(F("Turn wifi off.")); + Serial.println(F("Turn wifi off.")); #endif } void ICACHE_FLASH_ATTR enableWifi() { - wiFiUptimeMillis = 0; - if (config.accessPointMode) - { - startAP(config.accessPointIp, config.accessPointSubnetIp, config.networkHidden, config.ssid, config.wifiPassword); - } - else - { - bool connected = connectSTA(config.ssid, config.wifiPassword, config.bssid); - if (!connected && config.fallbackMode) - { - fallbacktoAPMode(); - } - } + wiFiUptimeMillis = 0; + if (config.accessPointMode) { + startAP(config.accessPointIp, config.accessPointSubnetIp, config.networkHidden, config.ssid, + config.wifiPassword); + } else { + bool connected = connectSTA(config.ssid, config.wifiPassword, config.bssid); + if (!connected && config.fallbackMode) { + fallbacktoAPMode(); + } + } } void setupWifi(bool configured) { - if (!configured) - { - WiFi.hostname("esp-rfid"); - fallbacktoAPMode(); - } else - { - wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect); - wifiOnStationModeGotIPHandler = WiFi.onStationModeGotIP(onWifiGotIP); - WiFi.hostname(config.deviceHostname); - enableWifi(); - } + if (!configured) { + WiFi.hostname("esp-rfid"); + fallbacktoAPMode(); + } else { + wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect); + wifiOnStationModeGotIPHandler = WiFi.onStationModeGotIP(onWifiGotIP); + WiFi.hostname(config.deviceHostname); + enableWifi(); + } } diff --git a/src/wsResponses.esp b/src/wsResponses.esp index 23b7c55a..76faf999 100644 --- a/src/wsResponses.esp +++ b/src/wsResponses.esp @@ -1,183 +1,175 @@ void ICACHE_FLASH_ATTR sendUserList(int page, AsyncWebSocketClient *client) { - DynamicJsonDocument root(4096); - root["command"] = "userlist"; - root["page"] = page; - JsonArray users = root.createNestedArray("list"); - Dir dir = SPIFFS.openDir("/P/"); - int first = (page - 1) * 15; - int last = page * 15; - int i = 0; - while (dir.next()) - { - if (i >= first && i < last) - { - JsonObject item = users.createNestedObject(); - String uid = dir.fileName(); - uid.remove(0, 3); - item["uid"] = uid; - File f = SPIFFS.open(dir.fileName(), "r"); - size_t size = f.size(); - std::unique_ptr buf(new char[size]); - f.readBytes(buf.get(), size); - DynamicJsonDocument json(512); - auto error = deserializeJson(json, buf.get()); - if (!error) - { - String username = json["user"]; - String pincode = json["pincode"]; - for (int x = 1; x <= MAX_NUM_RELAYS; x++) - { - String theKey = String(); - if (x == 1) - theKey = "acctype"; - else - theKey = "acctype" + String(x); - int AccType = json[theKey]; - item[theKey] = AccType; - } - unsigned long validuntil = json["validuntil"]; - item["username"] = username; - item["validuntil"] = validuntil; - item["pincode"] = pincode; - } - } - i++; - } - float pages = i / 15.0; - root["haspages"] = ceil(pages); - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - if (client) - { - client->text(buffer); - client->text("{\"command\":\"result\",\"resultof\":\"userlist\",\"result\": true}"); - } - else - { - ws.textAll("{\"command\":\"result\",\"resultof\":\"userlist\",\"result\": false}"); - } - } + DynamicJsonDocument root(4096); + + root["command"] = "userlist"; + root["page"] = page; + JsonArray users = root.createNestedArray("list"); + Dir dir = SPIFFS.openDir("/P/"); + int first = (page - 1) * 15; + int last = page * 15; + int i = 0; + + while (dir.next()) { + if (i >= first && i < last) { + JsonObject item = users.createNestedObject(); + String uid = dir.fileName(); + uid.remove(0, 3); + item["uid"] = uid; + File f = SPIFFS.open(dir.fileName(), "r"); + size_t size = f.size(); + std::unique_ptr < char[] > buf(new char[size]); + f.readBytes(buf.get(), size); + DynamicJsonDocument json(512); + auto error = deserializeJson(json, buf.get()); + if (!error) { + String username = json["user"]; + String pincode = json["pincode"]; + for (int x = 1; x <= MAX_NUM_RELAYS; x++) { + String theKey = String(); + if (x == 1) { + theKey = "acctype"; + } else { + theKey = "acctype" + String(x); + } + int AccType = json[theKey]; + item[theKey] = AccType; + } + unsigned long validuntil = json["validuntil"]; + item["username"] = username; + item["validuntil"] = validuntil; + item["pincode"] = pincode; + } + } + i++; + } + float pages = i / 15.0; + + root["haspages"] = ceil(pages); + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); + + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + if (client) { + client->text(buffer); + client->text("{\"command\":\"result\",\"resultof\":\"userlist\",\"result\": true}"); + } else { + ws.textAll("{\"command\":\"result\",\"resultof\":\"userlist\",\"result\": false}"); + } + } } void ICACHE_FLASH_ATTR sendStatus() { - struct ip_info info; - FSInfo fsinfo; - if (!SPIFFS.info(fsinfo)) - { + struct ip_info info; + FSInfo fsinfo; + + if (!SPIFFS.info(fsinfo)) { #ifdef DEBUG - Serial.print(F("[ WARN ] Error getting info on SPIFFS")); + Serial.print(F("[ WARN ] Error getting info on SPIFFS")); #endif - } - DynamicJsonDocument root(1024); - root["command"] = "status"; + } + DynamicJsonDocument root(1024); + root["command"] = "status"; #ifdef OFFICIALBOARD - root["board"] = "brdV2"; + root["board"] = "brdV2"; #endif - root["heap"] = ESP.getFreeHeap(); - root["chipid"] = String(ESP.getChipId(), HEX); - root["cpu"] = ESP.getCpuFreqMHz(); - root["sketchsize"] = ESP.getSketchSize(); - root["availsize"] = ESP.getFreeSketchSpace(); - root["availspiffs"] = fsinfo.totalBytes - fsinfo.usedBytes; - root["spiffssize"] = fsinfo.totalBytes; - root["uptime"] = NTP.getDeviceUptimeString(); - root["version"] = VERSION; - - if (config.accessPointMode) - { - wifi_get_ip_info(SOFTAP_IF, &info); - struct softap_config conf; - wifi_softap_get_config(&conf); - root["ssid"] = String(reinterpret_cast(conf.ssid)); - root["dns"] = printIP(WiFi.softAPIP()); - root["mac"] = WiFi.softAPmacAddress(); - } - else - { - wifi_get_ip_info(STATION_IF, &info); - struct station_config conf; - wifi_station_get_config(&conf); - root["ssid"] = String(reinterpret_cast(conf.ssid)); - root["dns"] = printIP(WiFi.dnsIP()); - root["mac"] = WiFi.macAddress(); - } - - IPAddress ipaddr = IPAddress(info.ip.addr); - IPAddress gwaddr = IPAddress(info.gw.addr); - IPAddress nmaddr = IPAddress(info.netmask.addr); - root["ip"] = printIP(ipaddr); - root["gateway"] = printIP(gwaddr); - root["netmask"] = printIP(nmaddr); - - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - } + root["heap"] = ESP.getFreeHeap(); + root["chipid"] = String(ESP.getChipId(), HEX); + root["cpu"] = ESP.getCpuFreqMHz(); + root["sketchsize"] = ESP.getSketchSize(); + root["availsize"] = ESP.getFreeSketchSpace(); + root["availspiffs"] = fsinfo.totalBytes - fsinfo.usedBytes; + root["spiffssize"] = fsinfo.totalBytes; + root["uptime"] = NTP.getDeviceUptimeString(); + root["version"] = VERSION; + + if (config.accessPointMode) { + wifi_get_ip_info(SOFTAP_IF, &info); + struct softap_config conf; + wifi_softap_get_config(&conf); + root["ssid"] = String(reinterpret_cast < char * > (conf.ssid)); + root["dns"] = printIP(WiFi.softAPIP()); + root["mac"] = WiFi.softAPmacAddress(); + } else { + wifi_get_ip_info(STATION_IF, &info); + struct station_config conf; + wifi_station_get_config(&conf); + root["ssid"] = String(reinterpret_cast < char * > (conf.ssid)); + root["dns"] = printIP(WiFi.dnsIP()); + root["mac"] = WiFi.macAddress(); + } + + IPAddress ipaddr = IPAddress(info.ip.addr); + IPAddress gwaddr = IPAddress(info.gw.addr); + IPAddress nmaddr = IPAddress(info.netmask.addr); + root["ip"] = printIP(ipaddr); + root["gateway"] = printIP(gwaddr); + root["netmask"] = printIP(nmaddr); + + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + } } void ICACHE_FLASH_ATTR printScanResult(int networksFound) { - // sort by RSSI - int n = networksFound; - int indices[n]; - int skip[n]; - for (int i = 0; i < networksFound; i++) - { - indices[i] = i; - } - for (int i = 0; i < networksFound; i++) - { - for (int j = i + 1; j < networksFound; j++) - { - if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) - { - std::swap(indices[i], indices[j]); - std::swap(skip[i], skip[j]); - } - } - } - DynamicJsonDocument root(512); - root["command"] = "ssidlist"; - JsonArray scan = root.createNestedArray("list"); - for (int i = 0; i < 5 && i < networksFound; ++i) - { - JsonObject item = scan.createNestedObject(); - item["ssid"] = WiFi.SSID(indices[i]); - item["bssid"] = WiFi.BSSIDstr(indices[i]); - item["rssi"] = WiFi.RSSI(indices[i]); - item["channel"] = WiFi.channel(indices[i]); - item["enctype"] = WiFi.encryptionType(indices[i]); - item["hidden"] = WiFi.isHidden(indices[i]) ? true : false; - } - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); // creates a buffer (len + 1) for you. - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - } - WiFi.scanDelete(); + // sort by RSSI + int n = networksFound; + int indices[n]; + int skip[n]; + + for (int i = 0; i < networksFound; i++) { + indices[i] = i; + } + for (int i = 0; i < networksFound; i++) { + for (int j = i + 1; j < networksFound; j++) { + if (WiFi.RSSI(indices[j]) > WiFi.RSSI(indices[i])) { + std::swap(indices[i], indices[j]); + std::swap(skip[i], skip[j]); + } + } + } + DynamicJsonDocument root(512); + + root["command"] = "ssidlist"; + JsonArray scan = root.createNestedArray("list"); + + for (int i = 0; i < 5 && i < networksFound; ++i) { + JsonObject item = scan.createNestedObject(); + item["ssid"] = WiFi.SSID(indices[i]); + item["bssid"] = WiFi.BSSIDstr(indices[i]); + item["rssi"] = WiFi.RSSI(indices[i]); + item["channel"] = WiFi.channel(indices[i]); + item["enctype"] = WiFi.encryptionType(indices[i]); + item["hidden"] = WiFi.isHidden(indices[i]) ? true : false; + } + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); // creates a buffer (len + 1) for you. + + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + } + WiFi.scanDelete(); } void ICACHE_FLASH_ATTR sendTime() { - DynamicJsonDocument root(512); - root["command"] = "gettime"; - root["epoch"] = now(); - root["timezone"] = config.timeZone; - size_t len = measureJson(root); - AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); - if (buffer) - { - serializeJson(root, (char *)buffer->get(), len + 1); - ws.textAll(buffer); - } -} \ No newline at end of file + DynamicJsonDocument root(512); + + root["command"] = "gettime"; + root["epoch"] = now(); + root["timezone"] = config.timeZone; + size_t len = measureJson(root); + AsyncWebSocketMessageBuffer *buffer = ws.makeBuffer(len); + + if (buffer) { + serializeJson(root, (char *)buffer->get(), len + 1); + ws.textAll(buffer); + } +} diff --git a/uncrustify.cfg b/uncrustify.cfg new file mode 100644 index 00000000..b798456b --- /dev/null +++ b/uncrustify.cfg @@ -0,0 +1,93 @@ +# +# uncrustify config file for the linux kernel, with mods for Tome's preferences. +# +# Documentation for settings https://github.com/uncrustify/uncrustify/blob/master/etc/defaults.cfg + +indent_with_tabs = 0 # 1=indent to level only, 2=indent with tabs +input_tab_size = 4 # original tab size +output_tab_size = 4 # new tab size +indent_columns = output_tab_size +indent_switch_case = 4 +code_width = 120 +indent_label = 1 # pos: absolute col, neg: relative column +indent_class = true + + +# inter-symbol newlines +nl_enum_brace = remove # "enum {" vs "enum \n {" +nl_union_brace = remove # "union {" vs "union \n {" +nl_struct_brace = remove # "struct {" vs "struct \n {" +nl_do_brace = remove # "do {" vs "do \n {" +nl_if_brace = remove # "if () {" vs "if () \n {" +nl_for_brace = remove # "for () {" vs "for () \n {" +nl_else_brace = remove # "else {" vs "else \n {" +nl_while_brace = remove # "while () {" vs "while () \n {" +nl_switch_brace = remove # "switch () {" vs "switch () \n {" +nl_brace_while = remove # "} while" vs "} \n while" - cuddle while +nl_brace_else = remove # "} else" vs "} \n else" - cuddle else +sp_brace_else = force +sp_else_brace = force +nl_func_var_def_blk = 1 +nl_fcall_brace = remove # "list_for_each() {" vs "list_for_each()\n{" +nl_fdef_brace = add # "int foo() {" vs "int foo()\n{" +nl_after_label_colon= true # "fail:\nfree(foo);" vs "fail: free(foo);" + + +# Source code modifications +mod_paren_on_return = remove # "return 1;" vs "return (1);" +mod_full_brace_if = force # "if (a) a--;" vs "if (a) { a--; }" +mod_full_brace_if_chain = false +mod_full_brace_for = force # "for () a--;" vs "for () { a--; }" +mod_full_brace_do = force # "do a--; while ();" vs "do { a--; } while ();" +mod_full_brace_while = force # "while (a) a--;" vs "while (a) { a--; }" +mod_full_brace_nl = 3 # don't remove if more than 3 newlines + + +# inter-character spacing options +sp_return_paren = force # "return (1);" vs "return(1);" +sp_sizeof_paren = remove # "sizeof (int)" vs "sizeof(int)" +sp_before_sparen = force # "if (" vs "if(" +sp_after_sparen = force # "if () {" vs "if (){" +sp_after_cast = remove # "(int) a" vs "(int)a" +sp_inside_braces = force # "{ 1 }" vs "{1}" +sp_inside_braces_struct = force # "{ 1 }" vs "{1}" +sp_inside_braces_enum = force # "{ 1 }" vs "{1}" +sp_arith = force # spaces around + - etc +sp_bool = force # spaces around && etc +sp_compare = force +sp_assign = force +sp_after_comma = force +sp_func_def_paren = remove # "int foo (){" vs "int foo(){" +sp_func_call_paren = remove # "foo (" vs "foo(" +sp_func_proto_paren = remove # "int foo ();" vs "int foo();" +sp_inside_paren = remove +sp_inside_square = remove +sp_inside_paren_cast = remove +sp_inside_fparen = remove # function paren +sp_inside_sparen = remove # control statemnets besides for +sp_paren_paren = remove # inside (( )) +sp_before_ptr_star = force # uint8_t * not uint8_t* +sp_after_ptr_star = remove # uint8_t * not uint8_t* +sp_between_ptr_star = remove # remove space between multiple ** +eat_blanks_after_open_brace = true # remove empty lines after { +eat_blanks_before_close_brace = true +pp_indent = remove # preprocessor indenting + + +# Aligning stuff +align_with_tabs = false # use tabs to align +align_on_tabstop = true # align on tabstops +align_keep_tabs = false +align_enum_equ_span = 4 # '=' in enum definition +align_nl_cont = true // align multiline macrobackslashes +align_struct_init_span = 3 # align stuff in a structure init '= { }' +align_right_cmt_span = 3 +cmt_star_cont = true +indent_brace = 0 +align_func_params = true +align_var_struct_span = 6 + +# Newline +nl_start_of_file = remove +nl_end_of_file = force +nl_end_of_file_min = 1