Split firmware into separate files
This commit is contained in:
parent
0ab2ac086f
commit
79c76a57aa
230
firmware/comm.cpp
Normal file
230
firmware/comm.cpp
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
//TODO: abstract http functions
|
||||||
|
|
||||||
|
void postState()
|
||||||
|
{
|
||||||
|
// Don't log more than one error at a time
|
||||||
|
static bool logErrors = true;
|
||||||
|
|
||||||
|
HTTPClient lockHTTP;
|
||||||
|
|
||||||
|
//lockHTTP.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
||||||
|
lockHTTP.begin(SOCKET_URL + wifiMACAddr);
|
||||||
|
lockHTTP.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Lock state HTTP begin.");
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.print("[INFO] HTTP POST: ");
|
||||||
|
String postData = serializeLockJson(lockState);
|
||||||
|
if (SERIAL_LOGGING) Serial.println(postData);
|
||||||
|
int16_t lockHTTPCode = lockHTTP.POST(postData);
|
||||||
|
String lockHTTPCodeStr = String(lockHTTPCode);
|
||||||
|
|
||||||
|
if (lockHTTPCode > 0) {
|
||||||
|
if (SERIAL_LOGGING) Serial.printf("[INFO] POST success, code: %d\n", lockHTTPCode);
|
||||||
|
|
||||||
|
if (lockHTTPCode == HTTP_CODE_OK) {
|
||||||
|
logErrors = true;
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
||||||
|
String lockPayload = lockHTTP.getString();
|
||||||
|
if (SERIAL_LOGGING) Serial.println(lockPayload);
|
||||||
|
String action = deserializeLockJson(lockPayload);
|
||||||
|
|
||||||
|
if (action == "arm" && lockState == LOCK_OFF && LEDState == LED_OFF) {
|
||||||
|
logEvent(LOG_COMM_LOCK_ARM);
|
||||||
|
lockState = LOCK_PREARM;
|
||||||
|
} else if (action == "disarm" && lockState != LOCK_ON) {
|
||||||
|
logEvent(LOG_COMM_LOCK_DISARM);
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Unarming interlock.");
|
||||||
|
logEvent(LOG_LOCK_DISARM);
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] action: " + action);
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Resource not found.");
|
||||||
|
if (logErrors) logEvent(LOG_COMM_LOCK_FAIL, lockHTTPCodeStr.c_str(), lockHTTPCodeStr.length());
|
||||||
|
logErrors = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", lockHTTP.errorToString(lockHTTPCode).c_str());
|
||||||
|
if (logErrors) logEvent(LOG_COMM_LOCK_FAIL, lockHTTPCodeStr.c_str(), lockHTTPCodeStr.length());
|
||||||
|
logErrors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
lockHTTP.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void getCards()
|
||||||
|
{
|
||||||
|
// Don't log more than one error at a time
|
||||||
|
static bool logErrors = true;
|
||||||
|
|
||||||
|
HTTPClient cardHTTP;
|
||||||
|
|
||||||
|
//cardHTTP.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
||||||
|
cardHTTP.begin(CARD_URL + wifiMACAddr + "/");
|
||||||
|
cardHTTP.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Card state HTTP begin.");
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] HTTP GET");
|
||||||
|
int16_t cardHTTPCode = cardHTTP.GET();
|
||||||
|
String cardHTTPCodeStr = String(cardHTTPCode);
|
||||||
|
|
||||||
|
if (cardHTTPCode > 0) {
|
||||||
|
if (SERIAL_LOGGING) Serial.printf("[INFO] GET success, code: %d\n", cardHTTPCode);
|
||||||
|
|
||||||
|
if (cardHTTPCode == HTTP_CODE_OK) {
|
||||||
|
logErrors = true;
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
||||||
|
String cardPayload = cardHTTP.getString();
|
||||||
|
cardPayload += String(EEPROM_END_MARKER);
|
||||||
|
if (SERIAL_LOGGING) Serial.println(cardPayload);
|
||||||
|
|
||||||
|
noInterrupts(); // commit() disables interrupts, but we want an atomic EEPROM buffer write
|
||||||
|
for (int i = 0; i < cardPayload.length(); i++) {
|
||||||
|
if (i >= EEPROM_SIZE) break;
|
||||||
|
EEPROM.write(i, cardPayload.charAt(i));
|
||||||
|
}
|
||||||
|
EEPROM.commit();
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Finished getting card data.");
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Resource not found.");
|
||||||
|
if (logErrors) logEvent(LOG_COMM_CARD_FAIL, cardHTTPCodeStr.c_str(), cardHTTPCodeStr.length());
|
||||||
|
logErrors = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", cardHTTP.errorToString(cardHTTPCode).c_str());
|
||||||
|
if (logErrors) logEvent(LOG_COMM_CARD_FAIL, cardHTTPCodeStr.c_str(), cardHTTPCodeStr.length());
|
||||||
|
logErrors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cardHTTP.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void postInfolog()
|
||||||
|
{
|
||||||
|
// Don't log more than one error at a time
|
||||||
|
static bool logErrors = true;
|
||||||
|
|
||||||
|
HTTPClient infoHTTP;
|
||||||
|
|
||||||
|
//infoHTTP.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
||||||
|
infoHTTP.begin(INFOLOG_URL + wifiMACAddr + "/");
|
||||||
|
infoHTTP.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Info state HTTP begin.");
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] HTTP POST.");
|
||||||
|
String postData = serializeLog();
|
||||||
|
int16_t infoHTTPCode = infoHTTP.POST(postData);
|
||||||
|
String infoHTTPCodeStr = String(infoHTTPCode);
|
||||||
|
|
||||||
|
if (infoHTTPCode > 0) {
|
||||||
|
if (SERIAL_LOGGING) Serial.printf("[INFO] POST success, code: %d\n", infoHTTPCode);
|
||||||
|
|
||||||
|
if (infoHTTPCode == HTTP_CODE_OK) {
|
||||||
|
logErrors = true;
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
||||||
|
String infoPayload = infoHTTP.getString();
|
||||||
|
if (SERIAL_LOGGING) Serial.println(infoPayload);
|
||||||
|
uint8_t processed;
|
||||||
|
uint32_t unixTime;
|
||||||
|
String version = String();
|
||||||
|
deserializeInfoJson(infoPayload, &processed, &unixTime, &version);
|
||||||
|
|
||||||
|
struct timeval tv = { .tv_sec = unixTime, .tv_usec = 0 };
|
||||||
|
struct timezone tz = { .tz_minuteswest = 0, .tz_dsttime = 0 };
|
||||||
|
settimeofday(&tv, &tz);
|
||||||
|
|
||||||
|
removeLogRecords(processed);
|
||||||
|
|
||||||
|
if (version != LOCKOUT_FIRMWARE_VERSION && lockState == LOCK_OFF) {
|
||||||
|
noInterrupts();
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Firmware out of date. Updating...");
|
||||||
|
WiFiClient client;
|
||||||
|
int16_t update_response = ESPhttpUpdate.update(client, UPDATE_URL + wifiMACAddr + "/");
|
||||||
|
interrupts();
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) printf("[ERROR] %s\n", ESPhttpUpdate.getLastErrorString().c_str());
|
||||||
|
String lastErrorNum = String(ESPhttpUpdate.getLastError());
|
||||||
|
logEvent(LOG_UPDATE_FAILED, lastErrorNum.c_str(), lastErrorNum.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.print("[INFO] Set system time to: ");
|
||||||
|
if (SERIAL_LOGGING) Serial.println(unixTime);
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Resource not found.");
|
||||||
|
if (logErrors) logEvent(LOG_COMM_INFO_FAIL, infoHTTPCodeStr.c_str(), infoHTTPCodeStr.length());
|
||||||
|
logErrors = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", infoHTTP.errorToString(infoHTTPCode).c_str());
|
||||||
|
if (logErrors) logEvent(LOG_COMM_INFO_FAIL, infoHTTPCodeStr.c_str(), infoHTTPCodeStr.length());
|
||||||
|
logErrors = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
infoHTTP.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
void processCommState()
|
||||||
|
{
|
||||||
|
static uint16_t commLockIdleCount, commCardIdleCount, commInfoIdleCount;
|
||||||
|
|
||||||
|
switch (commState) {
|
||||||
|
case COMM_INIT:
|
||||||
|
commLockIdleCount = 0;
|
||||||
|
commCardIdleCount = 0;
|
||||||
|
commInfoIdleCount = 0;
|
||||||
|
|
||||||
|
commState = COMM_IDLE;
|
||||||
|
break;
|
||||||
|
case COMM_IDLE:
|
||||||
|
commLockIdleCount++;
|
||||||
|
commCardIdleCount++;
|
||||||
|
commInfoIdleCount++;
|
||||||
|
|
||||||
|
if (commLockIdleCount >= COMM_LOCK_IDLE_TIME) {
|
||||||
|
commState = COMM_LOCK;
|
||||||
|
} else if (commCardIdleCount >= COMM_CARD_IDLE_TIME) {
|
||||||
|
commState = COMM_CARD;
|
||||||
|
} else if (commInfoIdleCount >= COMM_INFO_IDLE_TIME) {
|
||||||
|
commState = COMM_INFO;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMM_LOCK:
|
||||||
|
{
|
||||||
|
postState();
|
||||||
|
|
||||||
|
commLockIdleCount = 0;
|
||||||
|
|
||||||
|
commState = COMM_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMM_CARD:
|
||||||
|
{
|
||||||
|
getCards();
|
||||||
|
|
||||||
|
commCardIdleCount = 0;
|
||||||
|
|
||||||
|
commState = COMM_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMM_INFO:
|
||||||
|
{
|
||||||
|
postInfolog();
|
||||||
|
|
||||||
|
commInfoIdleCount = 0;
|
||||||
|
|
||||||
|
commState = COMM_IDLE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
34
firmware/comm.h
Normal file
34
firmware/comm.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#ifndef COMM_H
|
||||||
|
#define COMM_H
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
// times below are multiplied by DELAY_TIME, in ms
|
||||||
|
#define COMM_LOCK_IDLE_TIME 50
|
||||||
|
#define COMM_CARD_IDLE_TIME 1000
|
||||||
|
#define COMM_INFO_IDLE_TIME 3000
|
||||||
|
|
||||||
|
enum commStates
|
||||||
|
{
|
||||||
|
COMM_INIT,
|
||||||
|
COMM_IDLE,
|
||||||
|
COMM_LOCK,
|
||||||
|
COMM_CARD,
|
||||||
|
COMM_INFO,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum commStates commState;
|
||||||
|
extern char wifiMACAddr[20];
|
||||||
|
extern const char *LOCKOUT_FIRMWARE_VERSION;
|
||||||
|
extern const String SOCKET_URL;
|
||||||
|
extern const String CARD_URL;
|
||||||
|
extern const String INFOLOG_URL;
|
||||||
|
extern const String UPDATE_URL;
|
||||||
|
|
||||||
|
void postState();
|
||||||
|
void getCards();
|
||||||
|
void postInfolog();
|
||||||
|
void processCommState();
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
43
firmware/firmware.h
Normal file
43
firmware/firmware.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef FIRMWARE_H
|
||||||
|
#define FIRMWARE_H
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <base64.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
#include <ESP8266httpUpdate.h>
|
||||||
|
#include <EEPROM.h>
|
||||||
|
#include <Ticker.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if !defined(ARDUINO_ESP8266_RELEASE_2_5_0) || ARDUINOJSON_VERSION_MAJOR != 5 || ARDUINOJSON_VERSION_MINOR != 13 || ARDUINOJSON_VERSION_REVISION != 3
|
||||||
|
#error Incorrect library version detected. See README.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "lock.h"
|
||||||
|
#include "leds.h"
|
||||||
|
#include "wifi.h"
|
||||||
|
#include "comm.h"
|
||||||
|
|
||||||
|
#define DELAY_TIME 10
|
||||||
|
|
||||||
|
#define RELAY_PIN D1
|
||||||
|
#define GREEN_BUTTON_PIN D3
|
||||||
|
#define RED_BUTTON_PIN D4
|
||||||
|
#define GREEN_LED_PIN D6
|
||||||
|
#define RED_LED_PIN D7
|
||||||
|
|
||||||
|
#define RELAY_CLOSED HIGH
|
||||||
|
#define RELAY_OPEN !RELAY_CLOSED
|
||||||
|
#define BUTTON_CLOSED LOW
|
||||||
|
#define BUTTON_OPEN !BUTTON_CLOSED
|
||||||
|
#define LED_PIN_ON HIGH
|
||||||
|
#define LED_PIN_OFF !LED_PIN_ON
|
||||||
|
|
||||||
|
#define EEPROM_SIZE 4095
|
||||||
|
#define EEPROM_END_MARKER '\0'
|
||||||
|
|
||||||
|
#endif
|
|
@ -1,22 +1,8 @@
|
||||||
#include <Arduino.h>
|
#include "firmware.h"
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <base64.h>
|
|
||||||
#include <ESP8266WiFi.h>
|
|
||||||
#include <ESP8266HTTPClient.h>
|
|
||||||
#include <ESP8266httpUpdate.h>
|
|
||||||
#include <EEPROM.h>
|
|
||||||
#include <Ticker.h>
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#if !defined(ARDUINO_ESP8266_RELEASE_2_5_0) || ARDUINOJSON_VERSION_MAJOR != 5 || ARDUINOJSON_VERSION_MINOR != 13 || ARDUINOJSON_VERSION_REVISION != 3
|
const char *LOCKOUT_FIRMWARE_VERSION = "MRWIZARD 0010 MRWIZARD";
|
||||||
#error Incorrect library version detected. See README.
|
const char *LOCKOUT_WIFI_SSID PROGMEM = "Protospace";
|
||||||
#endif
|
const char *LOCKOUT_WIFI_PASS PROGMEM = "yycmakers";
|
||||||
|
|
||||||
const char *FIRMWARE_VERSION = "MRWIZARD 0010 MRWIZARD";
|
|
||||||
|
|
||||||
const char *WIFI_SSID PROGMEM = "Protospace";
|
|
||||||
const char *WIFI_PASS PROGMEM = "yycmakers";
|
|
||||||
char wifiMACAddr[20] = "";
|
|
||||||
const String SOCKET_URL = String("http://tools-socket.protospace.ca/api/lockout/");
|
const String SOCKET_URL = String("http://tools-socket.protospace.ca/api/lockout/");
|
||||||
const String CARD_URL = String("http://tools-auth.protospace.ca/cards/");
|
const String CARD_URL = String("http://tools-auth.protospace.ca/cards/");
|
||||||
const String INFOLOG_URL = String("http://tools-auth.protospace.ca/infolog/");
|
const String INFOLOG_URL = String("http://tools-auth.protospace.ca/infolog/");
|
||||||
|
@ -24,153 +10,15 @@ const String UPDATE_URL = String("http://tools-auth.protospace.ca/update/");
|
||||||
|
|
||||||
Ticker ticker;
|
Ticker ticker;
|
||||||
|
|
||||||
#define CARD_BUFFER_LENGTH 14
|
char wifiMACAddr[20] = "";
|
||||||
char cardBuffer[CARD_BUFFER_LENGTH];
|
char cardBuffer[CARD_BUFFER_LENGTH];
|
||||||
|
|
||||||
#define CARD_DATA_LENGTH 10
|
|
||||||
#define CARD_CHECK_LENGTH 2
|
|
||||||
#define CARD_HEAD_BYTE 0x2
|
|
||||||
#define CARD_TAIL_BYTE 0x3
|
|
||||||
struct __attribute__((packed)) cardData {
|
|
||||||
char head;
|
|
||||||
char data[CARD_DATA_LENGTH];
|
|
||||||
char checksum[CARD_CHECK_LENGTH];
|
|
||||||
char tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define RELAY_PIN D1
|
|
||||||
#define GREEN_BUTTON_PIN D3
|
|
||||||
#define RED_BUTTON_PIN D4
|
|
||||||
#define GREEN_LED_PIN D6
|
|
||||||
#define RED_LED_PIN D7
|
|
||||||
|
|
||||||
#define RELAY_CLOSED HIGH
|
|
||||||
#define RELAY_OPEN !RELAY_CLOSED
|
|
||||||
#define BUTTON_CLOSED LOW
|
|
||||||
#define BUTTON_OPEN !BUTTON_CLOSED
|
|
||||||
#define LED_PIN_ON HIGH
|
|
||||||
#define LED_PIN_OFF !LED_PIN_ON
|
|
||||||
|
|
||||||
#define DELAY_TIME 10
|
|
||||||
// times below are multiplied by DELAY_TIME, in ms
|
|
||||||
#define LOCK_ARMED_TIMEOUT 1000
|
|
||||||
#define COMM_LOCK_IDLE_TIME 50
|
|
||||||
#define COMM_CARD_IDLE_TIME 1000
|
|
||||||
#define COMM_INFO_IDLE_TIME 3000
|
|
||||||
#define LED_ARMED_BLINK_TIME 50
|
|
||||||
#define LED_ERROR_BLINK_TIME 50
|
|
||||||
|
|
||||||
#define EEPROM_SIZE 4095
|
|
||||||
#define EEPROM_END_MARKER '\0'
|
|
||||||
|
|
||||||
enum wifiStates
|
|
||||||
{
|
|
||||||
WIFI_DISCONNECTED,
|
|
||||||
WIFI_CONNECTING,
|
|
||||||
WIFI_CONNECTED,
|
|
||||||
} wifiState = WIFI_DISCONNECTED;
|
|
||||||
|
|
||||||
enum LEDStates
|
|
||||||
{
|
|
||||||
LED_OFF,
|
|
||||||
LED_ARMED,
|
|
||||||
LED_ON,
|
|
||||||
LED_ERROR,
|
|
||||||
} LEDState = LED_OFF;
|
|
||||||
|
|
||||||
enum lockStates
|
|
||||||
{
|
|
||||||
LOCK_OFF,
|
|
||||||
LOCK_PREARM, // prevent arming while buttons held
|
|
||||||
LOCK_ARMED,
|
|
||||||
LOCK_ON_PRESSED, // to wait until button is released
|
|
||||||
LOCK_ON,
|
|
||||||
} lockState = LOCK_OFF;
|
|
||||||
|
|
||||||
enum commStates
|
|
||||||
{
|
|
||||||
COMM_INIT,
|
|
||||||
COMM_IDLE,
|
|
||||||
COMM_LOCK,
|
|
||||||
COMM_CARD,
|
|
||||||
COMM_INFO,
|
|
||||||
} commState = COMM_INIT;
|
|
||||||
|
|
||||||
#define SERIAL_LOGGING true
|
|
||||||
|
|
||||||
#define LOG_SIZE 90 // 100 blew up the stack
|
|
||||||
#define LOG_DATA_LENGTH CARD_DATA_LENGTH
|
|
||||||
|
|
||||||
enum eventCodes
|
|
||||||
{
|
|
||||||
LOG_BOOT_UP,
|
|
||||||
LOG_INIT_COMPLETE,
|
|
||||||
LOG_WIFI_CONNECTED,
|
|
||||||
LOG_WIFI_DISCONNECTED,
|
|
||||||
LOG_COMM_LOCK_ARM,
|
|
||||||
LOG_COMM_LOCK_DISARM,
|
|
||||||
LOG_COMM_LOCK_FAIL,
|
|
||||||
LOG_COMM_CARD_FAIL,
|
|
||||||
LOG_COMM_INFO_FAIL,
|
|
||||||
LOG_LOCK_OFF,
|
|
||||||
LOG_LOCK_ARMED,
|
|
||||||
LOG_LOCK_TIMEOUT,
|
|
||||||
LOG_LOCK_ON,
|
|
||||||
LOG_LOCK_DISARM,
|
|
||||||
LOG_LOCK_ERROR,
|
|
||||||
LOG_CARD_GOOD_READ,
|
|
||||||
LOG_CARD_ACCEPTED,
|
|
||||||
LOG_CARD_DENIED,
|
|
||||||
LOG_UPDATE_FAILED,
|
|
||||||
LOG_TEST,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct __attribute__((packed)) logData {
|
|
||||||
uint32_t unixTime;
|
|
||||||
uint8_t eventCode;
|
|
||||||
char data[LOG_DATA_LENGTH];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct logData eventLog[LOG_SIZE];
|
struct logData eventLog[LOG_SIZE];
|
||||||
uint16_t logPosition = 0;
|
uint16_t logPosition = 0;
|
||||||
|
|
||||||
void logEvent(uint8_t eventCode, const char *data = nullptr, size_t num = 0)
|
enum wifiStates wifiState = WIFI_DISCONNECTED;
|
||||||
{
|
enum LEDStates LEDState = LED_OFF;
|
||||||
struct logData event;
|
enum lockStates lockState = LOCK_OFF;
|
||||||
|
enum commStates commState = COMM_INIT;
|
||||||
noInterrupts();
|
|
||||||
|
|
||||||
event.unixTime = time(nullptr);
|
|
||||||
event.eventCode = eventCode;
|
|
||||||
|
|
||||||
memset(event.data, 0, LOG_DATA_LENGTH);
|
|
||||||
for (uint8_t i = 0; i < LOG_DATA_LENGTH; i++) {
|
|
||||||
if (i >= num) break;
|
|
||||||
event.data[i] = data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (logPosition < LOG_SIZE) {
|
|
||||||
eventLog[logPosition++] = event;
|
|
||||||
}
|
|
||||||
|
|
||||||
interrupts();
|
|
||||||
}
|
|
||||||
|
|
||||||
void removeLogRecords(uint8_t num) {
|
|
||||||
// shift records down by num because they've been sent
|
|
||||||
|
|
||||||
if (num > logPosition) return;
|
|
||||||
|
|
||||||
noInterrupts();
|
|
||||||
|
|
||||||
for (int i = 0; i < num; i++) {
|
|
||||||
eventLog[i] = eventLog[i + num];
|
|
||||||
}
|
|
||||||
logPosition -= num;
|
|
||||||
|
|
||||||
interrupts();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
@ -182,9 +30,9 @@ void setup()
|
||||||
settimeofday(&tv, &tz);
|
settimeofday(&tv, &tz);
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Set system time to 0.");
|
if (SERIAL_LOGGING) Serial.println("[INFO] Set system time to 0.");
|
||||||
|
|
||||||
logEvent(LOG_BOOT_UP, &FIRMWARE_VERSION[9], 4);
|
logEvent(LOG_BOOT_UP, &LOCKOUT_FIRMWARE_VERSION[9], 4);
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] Booting firmware version: ");
|
if (SERIAL_LOGGING) Serial.print("[INFO] Booting firmware version: ");
|
||||||
if (SERIAL_LOGGING) Serial.println(FIRMWARE_VERSION);
|
if (SERIAL_LOGGING) Serial.println(LOCKOUT_FIRMWARE_VERSION);
|
||||||
|
|
||||||
pinMode(RELAY_PIN, OUTPUT);
|
pinMode(RELAY_PIN, OUTPUT);
|
||||||
pinMode(GREEN_BUTTON_PIN, INPUT_PULLUP);
|
pinMode(GREEN_BUTTON_PIN, INPUT_PULLUP);
|
||||||
|
@ -244,523 +92,3 @@ void loop()
|
||||||
|
|
||||||
delay(DELAY_TIME);
|
delay(DELAY_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t charToNum(char input)
|
|
||||||
{
|
|
||||||
return String("0123456789ABCDEF").indexOf(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool checksum(struct cardData *cardData)
|
|
||||||
{
|
|
||||||
// checksum is each hex data byte xord'd together.
|
|
||||||
// each char is a hex nibble, so we have to work in pairs.
|
|
||||||
|
|
||||||
int8_t even = 0, odd = 0;
|
|
||||||
|
|
||||||
for (int8_t i = 0; i < CARD_DATA_LENGTH; i++) {
|
|
||||||
int8_t num = charToNum(cardData->data[i]);
|
|
||||||
|
|
||||||
if (num == -1) return false;
|
|
||||||
if (i % 2 == 0) even ^= num;
|
|
||||||
if (i % 2 == 1) odd ^= num;
|
|
||||||
}
|
|
||||||
|
|
||||||
int8_t checksum_even = charToNum(cardData->checksum[0]);
|
|
||||||
int8_t checksum_odd = charToNum(cardData->checksum[1]);
|
|
||||||
|
|
||||||
if (even == checksum_even && odd == checksum_odd) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void checkCard()
|
|
||||||
{
|
|
||||||
struct cardData *cardData = (struct cardData *) cardBuffer;
|
|
||||||
|
|
||||||
if (cardData->head == CARD_HEAD_BYTE &&
|
|
||||||
cardData->tail == CARD_TAIL_BYTE &&
|
|
||||||
checksum(cardData)) {
|
|
||||||
|
|
||||||
String cardStr = String();
|
|
||||||
String authorizedCards = String();
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < CARD_DATA_LENGTH; i++) {
|
|
||||||
cardStr += cardData->data[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < EEPROM_SIZE; i++) {
|
|
||||||
char tmp = EEPROM.read(i);
|
|
||||||
authorizedCards += tmp;
|
|
||||||
if (tmp == EEPROM_END_MARKER) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Good scan from card: " + cardStr);
|
|
||||||
logEvent(LOG_CARD_GOOD_READ, cardStr.c_str(), cardStr.length());
|
|
||||||
|
|
||||||
if (authorizedCards.indexOf(cardStr) >= 0) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Card is authorized on machine.");
|
|
||||||
if (lockState == LOCK_OFF) {
|
|
||||||
lockState = LOCK_PREARM;
|
|
||||||
}
|
|
||||||
logEvent(LOG_CARD_ACCEPTED, cardStr.c_str(), cardStr.length());
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Card not authorized on machine.");
|
|
||||||
LEDState = LED_ERROR;
|
|
||||||
logEvent(LOG_CARD_DENIED, cardStr.c_str(), cardStr.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processWifiState()
|
|
||||||
{
|
|
||||||
switch(wifiState) {
|
|
||||||
case WIFI_DISCONNECTED:
|
|
||||||
commState = COMM_INIT;
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Wifi attempting to connect...");
|
|
||||||
|
|
||||||
WiFi.begin(WIFI_SSID, WIFI_PASS);
|
|
||||||
|
|
||||||
wifiState = WIFI_CONNECTING;
|
|
||||||
break;
|
|
||||||
case WIFI_CONNECTING:
|
|
||||||
commState = COMM_INIT;
|
|
||||||
|
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Wifi is connected.");
|
|
||||||
logEvent(LOG_WIFI_CONNECTED);
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] Wifi IP Address: ");
|
|
||||||
if (SERIAL_LOGGING) Serial.println(WiFi.localIP());
|
|
||||||
|
|
||||||
wifiState = WIFI_CONNECTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case WIFI_CONNECTED:
|
|
||||||
if (WiFi.status() != WL_CONNECTED) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Wifi disconnected.");
|
|
||||||
logEvent(LOG_WIFI_DISCONNECTED);
|
|
||||||
wifiState = WIFI_DISCONNECTED;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Invalid wifi state.");
|
|
||||||
wifiState = WIFI_DISCONNECTED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool greenButton() { return digitalRead(GREEN_BUTTON_PIN) == BUTTON_CLOSED; }
|
|
||||||
bool redButton() { return digitalRead(RED_BUTTON_PIN) == BUTTON_CLOSED; }
|
|
||||||
|
|
||||||
void relayOn() { digitalWrite(RELAY_PIN, RELAY_CLOSED); }
|
|
||||||
void relayOff() { digitalWrite(RELAY_PIN, RELAY_OPEN); }
|
|
||||||
|
|
||||||
void processLockState()
|
|
||||||
{
|
|
||||||
static uint16_t lockArmedTimeoutCount;
|
|
||||||
|
|
||||||
if (lockState != LOCK_ARMED) lockArmedTimeoutCount = 0;
|
|
||||||
|
|
||||||
switch (lockState) {
|
|
||||||
case LOCK_OFF:
|
|
||||||
if (LEDState != LED_ERROR) LEDState = LED_OFF;
|
|
||||||
|
|
||||||
relayOff();
|
|
||||||
break;
|
|
||||||
case LOCK_PREARM:
|
|
||||||
if (!greenButton() && !redButton()) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Arming interlock.");
|
|
||||||
logEvent(LOG_LOCK_ARMED);
|
|
||||||
lockState = LOCK_ARMED;
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Buttons held, aborting.");
|
|
||||||
logEvent(LOG_LOCK_ERROR);
|
|
||||||
LEDState = LED_ERROR;
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LOCK_ARMED:
|
|
||||||
if (LEDState != LED_ERROR) LEDState = LED_ARMED;
|
|
||||||
|
|
||||||
relayOff();
|
|
||||||
lockArmedTimeoutCount++;
|
|
||||||
|
|
||||||
if (redButton()) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Unarming interlock.");
|
|
||||||
logEvent(LOG_LOCK_DISARM);
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
} else if (greenButton()) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] On button pressed.");
|
|
||||||
lockState = LOCK_ON_PRESSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lockArmedTimeoutCount > LOCK_ARMED_TIMEOUT) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Arming timed out, disarming.");
|
|
||||||
logEvent(LOG_LOCK_TIMEOUT);
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
LEDState = LED_ERROR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LOCK_ON_PRESSED:
|
|
||||||
if (redButton()) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Off button pressed, aborting.");
|
|
||||||
logEvent(LOG_LOCK_ERROR);
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
} else if (!greenButton()) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Turning machine on.");
|
|
||||||
logEvent(LOG_LOCK_ON);
|
|
||||||
lockState = LOCK_ON;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LOCK_ON:
|
|
||||||
if (LEDState != LED_ERROR) LEDState = LED_ON;
|
|
||||||
|
|
||||||
relayOn();
|
|
||||||
|
|
||||||
if (redButton()) {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Off button pressed.");
|
|
||||||
logEvent(LOG_LOCK_OFF);
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Invalid lock state.");
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void greenLEDOn() { digitalWrite(GREEN_LED_PIN, LED_PIN_ON); }
|
|
||||||
void greenLEDOff() { digitalWrite(GREEN_LED_PIN, LED_PIN_OFF); }
|
|
||||||
void redLEDOn() { digitalWrite(RED_LED_PIN, LED_PIN_ON); }
|
|
||||||
void redLEDOff() { digitalWrite(RED_LED_PIN, LED_PIN_OFF); }
|
|
||||||
|
|
||||||
void processLEDState()
|
|
||||||
{
|
|
||||||
static uint16_t LEDArmedBlinkCount, LEDErrorBlinkCount;
|
|
||||||
|
|
||||||
if (LEDState != LED_ARMED) LEDArmedBlinkCount = 0;
|
|
||||||
if (LEDState != LED_ERROR) LEDErrorBlinkCount = 0;
|
|
||||||
|
|
||||||
switch (LEDState) {
|
|
||||||
case LED_OFF:
|
|
||||||
greenLEDOff();
|
|
||||||
redLEDOn();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LED_ARMED:
|
|
||||||
LEDArmedBlinkCount++;
|
|
||||||
|
|
||||||
if (LEDArmedBlinkCount < LED_ARMED_BLINK_TIME) {
|
|
||||||
greenLEDOn();
|
|
||||||
redLEDOn();
|
|
||||||
} else if (LEDArmedBlinkCount < LED_ARMED_BLINK_TIME * 2) {
|
|
||||||
greenLEDOff();
|
|
||||||
redLEDOn();
|
|
||||||
} else {
|
|
||||||
LEDArmedBlinkCount = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LED_ON:
|
|
||||||
greenLEDOn();
|
|
||||||
redLEDOn();
|
|
||||||
|
|
||||||
break;
|
|
||||||
case LED_ERROR:
|
|
||||||
LEDErrorBlinkCount++;
|
|
||||||
|
|
||||||
if (LEDErrorBlinkCount < LED_ERROR_BLINK_TIME) {
|
|
||||||
greenLEDOff();
|
|
||||||
redLEDOff();
|
|
||||||
} else if (LEDErrorBlinkCount < LED_ERROR_BLINK_TIME * 2) {
|
|
||||||
greenLEDOff();
|
|
||||||
redLEDOn();
|
|
||||||
} else {
|
|
||||||
LEDErrorBlinkCount = 0;
|
|
||||||
LEDState = LED_OFF;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Invalid LED state.");
|
|
||||||
LEDState = LED_OFF;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// JSON functions to prevent memory leaking see:
|
|
||||||
// https://arduinojson.org/v5/faq/i-found-a-memory-leak-in-the-library/
|
|
||||||
String serializeLockJson(uint8_t lockState)
|
|
||||||
{
|
|
||||||
// Generated with: https://arduinojson.org/assistant/
|
|
||||||
const size_t bufferSize = JSON_OBJECT_SIZE(1) + 50;
|
|
||||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
|
||||||
|
|
||||||
JsonObject& root = jsonBuffer.createObject();
|
|
||||||
root["lockState"] = (uint8_t) lockState;
|
|
||||||
String postData = String();
|
|
||||||
root.printTo(postData);
|
|
||||||
|
|
||||||
return postData;
|
|
||||||
}
|
|
||||||
|
|
||||||
String deserializeLockJson(String input)
|
|
||||||
{
|
|
||||||
// Generated with: https://arduinojson.org/assistant/
|
|
||||||
const size_t bufferSize = JSON_OBJECT_SIZE(1) + 50;
|
|
||||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
|
||||||
JsonObject& root = jsonBuffer.parseObject(input);
|
|
||||||
|
|
||||||
String action = root["action"];
|
|
||||||
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
|
|
||||||
String serializeLog() {
|
|
||||||
size_t logLengthBytes = logPosition * sizeof(struct logData);
|
|
||||||
return "{\"log\": \"" + base64::encode((uint8_t *) eventLog, logLengthBytes, false) + "\"}";
|
|
||||||
}
|
|
||||||
|
|
||||||
void deserializeInfoJson(String input, uint8_t *processed, uint32_t *unixTime, String *version)
|
|
||||||
{
|
|
||||||
// Generated with: https://arduinojson.org/assistant/
|
|
||||||
const size_t bufferSize = JSON_OBJECT_SIZE(3) + 70;
|
|
||||||
StaticJsonBuffer<bufferSize> jsonBuffer;
|
|
||||||
JsonObject& root = jsonBuffer.parseObject(input);
|
|
||||||
|
|
||||||
*processed = root["processed"];
|
|
||||||
*unixTime = root["unixTime"];
|
|
||||||
*version = root["version"].as<String>();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//TODO: abstract http functions
|
|
||||||
|
|
||||||
void postState()
|
|
||||||
{
|
|
||||||
// Don't log more than one error at a time
|
|
||||||
static bool logErrors = true;
|
|
||||||
|
|
||||||
HTTPClient lockHTTP;
|
|
||||||
|
|
||||||
//lockHTTP.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
|
||||||
lockHTTP.begin(SOCKET_URL + wifiMACAddr);
|
|
||||||
lockHTTP.addHeader("Content-Type", "application/json");
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Lock state HTTP begin.");
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] HTTP POST: ");
|
|
||||||
String postData = serializeLockJson(lockState);
|
|
||||||
if (SERIAL_LOGGING) Serial.println(postData);
|
|
||||||
int16_t lockHTTPCode = lockHTTP.POST(postData);
|
|
||||||
String lockHTTPCodeStr = String(lockHTTPCode);
|
|
||||||
|
|
||||||
if (lockHTTPCode > 0) {
|
|
||||||
if (SERIAL_LOGGING) Serial.printf("[INFO] POST success, code: %d\n", lockHTTPCode);
|
|
||||||
|
|
||||||
if (lockHTTPCode == HTTP_CODE_OK) {
|
|
||||||
logErrors = true;
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
|
||||||
String lockPayload = lockHTTP.getString();
|
|
||||||
if (SERIAL_LOGGING) Serial.println(lockPayload);
|
|
||||||
String action = deserializeLockJson(lockPayload);
|
|
||||||
|
|
||||||
if (action == "arm" && lockState == LOCK_OFF && LEDState == LED_OFF) {
|
|
||||||
logEvent(LOG_COMM_LOCK_ARM);
|
|
||||||
lockState = LOCK_PREARM;
|
|
||||||
} else if (action == "disarm" && lockState != LOCK_ON) {
|
|
||||||
logEvent(LOG_COMM_LOCK_DISARM);
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Unarming interlock.");
|
|
||||||
logEvent(LOG_LOCK_DISARM);
|
|
||||||
lockState = LOCK_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] action: " + action);
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Resource not found.");
|
|
||||||
if (logErrors) logEvent(LOG_COMM_LOCK_FAIL, lockHTTPCodeStr.c_str(), lockHTTPCodeStr.length());
|
|
||||||
logErrors = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", lockHTTP.errorToString(lockHTTPCode).c_str());
|
|
||||||
if (logErrors) logEvent(LOG_COMM_LOCK_FAIL, lockHTTPCodeStr.c_str(), lockHTTPCodeStr.length());
|
|
||||||
logErrors = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
lockHTTP.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void getCards()
|
|
||||||
{
|
|
||||||
// Don't log more than one error at a time
|
|
||||||
static bool logErrors = true;
|
|
||||||
|
|
||||||
HTTPClient cardHTTP;
|
|
||||||
|
|
||||||
//cardHTTP.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
|
||||||
cardHTTP.begin(CARD_URL + wifiMACAddr + "/");
|
|
||||||
cardHTTP.addHeader("Content-Type", "application/json");
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Card state HTTP begin.");
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] HTTP GET");
|
|
||||||
int16_t cardHTTPCode = cardHTTP.GET();
|
|
||||||
String cardHTTPCodeStr = String(cardHTTPCode);
|
|
||||||
|
|
||||||
if (cardHTTPCode > 0) {
|
|
||||||
if (SERIAL_LOGGING) Serial.printf("[INFO] GET success, code: %d\n", cardHTTPCode);
|
|
||||||
|
|
||||||
if (cardHTTPCode == HTTP_CODE_OK) {
|
|
||||||
logErrors = true;
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
|
||||||
String cardPayload = cardHTTP.getString();
|
|
||||||
cardPayload += String(EEPROM_END_MARKER);
|
|
||||||
if (SERIAL_LOGGING) Serial.println(cardPayload);
|
|
||||||
|
|
||||||
noInterrupts(); // commit() disables interrupts, but we want an atomic EEPROM buffer write
|
|
||||||
for (int i = 0; i < cardPayload.length(); i++) {
|
|
||||||
if (i >= EEPROM_SIZE) break;
|
|
||||||
EEPROM.write(i, cardPayload.charAt(i));
|
|
||||||
}
|
|
||||||
EEPROM.commit();
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Finished getting card data.");
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Resource not found.");
|
|
||||||
if (logErrors) logEvent(LOG_COMM_CARD_FAIL, cardHTTPCodeStr.c_str(), cardHTTPCodeStr.length());
|
|
||||||
logErrors = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", cardHTTP.errorToString(cardHTTPCode).c_str());
|
|
||||||
if (logErrors) logEvent(LOG_COMM_CARD_FAIL, cardHTTPCodeStr.c_str(), cardHTTPCodeStr.length());
|
|
||||||
logErrors = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
cardHTTP.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void postInfolog()
|
|
||||||
{
|
|
||||||
// Don't log more than one error at a time
|
|
||||||
static bool logErrors = true;
|
|
||||||
|
|
||||||
HTTPClient infoHTTP;
|
|
||||||
|
|
||||||
//infoHTTP.begin("https://url", "7a 9c f4 db 40 d3 62 5a 6e 21 bc 5c cc 66 c8 3e a1 45 59 38"); //HTTPS
|
|
||||||
infoHTTP.begin(INFOLOG_URL + wifiMACAddr + "/");
|
|
||||||
infoHTTP.addHeader("Content-Type", "application/json");
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Info state HTTP begin.");
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] HTTP POST.");
|
|
||||||
String postData = serializeLog();
|
|
||||||
int16_t infoHTTPCode = infoHTTP.POST(postData);
|
|
||||||
String infoHTTPCodeStr = String(infoHTTPCode);
|
|
||||||
|
|
||||||
if (infoHTTPCode > 0) {
|
|
||||||
if (SERIAL_LOGGING) Serial.printf("[INFO] POST success, code: %d\n", infoHTTPCode);
|
|
||||||
|
|
||||||
if (infoHTTPCode == HTTP_CODE_OK) {
|
|
||||||
logErrors = true;
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] Resource found, parsing response: ");
|
|
||||||
String infoPayload = infoHTTP.getString();
|
|
||||||
if (SERIAL_LOGGING) Serial.println(infoPayload);
|
|
||||||
uint8_t processed;
|
|
||||||
uint32_t unixTime;
|
|
||||||
String version = String();
|
|
||||||
deserializeInfoJson(infoPayload, &processed, &unixTime, &version);
|
|
||||||
|
|
||||||
struct timeval tv = { .tv_sec = unixTime, .tv_usec = 0 };
|
|
||||||
struct timezone tz = { .tz_minuteswest = 0, .tz_dsttime = 0 };
|
|
||||||
settimeofday(&tv, &tz);
|
|
||||||
|
|
||||||
removeLogRecords(processed);
|
|
||||||
|
|
||||||
if (version != FIRMWARE_VERSION && lockState == LOCK_OFF) {
|
|
||||||
noInterrupts();
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[INFO] Firmware out of date. Updating...");
|
|
||||||
WiFiClient client;
|
|
||||||
int16_t update_response = ESPhttpUpdate.update(client, UPDATE_URL + wifiMACAddr + "/");
|
|
||||||
interrupts();
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) printf("[ERROR] %s\n", ESPhttpUpdate.getLastErrorString().c_str());
|
|
||||||
String lastErrorNum = String(ESPhttpUpdate.getLastError());
|
|
||||||
logEvent(LOG_UPDATE_FAILED, lastErrorNum.c_str(), lastErrorNum.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SERIAL_LOGGING) Serial.print("[INFO] Set system time to: ");
|
|
||||||
if (SERIAL_LOGGING) Serial.println(unixTime);
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.println("[ERROR] Resource not found.");
|
|
||||||
if (logErrors) logEvent(LOG_COMM_INFO_FAIL, infoHTTPCodeStr.c_str(), infoHTTPCodeStr.length());
|
|
||||||
logErrors = false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (SERIAL_LOGGING) Serial.printf("[ERROR] POST failed, error: %s\n", infoHTTP.errorToString(infoHTTPCode).c_str());
|
|
||||||
if (logErrors) logEvent(LOG_COMM_INFO_FAIL, infoHTTPCodeStr.c_str(), infoHTTPCodeStr.length());
|
|
||||||
logErrors = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
infoHTTP.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
void processCommState()
|
|
||||||
{
|
|
||||||
static uint16_t commLockIdleCount, commCardIdleCount, commInfoIdleCount;
|
|
||||||
|
|
||||||
switch (commState) {
|
|
||||||
case COMM_INIT:
|
|
||||||
commLockIdleCount = 0;
|
|
||||||
commCardIdleCount = 0;
|
|
||||||
commInfoIdleCount = 0;
|
|
||||||
|
|
||||||
commState = COMM_IDLE;
|
|
||||||
break;
|
|
||||||
case COMM_IDLE:
|
|
||||||
commLockIdleCount++;
|
|
||||||
commCardIdleCount++;
|
|
||||||
commInfoIdleCount++;
|
|
||||||
|
|
||||||
if (commLockIdleCount >= COMM_LOCK_IDLE_TIME) {
|
|
||||||
commState = COMM_LOCK;
|
|
||||||
} else if (commCardIdleCount >= COMM_CARD_IDLE_TIME) {
|
|
||||||
commState = COMM_CARD;
|
|
||||||
} else if (commInfoIdleCount >= COMM_INFO_IDLE_TIME) {
|
|
||||||
commState = COMM_INFO;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMM_LOCK:
|
|
||||||
{
|
|
||||||
postState();
|
|
||||||
|
|
||||||
commLockIdleCount = 0;
|
|
||||||
|
|
||||||
commState = COMM_IDLE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMM_CARD:
|
|
||||||
{
|
|
||||||
getCards();
|
|
||||||
|
|
||||||
commCardIdleCount = 0;
|
|
||||||
|
|
||||||
commState = COMM_IDLE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMM_INFO:
|
|
||||||
{
|
|
||||||
postInfolog();
|
|
||||||
|
|
||||||
commInfoIdleCount = 0;
|
|
||||||
|
|
||||||
commState = COMM_IDLE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
53
firmware/leds.cpp
Normal file
53
firmware/leds.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#include "leds.h"
|
||||||
|
|
||||||
|
void processLEDState()
|
||||||
|
{
|
||||||
|
static uint16_t LEDArmedBlinkCount, LEDErrorBlinkCount;
|
||||||
|
|
||||||
|
if (LEDState != LED_ARMED) LEDArmedBlinkCount = 0;
|
||||||
|
if (LEDState != LED_ERROR) LEDErrorBlinkCount = 0;
|
||||||
|
|
||||||
|
switch (LEDState) {
|
||||||
|
case LED_OFF:
|
||||||
|
greenLEDOff();
|
||||||
|
redLEDOn();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LED_ARMED:
|
||||||
|
LEDArmedBlinkCount++;
|
||||||
|
|
||||||
|
if (LEDArmedBlinkCount < LED_ARMED_BLINK_TIME) {
|
||||||
|
greenLEDOn();
|
||||||
|
redLEDOn();
|
||||||
|
} else if (LEDArmedBlinkCount < LED_ARMED_BLINK_TIME * 2) {
|
||||||
|
greenLEDOff();
|
||||||
|
redLEDOn();
|
||||||
|
} else {
|
||||||
|
LEDArmedBlinkCount = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LED_ON:
|
||||||
|
greenLEDOn();
|
||||||
|
redLEDOn();
|
||||||
|
|
||||||
|
break;
|
||||||
|
case LED_ERROR:
|
||||||
|
LEDErrorBlinkCount++;
|
||||||
|
|
||||||
|
if (LEDErrorBlinkCount < LED_ERROR_BLINK_TIME) {
|
||||||
|
greenLEDOff();
|
||||||
|
redLEDOff();
|
||||||
|
} else if (LEDErrorBlinkCount < LED_ERROR_BLINK_TIME * 2) {
|
||||||
|
greenLEDOff();
|
||||||
|
redLEDOn();
|
||||||
|
} else {
|
||||||
|
LEDErrorBlinkCount = 0;
|
||||||
|
LEDState = LED_OFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Invalid LED state.");
|
||||||
|
LEDState = LED_OFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
22
firmware/leds.h
Normal file
22
firmware/leds.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef LEDS_H
|
||||||
|
#define LEDS_H
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
// times below are multiplied by DELAY_TIME, in ms
|
||||||
|
#define LED_ARMED_BLINK_TIME 50
|
||||||
|
#define LED_ERROR_BLINK_TIME 50
|
||||||
|
|
||||||
|
enum LEDStates
|
||||||
|
{
|
||||||
|
LED_OFF,
|
||||||
|
LED_ARMED,
|
||||||
|
LED_ON,
|
||||||
|
LED_ERROR,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum LEDStates LEDState;
|
||||||
|
|
||||||
|
void processLEDState();
|
||||||
|
|
||||||
|
#endif
|
76
firmware/lock.cpp
Normal file
76
firmware/lock.cpp
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
|
void processLockState()
|
||||||
|
{
|
||||||
|
static uint16_t lockArmedTimeoutCount;
|
||||||
|
|
||||||
|
if (lockState != LOCK_ARMED) lockArmedTimeoutCount = 0;
|
||||||
|
|
||||||
|
switch (lockState) {
|
||||||
|
case LOCK_OFF:
|
||||||
|
if (LEDState != LED_ERROR) LEDState = LED_OFF;
|
||||||
|
|
||||||
|
relayOff();
|
||||||
|
break;
|
||||||
|
case LOCK_PREARM:
|
||||||
|
if (!greenButton() && !redButton()) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Arming interlock.");
|
||||||
|
logEvent(LOG_LOCK_ARMED);
|
||||||
|
lockState = LOCK_ARMED;
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Buttons held, aborting.");
|
||||||
|
logEvent(LOG_LOCK_ERROR);
|
||||||
|
LEDState = LED_ERROR;
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOCK_ARMED:
|
||||||
|
if (LEDState != LED_ERROR) LEDState = LED_ARMED;
|
||||||
|
|
||||||
|
relayOff();
|
||||||
|
lockArmedTimeoutCount++;
|
||||||
|
|
||||||
|
if (redButton()) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Unarming interlock.");
|
||||||
|
logEvent(LOG_LOCK_DISARM);
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
} else if (greenButton()) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] On button pressed.");
|
||||||
|
lockState = LOCK_ON_PRESSED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lockArmedTimeoutCount > LOCK_ARMED_TIMEOUT) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Arming timed out, disarming.");
|
||||||
|
logEvent(LOG_LOCK_TIMEOUT);
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
LEDState = LED_ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOCK_ON_PRESSED:
|
||||||
|
if (redButton()) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Off button pressed, aborting.");
|
||||||
|
logEvent(LOG_LOCK_ERROR);
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
} else if (!greenButton()) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Turning machine on.");
|
||||||
|
logEvent(LOG_LOCK_ON);
|
||||||
|
lockState = LOCK_ON;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case LOCK_ON:
|
||||||
|
if (LEDState != LED_ERROR) LEDState = LED_ON;
|
||||||
|
|
||||||
|
relayOn();
|
||||||
|
|
||||||
|
if (redButton()) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Off button pressed.");
|
||||||
|
logEvent(LOG_LOCK_OFF);
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Invalid lock state.");
|
||||||
|
lockState = LOCK_OFF;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
22
firmware/lock.h
Normal file
22
firmware/lock.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef LOCK_H
|
||||||
|
#define LOCK_H
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
// times below are multiplied by DELAY_TIME, in ms
|
||||||
|
#define LOCK_ARMED_TIMEOUT 1000
|
||||||
|
|
||||||
|
enum lockStates
|
||||||
|
{
|
||||||
|
LOCK_OFF,
|
||||||
|
LOCK_PREARM, // prevent arming while buttons held
|
||||||
|
LOCK_ARMED,
|
||||||
|
LOCK_ON_PRESSED, // to wait until button is released
|
||||||
|
LOCK_ON,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum lockStates lockState;
|
||||||
|
|
||||||
|
void processLockState();
|
||||||
|
|
||||||
|
#endif
|
39
firmware/logging.cpp
Normal file
39
firmware/logging.cpp
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "logging.h"
|
||||||
|
|
||||||
|
void logEvent(uint8_t eventCode, const char *data, size_t num)
|
||||||
|
{
|
||||||
|
struct logData event;
|
||||||
|
|
||||||
|
noInterrupts();
|
||||||
|
|
||||||
|
event.unixTime = time(nullptr);
|
||||||
|
event.eventCode = eventCode;
|
||||||
|
|
||||||
|
memset(event.data, 0, LOG_DATA_LENGTH);
|
||||||
|
for (uint8_t i = 0; i < LOG_DATA_LENGTH; i++) {
|
||||||
|
if (i >= num) break;
|
||||||
|
event.data[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logPosition < LOG_SIZE) {
|
||||||
|
eventLog[logPosition++] = event;
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeLogRecords(uint8_t num)
|
||||||
|
{
|
||||||
|
// shift records down by num because they've been sent
|
||||||
|
|
||||||
|
if (num > logPosition) return;
|
||||||
|
|
||||||
|
noInterrupts();
|
||||||
|
|
||||||
|
for (int i = 0; i < num; i++) {
|
||||||
|
eventLog[i] = eventLog[i + num];
|
||||||
|
}
|
||||||
|
logPosition -= num;
|
||||||
|
|
||||||
|
interrupts();
|
||||||
|
}
|
47
firmware/logging.h
Normal file
47
firmware/logging.h
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef LOGGING_H
|
||||||
|
#define LOGGING_H
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
#define SERIAL_LOGGING true
|
||||||
|
|
||||||
|
#define LOG_SIZE 90 // 100 blew up the stack
|
||||||
|
#define LOG_DATA_LENGTH 10
|
||||||
|
|
||||||
|
enum eventCodes
|
||||||
|
{
|
||||||
|
LOG_BOOT_UP,
|
||||||
|
LOG_INIT_COMPLETE,
|
||||||
|
LOG_WIFI_CONNECTED,
|
||||||
|
LOG_WIFI_DISCONNECTED,
|
||||||
|
LOG_COMM_LOCK_ARM,
|
||||||
|
LOG_COMM_LOCK_DISARM,
|
||||||
|
LOG_COMM_LOCK_FAIL,
|
||||||
|
LOG_COMM_CARD_FAIL,
|
||||||
|
LOG_COMM_INFO_FAIL,
|
||||||
|
LOG_LOCK_OFF,
|
||||||
|
LOG_LOCK_ARMED,
|
||||||
|
LOG_LOCK_TIMEOUT,
|
||||||
|
LOG_LOCK_ON,
|
||||||
|
LOG_LOCK_DISARM,
|
||||||
|
LOG_LOCK_ERROR,
|
||||||
|
LOG_CARD_GOOD_READ,
|
||||||
|
LOG_CARD_ACCEPTED,
|
||||||
|
LOG_CARD_DENIED,
|
||||||
|
LOG_UPDATE_FAILED,
|
||||||
|
LOG_TEST,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct __attribute__((packed)) logData {
|
||||||
|
uint32_t unixTime;
|
||||||
|
uint8_t eventCode;
|
||||||
|
char data[LOG_DATA_LENGTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct logData eventLog[LOG_SIZE];
|
||||||
|
extern uint16_t logPosition;
|
||||||
|
|
||||||
|
void logEvent(uint8_t eventCode, const char *data = nullptr, size_t num = 0);
|
||||||
|
void removeLogRecords(uint8_t num);
|
||||||
|
|
||||||
|
#endif
|
124
firmware/utils.cpp
Normal file
124
firmware/utils.cpp
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
bool greenButton() { return digitalRead(GREEN_BUTTON_PIN) == BUTTON_CLOSED; }
|
||||||
|
bool redButton() { return digitalRead(RED_BUTTON_PIN) == BUTTON_CLOSED; }
|
||||||
|
void relayOn() { digitalWrite(RELAY_PIN, RELAY_CLOSED); }
|
||||||
|
void relayOff() { digitalWrite(RELAY_PIN, RELAY_OPEN); }
|
||||||
|
void greenLEDOn() { digitalWrite(GREEN_LED_PIN, LED_PIN_ON); }
|
||||||
|
void greenLEDOff() { digitalWrite(GREEN_LED_PIN, LED_PIN_OFF); }
|
||||||
|
void redLEDOn() { digitalWrite(RED_LED_PIN, LED_PIN_ON); }
|
||||||
|
void redLEDOff() { digitalWrite(RED_LED_PIN, LED_PIN_OFF); }
|
||||||
|
|
||||||
|
int8_t charToNum(char input)
|
||||||
|
{
|
||||||
|
return String("0123456789ABCDEF").indexOf(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checksum(struct cardData *cardData)
|
||||||
|
{
|
||||||
|
// checksum is each hex data byte xord'd together.
|
||||||
|
// each char is a hex nibble, so we have to work in pairs.
|
||||||
|
|
||||||
|
int8_t even = 0, odd = 0;
|
||||||
|
|
||||||
|
for (int8_t i = 0; i < CARD_DATA_LENGTH; i++) {
|
||||||
|
int8_t num = charToNum(cardData->data[i]);
|
||||||
|
|
||||||
|
if (num == -1) return false;
|
||||||
|
if (i % 2 == 0) even ^= num;
|
||||||
|
if (i % 2 == 1) odd ^= num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t checksum_even = charToNum(cardData->checksum[0]);
|
||||||
|
int8_t checksum_odd = charToNum(cardData->checksum[1]);
|
||||||
|
|
||||||
|
if (even == checksum_even && odd == checksum_odd) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCard()
|
||||||
|
{
|
||||||
|
struct cardData *cardData = (struct cardData *) cardBuffer;
|
||||||
|
|
||||||
|
if (cardData->head == CARD_HEAD_BYTE &&
|
||||||
|
cardData->tail == CARD_TAIL_BYTE &&
|
||||||
|
checksum(cardData)) {
|
||||||
|
|
||||||
|
String cardStr = String();
|
||||||
|
String authorizedCards = String();
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < CARD_DATA_LENGTH; i++) {
|
||||||
|
cardStr += cardData->data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < EEPROM_SIZE; i++) {
|
||||||
|
char tmp = EEPROM.read(i);
|
||||||
|
authorizedCards += tmp;
|
||||||
|
if (tmp == EEPROM_END_MARKER) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Good scan from card: " + cardStr);
|
||||||
|
logEvent(LOG_CARD_GOOD_READ, cardStr.c_str(), cardStr.length());
|
||||||
|
|
||||||
|
if (authorizedCards.indexOf(cardStr) >= 0) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Card is authorized on machine.");
|
||||||
|
if (lockState == LOCK_OFF) {
|
||||||
|
lockState = LOCK_PREARM;
|
||||||
|
}
|
||||||
|
logEvent(LOG_CARD_ACCEPTED, cardStr.c_str(), cardStr.length());
|
||||||
|
} else {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Card not authorized on machine.");
|
||||||
|
LEDState = LED_ERROR;
|
||||||
|
logEvent(LOG_CARD_DENIED, cardStr.c_str(), cardStr.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON functions to prevent memory leaking see:
|
||||||
|
// https://arduinojson.org/v5/faq/i-found-a-memory-leak-in-the-library/
|
||||||
|
String serializeLockJson(uint8_t lockState)
|
||||||
|
{
|
||||||
|
// Generated with: https://arduinojson.org/assistant/
|
||||||
|
const size_t bufferSize = JSON_OBJECT_SIZE(1) + 50;
|
||||||
|
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||||
|
|
||||||
|
JsonObject& root = jsonBuffer.createObject();
|
||||||
|
root["lockState"] = (uint8_t) lockState;
|
||||||
|
String postData = String();
|
||||||
|
root.printTo(postData);
|
||||||
|
|
||||||
|
return postData;
|
||||||
|
}
|
||||||
|
|
||||||
|
String deserializeLockJson(String input)
|
||||||
|
{
|
||||||
|
// Generated with: https://arduinojson.org/assistant/
|
||||||
|
const size_t bufferSize = JSON_OBJECT_SIZE(1) + 50;
|
||||||
|
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||||
|
JsonObject& root = jsonBuffer.parseObject(input);
|
||||||
|
|
||||||
|
String action = root["action"];
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
String serializeLog()
|
||||||
|
{
|
||||||
|
size_t logLengthBytes = logPosition * sizeof(struct logData);
|
||||||
|
return "{\"log\": \"" + base64::encode((uint8_t *) eventLog, logLengthBytes, false) + "\"}";
|
||||||
|
}
|
||||||
|
|
||||||
|
void deserializeInfoJson(String input, uint8_t *processed, uint32_t *unixTime, String *version)
|
||||||
|
{
|
||||||
|
// Generated with: https://arduinojson.org/assistant/
|
||||||
|
const size_t bufferSize = JSON_OBJECT_SIZE(3) + 70;
|
||||||
|
StaticJsonBuffer<bufferSize> jsonBuffer;
|
||||||
|
JsonObject& root = jsonBuffer.parseObject(input);
|
||||||
|
|
||||||
|
*processed = root["processed"];
|
||||||
|
*unixTime = root["unixTime"];
|
||||||
|
*version = root["version"].as<String>();
|
||||||
|
}
|
38
firmware/utils.h
Normal file
38
firmware/utils.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef UTILS_H
|
||||||
|
#define UTILS_H
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
#define CARD_BUFFER_LENGTH 14
|
||||||
|
#define CARD_DATA_LENGTH 10
|
||||||
|
#define CARD_CHECK_LENGTH 2
|
||||||
|
#define CARD_HEAD_BYTE 0x2
|
||||||
|
#define CARD_TAIL_BYTE 0x3
|
||||||
|
struct __attribute__((packed)) cardData {
|
||||||
|
char head;
|
||||||
|
char data[CARD_DATA_LENGTH];
|
||||||
|
char checksum[CARD_CHECK_LENGTH];
|
||||||
|
char tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char cardBuffer[CARD_BUFFER_LENGTH];
|
||||||
|
|
||||||
|
bool greenButton();
|
||||||
|
bool redButton();
|
||||||
|
void relayOn();
|
||||||
|
void relayOff();
|
||||||
|
void greenLEDOn();
|
||||||
|
void greenLEDOff();
|
||||||
|
void redLEDOn();
|
||||||
|
void redLEDOff();
|
||||||
|
|
||||||
|
int8_t charToNum(char input);
|
||||||
|
bool checksum(struct cardData *cardData);
|
||||||
|
void checkCard();
|
||||||
|
|
||||||
|
String serializeLockJson(uint8_t lockState);
|
||||||
|
String deserializeLockJson(String input);
|
||||||
|
String serializeLog();
|
||||||
|
void deserializeInfoJson(String input, uint8_t *processed, uint32_t *unixTime, String *version);
|
||||||
|
|
||||||
|
#endif
|
40
firmware/wifi.cpp
Normal file
40
firmware/wifi.cpp
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
#include "wifi.h"
|
||||||
|
|
||||||
|
void processWifiState()
|
||||||
|
{
|
||||||
|
switch(wifiState) {
|
||||||
|
case WIFI_DISCONNECTED:
|
||||||
|
commState = COMM_INIT;
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Wifi attempting to connect...");
|
||||||
|
|
||||||
|
WiFi.begin(LOCKOUT_WIFI_SSID, LOCKOUT_WIFI_PASS);
|
||||||
|
|
||||||
|
wifiState = WIFI_CONNECTING;
|
||||||
|
break;
|
||||||
|
case WIFI_CONNECTING:
|
||||||
|
commState = COMM_INIT;
|
||||||
|
|
||||||
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Wifi is connected.");
|
||||||
|
logEvent(LOG_WIFI_CONNECTED);
|
||||||
|
|
||||||
|
if (SERIAL_LOGGING) Serial.print("[INFO] Wifi IP Address: ");
|
||||||
|
if (SERIAL_LOGGING) Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
wifiState = WIFI_CONNECTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case WIFI_CONNECTED:
|
||||||
|
if (WiFi.status() != WL_CONNECTED) {
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[INFO] Wifi disconnected.");
|
||||||
|
logEvent(LOG_WIFI_DISCONNECTED);
|
||||||
|
wifiState = WIFI_DISCONNECTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (SERIAL_LOGGING) Serial.println("[ERROR] Invalid wifi state.");
|
||||||
|
wifiState = WIFI_DISCONNECTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
19
firmware/wifi.h
Normal file
19
firmware/wifi.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef WIFI_H
|
||||||
|
#define WIFI_H
|
||||||
|
|
||||||
|
#include "firmware.h"
|
||||||
|
|
||||||
|
enum wifiStates
|
||||||
|
{
|
||||||
|
WIFI_DISCONNECTED,
|
||||||
|
WIFI_CONNECTING,
|
||||||
|
WIFI_CONNECTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
extern enum wifiStates wifiState;
|
||||||
|
extern const char *LOCKOUT_WIFI_SSID PROGMEM;
|
||||||
|
extern const char *LOCKOUT_WIFI_PASS PROGMEM;
|
||||||
|
|
||||||
|
void processWifiState();
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user