MQ7-esp/esp8266-RM370-interrupt/esp8266-RM370-interrupt.ino

257 lines
7.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//#define LOG(fmt, ...)
#define LOG(fmt, ...) (Serial.printf("%09llu: " fmt "\n", GetTimestamp(), ##__VA_ARGS__)); Serial.flush();
//#define DEBUGLOG(fmt, ...)
#define DEBUGLOG(fmt, ...) (Serial.printf("%09llu: [DEBUG] " fmt "\n", GetTimestamp(), ##__VA_ARGS__));
#define GLOBAL_VERBOSE 1//activate if the 'GREEN' status should be globally available
#define debounceDelay 1000 //LED shining duration
#define globalDelay 20000
#define alarmDelay 50
#define adcDelay 600000UL //10 minutes
#define warningDelay 333
const int MAX_PEERS = 20; //Limited due espNOW
//static const int WIFIESPNOW_KEYLEN = 16; //Limited due espNOW
const uint8_t key[16] = { 0 };
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <Hash.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
#include <WifiEspNowBroadcast.h> //https://github.com/yoursunny/WifiEspNow
#include <Ticker.h> //Ticker Library
//version 1.1 - added originMAC
typedef struct {
char PREAMBLE1 = 'R';
char PREAMBLE2 = 'M';
uint8_t messageID[20];
char code = 'g'; // [g, y, r, X]
bool batteryWarning = false; //ToDo not implemented yet
uint8_t originMAC[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
} rm370;
rm370 receiveBuffer[MAX_PEERS];
rm370 transmitBuffer;
rm370 ownState;
//Remember VIL == 0.25×VIO ==> ~0,8275V
//Lowest voltage on LED 2,5V ==> 1,6V with level shifter
const uint8_t GREEN_Pin = D5; //CAUTION Vext is NOT 3.3V !!!
const uint8_t YELLOW_Pin = D6; //CAUTION Vext is NOT 3.3V !!!
const uint8_t RED_Pin = D7; //CAUTION Vext is NOT 3.3V !!!
const uint8_t BUZZER_Pin = D2; //CAUTION Vext is NOT 3.3V !!!
const uint8_t BAT_Pin = A0; //CAUTION Vext is NOT 1.1V !!!
Ticker alarmGenerator;
Ticker warningGenerator;
volatile bool alarmTrigger = false; //global
volatile bool warningTrigger = false; //global
volatile bool debounceTrigger = false;
//real physics workaround
volatile unsigned long globalStart = 0; //real physics workaround
volatile unsigned long debounceStart = 0; //real physics workaround
volatile unsigned long nowMillis = millis(); //real physics workaround
volatile unsigned long lastADCRead = 0;
volatile byte rxCounter = 0; //marker for the receive interrupt callback
volatile byte rxHandlePointer = 0; //marker for internal processing
int64_t GetTimestamp() {
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000LL + (tv.tv_usec / 1000LL));
}
void buzzerTone() {
//just trigger if externel trigger received
if (ownState.code == 'g') {
digitalWrite(BUZZER_Pin, !(digitalRead(BUZZER_Pin)));
}
}
void batteryCheck() {
int sensorValue = analogRead(BAT_Pin);
DEBUGLOG("AnalogRead: %i", sensorValue);
lastADCRead = millis();
int voltage = map(sensorValue, 0, 1023, 0, 5000);
DEBUGLOG("VoltageMap: %i mV", voltage);
if (voltage < 3000) {
ownState.batteryWarning = true;
}
else {
ownState.batteryWarning = false;
}
}
void buzzerTest() {
LOG("Test alarm buzzer");
debounceTrigger = true;
alarmTrigger = true;
for (int i = 0; i < (3000 / alarmDelay); i++) {
buzzerTone();
delay(alarmDelay);
}
alarmTrigger = false;
LOG("Test warning buzzer");
warningTrigger = true;
for (int i = 0; i < (3000 / warningDelay); i++) {
buzzerTone();
delay(warningDelay);
}
warningTrigger = false;
//Failsafe
digitalWrite(BUZZER_Pin, HIGH);
debounceTrigger = false;
}
void globalStatus() {
if (globalStart != 0) {
//reset global
if ( (nowMillis - globalStart) > globalDelay ) {
if (alarmGenerator.active()) {
alarmGenerator.detach();
alarmTrigger = false;
}
if (warningGenerator.active()) {
warningGenerator.detach();
warningTrigger = false;
}
globalStart = 0;
//Failsafe
digitalWrite(BUZZER_Pin, HIGH);
LOG("Global ended");
}
if (alarmTrigger && !alarmGenerator.active()) {
LOG("Global started");
alarmGenerator.attach(float(alarmDelay / 1000.0), buzzerTone);
}
//attach ticker
if (warningTrigger && !warningGenerator.active()) {
LOG("Global started");
warningGenerator.attach(float(warningDelay / 1000.0), buzzerTone);
}
}
}
void setup() {
pinMode(RED_Pin, INPUT_PULLUP);
pinMode(YELLOW_Pin, INPUT_PULLUP);
pinMode(GREEN_Pin, INPUT_PULLUP);
pinMode(BUZZER_Pin, OUTPUT);
digitalWrite(BUZZER_Pin, HIGH);
attachInterrupt(digitalPinToInterrupt(RED_Pin), IntREDCallback, FALLING);
attachInterrupt(digitalPinToInterrupt(YELLOW_Pin), IntYELLOWCallback, FALLING);
attachInterrupt(digitalPinToInterrupt(GREEN_Pin), IntGREENCallback, FALLING);
Serial.begin(115200);
Serial.flush();
delay(1000);
LOG("\n\nInterrupt D7,D6,D5 with Serial.print");
#if defined(GLOBAL_VERBOSE)
LOG("\nGlobal verbose ACTIVE");
#endif
if (!initCommunication()) {
ESP.restart();
}
batteryCheck();
buzzerTest();
LOG("Setup completed.\n");
}
void loop() {
//loop things
nowMillis = millis();
WifiEspNowBroadcast.loop();
globalStatus();
if ((nowMillis - lastADCRead) > adcDelay) {
batteryCheck();
}
//reset debounce, as the LEDs shine a period of time
if (debounceTrigger && ((nowMillis - debounceStart) > debounceDelay)) {
debounceTrigger = false;
if (ownState.code == 'r') {
DEBUGLOG("RED LED");
}
if (ownState.code == 'y') {
DEBUGLOG("YELLOW LED");
}
//Todo check for code 'g'
if (!(ownState.code == 'r' || ownState.code == 'y')) {
DEBUGLOG("GREEN LED");
}
//send own status
#if defined(GLOBAL_VERBOSE)
if (ownState.code == 'r' || ownState.code == 'y' || ownState.code == 'g') {
#else
if (ownState.code == 'r' || ownState.code == 'y') {
#endif
//generate unique identifier
char messageIDString[65];
itoa(millis(), messageIDString, 10);
sha1(messageIDString, ownState.messageID);
transmitBuffer = ownState;
sendMessage();
}
}
//process remaining rxBuffer
while (rxHandlePointer != rxCounter)
{
checkMessage();
//shift ring buffer working pointer
if (rxHandlePointer + 1 < MAX_PEERS) {
rxHandlePointer++;
}
else {
rxHandlePointer = 0;
}
//forward received messages
#if defined(GLOBAL_VERBOSE)
if (transmitBuffer.code == 'r' || transmitBuffer.code == 'y' || transmitBuffer.code == 'g') {
#else
if (transmitBuffer.code == 'r' || transmitBuffer.code == 'y') {
#endif
sendMessage();
}
}
}
ICACHE_RAM_ATTR void IntREDCallback() {
if (!debounceTrigger) {
alarmTrigger = true;
warningTrigger = false;
ownState.code = 'r';
//real physics workaround
debounceTrigger = true;
debounceStart = millis();
}
}
ICACHE_RAM_ATTR void IntYELLOWCallback() {
if (!debounceTrigger) {
if (!alarmTrigger) {
warningTrigger = true;
}
ownState.code = 'y';
//real physics workaround
debounceTrigger = true;
debounceStart = millis();
}
}
ICACHE_RAM_ATTR void IntGREENCallback() {
if (!debounceTrigger) {
ownState.code = 'g';
//real physics workaround
debounceTrigger = true;
debounceStart = millis();
}
}