TTL Reader Support

This commit is contained in:
Matthew Frost 2024-01-30 16:03:40 +01:00
parent 33db93deed
commit 74cc87fe65
8 changed files with 255 additions and 143 deletions

View file

@ -49,6 +49,7 @@
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
"typeinfo": "cpp",
"iostream": "cpp"
}
}

1
README
View file

@ -10,7 +10,6 @@ This project is a card reader system for Techinc that uses a WIEGAND based reade
-DWIFI : Enable WIFI and use secrets.h to manage.
-DWEB_SERVER : Enable Web Server
-DSERIAL_DEBUG : Enable Serial Console output and debug.
-DWEB_SERIAL_DEBUG : Enable Web Serial console to monitor for issues (does not support auth, needs -DWEB_SERVER)
-DNET_FAIL_SAFE : If WIFI disconnects release door / relay.
-DWEB_OTA_UPDATE : Present Web Interface on /update for managing firmware over the air (needs -DWEB_SERVER)
-DLOCAL_ACL : Enable local ACL list

View file

@ -2,32 +2,39 @@
#define HARDWARE_H
#include <Arduino.h>
#ifdef WEB_SERVER
#ifdef WEB_SERIAL_DEBUG
#include <WebSerial.h>
#endif
#endif
#ifdef BOARD1
#define TAMPER_PIN 26
#define LEDCTL_PIN 32
#define DATA0_PIN 34
#define DATA1_PIN 36
#ifdef WG_READER
#define TAMPER_PIN 26
#define LEDCTL_PIN 32
#define DATA0_PIN 34
#define DATA1_PIN 36
#endif
#define RELAY1_PIN 32
#define RELAY2_PIN 33
#define RELAY_DELAY 3000
#endif
#ifdef BOARD2
#define TAMPER_PIN 0
#define ALARM_PIN 33
#define WIEGAND_PIN 32
#define LEDCTL_PIN 25
#define DATA0_PIN 26
#define DATA1_PIN 27
#ifdef WG_READER
#define TAMPER_PIN 0
#define ALARM_PIN 33
#define LEDCTL_PIN 25
#define DATA0_PIN 26
#define DATA1_PIN 27
#define BIT_MODE_WG34_PIN 32
#endif
#ifdef TTL_READER
#define TXD 17
#define RXD 16
#endif
#define RELAY1_PIN 13
#define RELAY_DELAY 3000
#define BIT_MODE_WG34_PIN 32
#endif
void controlRelay();

View file

@ -18,14 +18,17 @@
};
#endif
#ifdef TTL_READER
#include <iostream>
#include <string>
#include <sstream>
#endif
#ifdef WEB_SERVER
#include <AsyncTCP.h>
#include "ESPAsyncWebServer.h"
#include "SPIFFS.h"
#include <AsyncJson.h>
#ifdef WEB_SERIAL_DEBUG
#include <WebSerial.h>
#endif
#ifdef WEB_OTA_UPDATE
#include <AsyncElegantOTA.h>
#endif

View file

@ -79,26 +79,17 @@ bool ACL::validateAccess(const String& cardId) {
#ifdef SERIAL_DEBUG
Serial.println("Checking ACL match for Card: " + String(cardId) + " Against Card: " + String(acl[i].cardId) + " desc: " + String(acl[i].desc));
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("Checking ACL match for Card: " + String(cardId) + " Against Card: " + String(acl[i].cardId) + " desc: " + String(acl[i].desc));
#endif
#endif
if (acl[i].cardId.equals(cardId)) {
#ifdef SERIAL_DEBUG
Serial.println("Card matched and authenticated.");
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("Card matched and authenticated.");
#endif
return true;
}
}
#ifdef SERIAL_DEBUG
Serial.println("Card did not match.");
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("Card did not match.");
#endif
return false;
}

View file

@ -25,9 +25,6 @@ void unlockDoor(bool silent) {
digitalWrite(LEDCTL_PIN,LOW);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("door unlocked");
#endif
}
void lockDoor(bool silent) {
@ -50,10 +47,6 @@ void lockDoor(bool silent) {
#ifdef LEDCTL_PIN
digitalWrite(LEDCTL_PIN,HIGH);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("door locked");
#endif
}
@ -87,5 +80,6 @@ String stateDoor() {
return "Locked";
}
#endif
return ""; // Add a return statement to handle the case when RELAY1 is not defined
}

View file

@ -368,6 +368,13 @@ void setup() {
Serial.begin(9600);
#endif
#ifdef TTL_READER
Serial2.begin(9600, SERIAL_8N1, RXD, TXD);
#endif
#ifdef WEB_SERVER
WiFi.disconnect(true);
#endif
@ -396,14 +403,15 @@ void setup() {
AsyncElegantOTA.begin(&server, http_username, http_password);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.begin(&server);
#endif
#endif
#ifdef DATA0_PIN
pinMode(DATA0_PIN, INPUT_PULLUP);
#endif
pinMode(DATA0_PIN, INPUT_PULLUP);
pinMode(DATA1_PIN, INPUT_PULLUP);
#ifdef DATA1_PIN
pinMode(DATA1_PIN, INPUT_PULLUP);
#endif
#ifdef BIT_MODE_WG34
pinMode(BIT_MODE_WG34_PIN, OUTPUT);
@ -415,11 +423,15 @@ void setup() {
#endif
#ifdef RELAY1
pinMode(RELAY1_PIN, OUTPUT);
#ifdef RELAY1_PIN
pinMode(RELAY1_PIN, OUTPUT);
#endif
#endif
attachInterrupt(digitalPinToInterrupt(DATA0_PIN), handleData0Interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(DATA1_PIN), handleData1Interrupt, FALLING);
#ifdef WG_READER
attachInterrupt(digitalPinToInterrupt(DATA0_PIN), handleData0Interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(DATA1_PIN), handleData1Interrupt, FALLING);
#endif
#ifdef WIFI
WiFi.onEvent(WiFiStationConnected, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED);
@ -440,8 +452,10 @@ void setup() {
#endif
#ifdef BUZZER
pinMode(ALARM_PIN, OUTPUT);
digitalWrite(ALARM_PIN, HIGH); // Do not set to low or it will constantly beep.
#ifdef ALARM_PIN
pinMode(ALARM_PIN, OUTPUT);
digitalWrite(ALARM_PIN, HIGH); // Do not set to low or it will constantly beep.
#endif
#endif
#ifdef WEB_SERVER
@ -652,30 +666,120 @@ void setup() {
* It then calls the appropriate functions based on the defined macros to handle the card data.
* If no valid card data is received within the specified time, it resets the card data and bit count.
*
* @note This function assumes the availability of certain macros like TINANCE2_BACKEND, LOCAL_ACL, SERIAL_ACL, SERIAL_DEBUG, and WEB_SERIAL_DEBUG.
* @note This function assumes the availability of certain macros like TINANCE2_BACKEND, LOCAL_ACL, SERIAL_ACL and SERIAL_DEBUG.
*
* @note This function assumes the availability of certain variables like newDataAvailable, lastDataTime, displayDelay, cardData, bitCount, and maxReaderWaitTime.
*
* @note This function assumes the availability of certain functions like updateDoorStatus, checkSerialCommand, tinance2authrequest, and localAcl.
*/
void loop() {
#ifdef TINANCE2_BACKEND
updateDoorStatus();
#endif
#ifdef LOCAL_ACL
#ifdef SERIAL_ACL
checkSerialCommand();
#endif
#endif
#ifdef TTL_READER
String parseStringSTXandETX(const String& incoming) {
int stxPos = incoming.indexOf('\x02');
int etxPos = incoming.indexOf('\x03');
if (newDataAvailable) {
newDataAvailable = false;
lastDataTime = millis(); // Reset the time of last received data
if (stxPos == -1 || etxPos == -1) {
return "";
}
String parsedString = incoming.substring(stxPos + 1, etxPos);
// Remove whitespace and hidden characters
parsedString.replace(" ", "");
parsedString.replace("\t", "");
parsedString.replace("\n", "");
parsedString.replace("\r", "");
return parsedString;
}
uint64_t hexToBinary(const String& hexString) {
String binaryString;
for (char c : hexString) {
switch (c) {
case '0':
binaryString += "0000";
break;
case '1':
binaryString += "0001";
break;
case '2':
binaryString += "0010";
break;
case '3':
binaryString += "0011";
break;
case '4':
binaryString += "0100";
break;
case '5':
binaryString += "0101";
break;
case '6':
binaryString += "0110";
break;
case '7':
binaryString += "0111";
break;
case '8':
binaryString += "1000";
break;
case '9':
binaryString += "1001";
break;
case 'A':
case 'a':
binaryString += "1010";
break;
case 'B':
case 'b':
binaryString += "1011";
break;
case 'C':
case 'c':
binaryString += "1100";
break;
case 'D':
case 'd':
binaryString += "1101";
break;
case 'E':
case 'e':
binaryString += "1110";
break;
case 'F':
case 'f':
binaryString += "1111";
break;
default:
// Invalid hexadecimal digit
#ifdef SERIAL_DEBUG
Serial.print("Invalid Hex Char: ");
Serial.println(c);
Serial.print("Hex String: ");
Serial.println(hexString);
Serial.print("Hex Char: ");
Serial.println(c);
Serial.print("Binary String: ");
Serial.println(binaryString);
#endif
return 0ULL;
}
}
uint64_t binaryValue = 0ULL;
for (char bit : binaryString) {
binaryValue <<= 1;
binaryValue |= (bit - '0');
}
if (millis() - lastDataTime >= displayDelay && cardData != 0 && (bitCount == 26 || bitCount == 34)) {
#ifdef SERIAL_DEBUG
Serial.print("Binary Value: ");
Serial.println(binaryValue);
#endif
return binaryValue;
}
#endif
void authenticationFlow(uint64_t cardData) {
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
uint64_t cardID = (cardData >> 1) & 0xFFFF;
@ -695,22 +799,7 @@ void loop() {
Serial.print("Total Bits Received: ");
Serial.println(bitCount);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.print("Facility ID (Decimal): ");
WebSerial.println(facilityID);
WebSerial.print("Facility ID (Binary): ");
WebSerial.println(facilityID, BIN);
WebSerial.print("Card ID (Decimal): ");
WebSerial.println(cardID);
WebSerial.print("Card ID (Binary): ");
WebSerial.println(cardID, BIN);
WebSerial.print("Card Data (Binary): ");
WebSerial.println(cardData, BIN);
WebSerial.print("Total Bits Received: ");
WebSerial.println(bitCount);
#endif
String fullCardID = String(facilityID)+":"+String(cardID);
#ifdef SERIAL_DEBUG
@ -718,10 +807,6 @@ void loop() {
Serial.println(fullCardID);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.print("Full Card (Tinance2): ");
WebSerial.println(fullCardID);
#endif
#ifdef TINANCE2_BACKEND
if (settings.getDoorDisabled()) {
@ -739,52 +824,97 @@ void loop() {
#endif
#endif
cardData = 0; // Reset the card data
lastDataTime = millis(); // Reset the time of last received data
bitCount = 0; // Reset the bit count
}
}
else if (millis() - lastDataTime >= maxReaderWaitTime && cardData != 0) {
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
uint64_t cardID = (cardData >> 1) & 0xFFFF;
#ifdef SERIAL_DEBUG
Serial.println("--- Reader Input Error ---");
Serial.print("Facility ID (Decimal): ");
Serial.println(facilityID);
Serial.print("Facility ID (Binary): ");
Serial.println(facilityID, BIN);
Serial.print("Card ID (Decimal): ");
Serial.println(cardID);
Serial.print("Card ID (Binary): ");
Serial.println(cardID, BIN);
Serial.print("Card Data (Binary): ");
Serial.println(cardData, BIN);
Serial.print("Total Bits Received: ");
Serial.println(bitCount);
void loop() {
#ifdef TINANCE2_BACKEND
updateDoorStatus();
#endif
#ifdef LOCAL_ACL
#ifdef SERIAL_ACL
checkSerialCommand();
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.print("Facility ID (Decimal): ");
WebSerial.println(facilityID);
WebSerial.print("Facility ID (Binary): ");
WebSerial.println(facilityID, BIN);
#endif
WebSerial.print("Card ID (Decimal): ");
WebSerial.println(cardID);
WebSerial.print("Card ID (Binary): ");
WebSerial.println(cardID, BIN);
WebSerial.print("Card Data (Binary): ");
WebSerial.println(cardData, BIN);
WebSerial.print("Total Bits Received: ");
WebSerial.println(bitCount);
#endif
cardData = 0; // Reset the card data
lastDataTime = millis(); // Reset the time of last received data
bitCount = 0; // Reset the bit count
#ifdef TTL_READER
if (Serial2.available() > 0) {
String incoming = Serial2.readString();
String parsed = parseStringSTXandETX(incoming);
}
#ifdef SERIAL_DEBUG
Serial.print("Message Received: ");
Serial.println(incoming);
#endif
if (parsed != "") {
uint64_t cardData = hexToBinary(parsed);
#ifdef SERIAL_DEBUG
Serial.println("Valid TTL Reader Data");
Serial.print("I received: ");
Serial.println(incoming);
Serial.print(parsed);
Serial.println("Hex Value:");
Serial.print(cardData);
#endif
authenticationFlow(cardData);
}
else {
#ifdef SERIAL_DEBUG
Serial.println("Invalid TTL Reader Data");
Serial.print("I received: ");
Serial.println(incoming);
#endif
}
}
#endif
#ifdef WG_READER
if (newDataAvailable) {
newDataAvailable = false;
lastDataTime = millis(); // Reset the time of last received data
}
if (millis() - lastDataTime >= displayDelay && cardData != 0 && (bitCount == 26 || bitCount == 34)) {
authenticationFlow(cardData);
cardData = 0; // Reset the card data
lastDataTime = millis(); // Reset the time of last received data
bitCount = 0; // Reset the bit count
}
else if (millis() - lastDataTime >= maxReaderWaitTime && cardData != 0) {
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
uint64_t cardID = (cardData >> 1) & 0xFFFF;
#ifdef SERIAL_DEBUG
Serial.println("--- Reader Input Error ---");
Serial.print("Facility ID (Decimal): ");
Serial.println(facilityID);
Serial.print("Facility ID (Binary): ");
Serial.println(facilityID, BIN);
Serial.print("Card ID (Decimal): ");
Serial.println(cardID);
Serial.print("Card ID (Binary): ");
Serial.println(cardID, BIN);
Serial.print("Card Data (Binary): ");
Serial.println(cardData, BIN);
Serial.print("Total Bits Received: ");
Serial.println(bitCount);
#endif
cardData = 0; // Reset the card data
lastDataTime = millis(); // Reset the time of last received data
bitCount = 0; // Reset the bit count
}
#endif
}

View file

@ -1,35 +1,21 @@
#include "settings.h"
Preferences settings_preferences;
Settings::Settings() {
// Set default value for disableDoor
disableDoor = false;
#ifdef LATCH_DOOR
doorMode = "LATCH"; // Set default value for doorMode
#endif
#ifdef TOGGLE_DOOR
doorMode = "TOGGLE"; // Set default value for doorMode
#endif
Settings::Settings() : disableDoor(false), doorMode("LATCH") {
}
void Settings::loadFromEEPROM() {
settings_preferences.begin("settings");
disableDoor = settings_preferences.getBool("disableDoor", false);
#ifdef LATCH_DOOR
doorMode = settings_preferences.getString("doorMode", "LATCH"); // Load doorMode from EEPROM
#endif
#ifdef TOGGLE_DOOR
doorMode = settings_preferences.getString("doorMode", "TOGGLE"); // Load doorMode from EEPROM
#endif
doorMode = settings_preferences.getString("doorMode", "LATCH");
settings_preferences.end();
}
void Settings::saveToEEPROM() {
settings_preferences.begin("settings");
settings_preferences.putBool("disableDoor", disableDoor);
settings_preferences.putString("doorMode", doorMode); // Save doorMode to EEPROM
settings_preferences.putString("doorMode", doorMode);
settings_preferences.end();
}
@ -40,7 +26,7 @@ void Settings::setDisableDoor(bool value) {
Serial.print("Settings::setDisableDoor: ");
Serial.println(disableDoor);
#endif
saveToEEPROM(); // Save the setting immediately to Preferences
saveToEEPROM();
}
}
@ -54,12 +40,13 @@ void Settings::setDoorMode(const String mode) {
doorMode = mode;
#ifdef SERIAL_DEBUG
Serial.print("Settings::setDoorMode: ");
Serial.println(doorMode.c_str());
Serial.println(doorMode);
#endif
saveToEEPROM(); // Save the setting immediately to Preferences
saveToEEPROM();
}
}
}
String Settings::getDoorMode() {
return doorMode;
}