basic serial reader

This commit is contained in:
Matthew Frost 2023-10-30 16:03:50 +01:00
commit c55bd0f87c
16 changed files with 595 additions and 0 deletions

8
.gitignore vendored Normal file
View file

@ -0,0 +1,8 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
include/secrets.h
.DS_Store
upload_params.ini

10
.vscode/extensions.json vendored Normal file
View file

@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

13
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,13 @@
{
"files.associations": {
"array": "cpp",
"deque": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"string_view": "cpp",
"initializer_list": "cpp",
"regex": "cpp"
}
}

15
README Normal file
View file

@ -0,0 +1,15 @@
This project is a card reader system for Techinc that uses a WIEGAND based reader and allows platform.io based user flags to allow change of certain features.
This project is designed to work over serial with an external computer that decides who has access.
# Currently supported flags:
-DBOARD1 : Used to set Pins for BOARD1 config
-DBOARD2 : Used to set Pins for BOARD2 config
-DRELAY1 : Enable the First Relay
-DRELAY2 : Not implemented yet
# Important Notes:
* None

45
include/ACL.h Normal file
View file

@ -0,0 +1,45 @@
#ifndef ACL_H
#define ACL_H
#include <Arduino.h>
#include <initializer_list>
#include <EEPROM.h>
#include <Preferences.h>
#ifdef WEB_SERVER
#ifdef WEB_SERIAL_DEBUG
#include <WebSerial.h>
#endif
#endif
struct User {
String cardId;
String desc;
};
class ACL {
public:
ACL();
ACL(std::initializer_list<User> userList);
~ACL();
void addUser(const String& cardId, const String& desc);
void updateUser(const String& cardId, const String& newCardId, const String& newdesc);
bool removeUser(const String& cardId);
bool validateAccess(const String& cardId);
int getACLSize() const;
// Additional EEPROM functions
void saveToEEPROM();
void loadFromEEPROM();
const User* getACL() const { return acl; } // Getter for acl
private:
User* acl;
int aclSize;
};
#endif

39
include/README Normal file
View file

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

11
include/buzzer_ctl.h Normal file
View file

@ -0,0 +1,11 @@
#ifndef BUZZER_CTL_H
#define BUZZER_CTL_H
#include "hardware.h"
void short_beep();
void granted_beep();
void denied_beep();
void clear_states();
#endif

38
include/hardware.h Normal file
View file

@ -0,0 +1,38 @@
#ifndef HARDWARE_H
#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
#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
#define RELAY1_PIN 13
#define RELAY_DELAY 3000
#endif
void controlRelay();
void unlockDoor(bool silent);
void lockDoor();
void toggleDoor();
String stateDoor();
#endif

14
include/main.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef MAIN_H
#define MAIN_H
#include "hardware.h"
#include <Arduino.h>
#include "settings.h"
Settings settings;
#ifdef BUZZER
#include "buzzer_ctl.h"
#endif
#endif

20
include/settings.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef SETTINGS_H
#define SETTINGS_H
#include <Preferences.h>
class Settings {
private:
bool disableDoor;
public:
Settings();
void loadFromEEPROM();
void saveToEEPROM();
void setDisableDoor(bool value);
bool DoorDisabled();
};
#endif // SETTINGS_H

46
lib/README Normal file
View file

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

47
platformio.ini Normal file
View file

@ -0,0 +1,47 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
extra_configs = upload_params.ini
[env:esp32-evb]
platform = espressif32
board = esp32-evb
framework = arduino
build_flags = -DBOARD1 -DRELAY1 -DWIFI -DWEB_SERVER -DNET_FAIL_SAFE -DWEB_OTA_UPDATE -DLOCAL_ACL -DLOCAL_ACL_API -DLATCH_DOOR
lib_deps =
ottowinter/ESPAsyncWebServer-esphome@^3.0.0
ayushsharma82/WebSerial@^1.4.0
ayushsharma82/AsyncElegantOTA@^2.2.7
bblanchon/ArduinoJson@^6.21.2
[env:mcu-esp32s]
platform = espressif32
framework = arduino
board = nodemcu-32s
build_flags = -DBOARD2 -DBUZZER -DRELAY1 -DWIFI -DWEB_SERVER -DNET_FAIL_SAFE -DWEB_OTA_UPDATE -DLOCAL_ACL -DLOCAL_ACL_API -DLATCH_DOOR
lib_deps =
ottowinter/ESPAsyncWebServer-esphome@^3.0.0
ayushsharma82/WebSerial@^1.4.0
ayushsharma82/AsyncElegantOTA@^2.2.7
bblanchon/ArduinoJson@^6.21.2
[env:mcu-esp32s-ota]
platform = espressif32
framework = arduino
board = nodemcu-32s
build_flags = -DBOARD2 -DBUZZER -DRELAY1 -DWIFI -DWEB_SERVER -DNET_FAIL_SAFE -DWEB_OTA_UPDATE -DLOCAL_ACL -DLOCAL_ACL_API -DLATCH_DOOR
lib_deps =
ottowinter/ESPAsyncWebServer-esphome@^3.0.0
ayushsharma82/WebSerial@^1.4.0
ayushsharma82/AsyncElegantOTA@^2.2.7
bblanchon/ArduinoJson@^6.21.2
extra_scripts = platformio_upload.py

40
src/buzzer_ctl.cpp Normal file
View file

@ -0,0 +1,40 @@
#include "buzzer_ctl.h"
void short_beep()
{
#ifdef ALARM_PIN
digitalWrite(ALARM_PIN, LOW);
delay(50);
digitalWrite(ALARM_PIN, HIGH);
#endif
}
void granted_beep()
{
#ifdef ALARM_PIN
digitalWrite(ALARM_PIN, LOW);
delay(50);
digitalWrite(ALARM_PIN, HIGH);
delay(50);
digitalWrite(ALARM_PIN, LOW);
delay(50);
digitalWrite(ALARM_PIN, HIGH);
delay(50);
digitalWrite(ALARM_PIN, LOW);
delay(50);
digitalWrite(ALARM_PIN, HIGH);
#endif
}
void denied_beep(void)
{
#ifdef ALARM_PIN
for (int i=0; i<100; i++)
{
delay(4);
digitalWrite(ALARM_PIN, LOW);
delay(4);
digitalWrite(ALARM_PIN, HIGH);
}
#endif
}

86
src/hardware.cpp Normal file
View file

@ -0,0 +1,86 @@
#include "hardware.h"
#include "buzzer_ctl.h"
void controlRelay(int relayPin, bool on) {
digitalWrite(relayPin, on ? HIGH : LOW); // Turn the relay on or off
}
void unlockDoor(bool silent) {
#ifdef BUZZER
if (!silent) {
granted_beep();
}
#endif
#ifdef RELAY1
#ifdef RELAY1_REVERSED
controlRelay(RELAY1_PIN,true);
#else
controlRelay(RELAY1_PIN,false);
#endif
#endif
#ifdef SERIAL_DEBUG
Serial.println("door unlocked");
#endif
#ifdef LEDCTL_PIN
digitalWrite(LEDCTL_PIN,LOW);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("door unlocked");
#endif
}
void lockDoor() {
#ifdef RELAY1
#ifdef RELAY1_REVERSED
controlRelay(RELAY1_PIN,false);
#else
controlRelay(RELAY1_PIN,true);
#endif
#endif
#ifdef SERIAL_DEBUG
Serial.println("door locked");
#endif
#ifdef LEDCTL_PIN
digitalWrite(LEDCTL_PIN,HIGH);
#endif
#ifdef WEB_SERIAL_DEBUG
WebSerial.println("door locked");
#endif
}
void toggleDoor() {
#ifdef RELAY1
int relayState = digitalRead(RELAY1_PIN);
// Toggle the relay based on the current state
#ifdef RELAY1_REVERSED
if (relayState == HIGH) {
lockDoor();
} else {
unlockDoor(false);
}
#else
if (relayState == LOW) {
lockDoor();
} else {
unlockDoor(false);
}
#endif
#endif
}
String stateDoor() {
#ifdef RELAY1
int relayState = digitalRead(RELAY1_PIN);
// Toggle the relay based on the current state
if (relayState == LOW) {
return "Unlocked";
} else {
return "Locked";
}
#endif
}

133
src/main.cpp Normal file
View file

@ -0,0 +1,133 @@
#include "main.h"
volatile uint64_t cardData = 0;
volatile bool newDataAvailable = false;
unsigned long lastDataTime = 0;
const unsigned long displayDelay = 1000; // Delay in milliseconds after which the data is displayed
unsigned int bitCount = 0; // Variable to keep track of the bit count
unsigned int maxReaderWaitTime = 9000; // Variable to timeout reader after too long of no data.
void handleInterrupt(int bitValue) {
static unsigned long lastInterruptTime = 0;
unsigned long interruptTime = micros();
if (interruptTime - lastInterruptTime > 200) {
cardData <<= 1;
cardData |= bitValue;
newDataAvailable = true;
bitCount++; // Increment the bit count
}
lastInterruptTime = interruptTime;
lastDataTime = millis(); // Update the time of last received data
}
void handleData0Interrupt() {
handleInterrupt(0);
}
void handleData1Interrupt() {
handleInterrupt(1);
}
void setup() {
Serial.begin(9600);
pinMode(DATA0_PIN, INPUT_PULLUP);
pinMode(DATA1_PIN, INPUT_PULLUP);
#ifdef LEDCTL_PIN
pinMode(LEDCTL_PIN, OUTPUT);
#endif
#ifdef RELAY1
pinMode(RELAY1_PIN, OUTPUT);
#endif
attachInterrupt(digitalPinToInterrupt(DATA0_PIN), handleData0Interrupt, FALLING);
attachInterrupt(digitalPinToInterrupt(DATA1_PIN), handleData1Interrupt, FALLING);
#ifdef RELAY1
#ifdef SERIAL_DEBUG
Serial.println("Enabling Relay: Locking Door");
#endif
lockDoor();
#endif
#ifdef RELAY2
pinMode(RELAY2_PIN, OUTPUT);
#endif
#ifdef BUZZER
pinMode(ALARM_PIN, OUTPUT);
digitalWrite(ALARM_PIN, HIGH); // Do not set to low or it will constantly beep.
#endif
}
void loop() {
#ifdef LOCAL_ACL
#ifdef SERIAL_ACL
checkSerialCommand();
#endif
#endif
if (newDataAvailable) {
newDataAvailable = false;
lastDataTime = millis(); // Reset the time of last received data
}
if (millis() - lastDataTime >= displayDelay && cardData != 0) {
uint64_t facilityID = (cardData >> 17) & 0xFFFF;
uint64_t cardID = (cardData >> 1) & 0xFFFF;
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);
String fullCardID = String(facilityID)+":"+String(cardID);
Serial.print("Full Card (Tinance2): ");
Serial.println(fullCardID);
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; // Reset the card data
lastDataTime = millis(); // Reset the time of last received data
bitCount = 0; // Reset the bit count
}
}

30
src/settings.cpp Normal file
View file

@ -0,0 +1,30 @@
#include "settings.h"
Preferences settings_preferences;
Settings::Settings() {
// Set default value for disableDoor
disableDoor = false;
}
void Settings::loadFromEEPROM() {
settings_preferences.begin("settings");
disableDoor = settings_preferences.getBool("disableDoor", false);
settings_preferences.end();
}
void Settings::saveToEEPROM() {
settings_preferences.begin("settings");
settings_preferences.putBool("disableDoor", disableDoor);
settings_preferences.end();
}
void Settings::setDisableDoor(bool value) {
disableDoor = value;
saveToEEPROM(); // Save the setting immediately to Preferences
}
bool Settings::DoorDisabled() {
return disableDoor;
}