This commit is contained in:
Lexzach 2022-04-19 09:49:10 -04:00
parent b766658d01
commit 7463c83cae
9 changed files with 484 additions and 0 deletions

5
facp/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

7
facp/.vscode/extensions.json vendored Normal file
View File

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

39
facp/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

46
facp/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

17
facp/platformio.ini Normal file
View File

@ -0,0 +1,17 @@
; 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
[env:esp32doit-devkit-v1]
platform = espressif32
board = esp32doit-devkit-v1
framework = arduino
monitor_speed = 115200
lib_deps =
marcoschwartz/LiquidCrystal_I2C@^1.1.4

7
facp/src/eeprom.txt Normal file
View File

@ -0,0 +1,7 @@
Address allocation:
1-6 | "Lexzach" - verify that eeprom is the FACP config eeprom
7 | 0-3 - coding selection
8 | 0-1 - is a key required
9 | 0-1 - is there verification
10 | 1-255 - how long to do verification (value * 0.1 = actual verification time in seconds)
11-71 | 65-90, 97-122, 45-57, 32 - System name

BIN
facp/src/eol.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

352
facp/src/main.cpp Normal file
View File

@ -0,0 +1,352 @@
#include <Arduino.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>
//RUNTIME VARIABLES
bool fullAlarm = false; //bool to control if this is a full alarm that requres a panel reset to clear
bool keyInserted = false; //if the control panel has a key inserted
bool horn = false; //bool to control if the horns are active
bool strobe = false; //bool to control if the strobes are active
bool trouble = false; //bool to control if the panel is in trouble
bool troubleAck = false; //bool to control if the trouble is acknowledged
int verification = 0; //number to keep track of ms for verification
int drill = 0; //number to keep track of ms for drill
int codeWheelTimer = 0; //code wheel timing variable
int troubleLedTimer = 0; //number to keep track of ms for trouble light
int alarmLedTimer = 0; //alarm led timer
int troubleType = 0; //trouble type 0 - general, 1 - eol resistor
int lcdUpdateTimer = 0; //update delay
int currentScreen = 0; //update display if previous screen is not the same
//CONFIG VARIABLES
bool keyRequired = true; //determine if key switch is required to operate buttons
bool isVerification = true; //is verification turned on
int codeWheel = 0; //which alarm pattern to use, code-3 default
int verificationTime = 2500;
LiquidCrystal_I2C lcd(0x27,16,2);
void setup() {
Serial.begin(115200); //begin serial
Serial.println("Lexzach's Low-Cost FACP v1");
Serial.println("Booting...");
pinMode(13, OUTPUT); //horn
pinMode(12, OUTPUT); //strobe
pinMode(14, OUTPUT); //smoke relay
pinMode(27, OUTPUT); //ready LED
pinMode(26, OUTPUT); //silence LED
pinMode(25, OUTPUT); //alarm LED
pinMode(33, INPUT); //key switch
pinMode(32, INPUT); //reset switch
pinMode(35, INPUT); //silence switch
pinMode(34, INPUT); //drill switch
pinMode(15, INPUT); //pull station
pinMode(4, OUTPUT); //buzzer
pinMode(22, OUTPUT); //scl
pinMode(21, OUTPUT); //sda
Serial.println("Initializing LCD...");
lcd.init(); //initialize LCD
lcd.clear();
lcd.backlight();
lcd.setCursor(3,0);
lcd.print("Booting...");
Serial.println("Configured all pins");
EEPROM.begin(1025); //allocate memory address 0-1024 for EEPROM
Serial.println("Configured EEPROM for addresses 0-1024");
EEPROM.write(0,255); //TESTING PURPOSES
EEPROM.commit(); //TESTING PURPOSES
Serial.println("Verifying EEPROM configuration integrity...");
if (EEPROM.read(0) != 76 or EEPROM.read(6) != 104 or EEPROM.read(7) > 3 or EEPROM.read(8) > 1){ //EEPROM verification, check essential-to-run components, listing all conditions that cannot exist in a correct EEPROM
Serial.println("EEPROM verification failed. Re-writing EEPROM");
for (int i=0; i<=1024; i++){ //write all 255's from 0-1024 address
EEPROM.write(i,255);
}
EEPROM.write(0,76);EEPROM.write(1,101);EEPROM.write(2,120);EEPROM.write(3,122);EEPROM.write(4,97);EEPROM.write(5,99);EEPROM.write(6,104); //write Lexzach to addresses 0-6
EEPROM.write(7,0); //code-3 default
EEPROM.write(8,0); //key not required by default
EEPROM.write(9,1); //verification is turned on by default
EEPROM.write(10,25); //default verification time of 2.5 seconds
EEPROM.commit();
} else {
Serial.println("EEPROM verification finished");
}
Serial.println("Current EEPROM:");
for (int i=0; i<=1024; i++){
Serial.print(EEPROM.read(i));
Serial.print(" ");
}
Serial.println();
//CONFIG LOADING ROUTINE
Serial.println("Loading config from EEPROM...");
codeWheel = EEPROM.read(7); //codeWheel setting address
if (EEPROM.read(8) == 1){
keyRequired = true;
} else {
keyRequired = false;
}
if (EEPROM.read(9) == 1){
isVerification = true;
} else {
isVerification = false;
}
verificationTime = EEPROM.read(10)*100;
Serial.println("Config loaded");
digitalWrite(27, HIGH); //power on ready LED on startup
}
void tone() {
ledcSetup(0, 5000, 8); // setup beeper
ledcAttachPin(4, 0); // attach beeper
ledcWriteTone(0, 1500); // play tone
}
void noTone() {
ledcSetup(0, 5000, 8); // setup beeper
ledcAttachPin(4, 0); // attach beeper
ledcWriteTone(0, 0); // stop tone
}
void checkKey(){
if (digitalRead(33) == HIGH){
keyInserted = true;
} else {
keyInserted = false;
}
}
void checkDevices(){
if (analogRead(15) <= 500 and horn != true){
verification++;
} else {
verification = 0;
}
if (verification == verificationTime or isVerification == false){ //activate the horns and strobes after verification
horn = true;
strobe = true;
fullAlarm = true;
tone();
} else if (analogRead(15) == 4095) {
trouble = true;
troubleType=1;
}
}
void troubleCheck(){
if (trouble == true){
if (troubleLedTimer == 0){
digitalWrite(27, LOW);
if (troubleAck == false and fullAlarm == false){
noTone();
}
} else if (troubleLedTimer == 750){
digitalWrite(27, HIGH);
if (troubleAck == false and fullAlarm == false){ //sound the buzzer if the trouble is not acked
tone();
}
} else if (troubleLedTimer == 1500){
troubleLedTimer = -1;
}
troubleLedTimer++;
} else {
digitalWrite(27, HIGH);
if (troubleLedTimer != 0){
noTone();
}
troubleLedTimer=0;
}
}
void checkButtons(){
if (digitalRead(32) == HIGH){ //RESET BUTTON
tone();
digitalWrite(27, HIGH); //ready LED
digitalWrite(26, HIGH); //silence LED
digitalWrite(25, HIGH); //alarm LED
delay(1500);
ESP.restart();
}
if (digitalRead(35) == HIGH){ //SILENCE BUTTON
if (horn == true){ //if horns are not silenced, silence the horns
digitalWrite(26, HIGH);
horn = false;
} else if (horn == false and strobe == true){ //if the horns are silenced and the button is pressed again, silence the buzzer
noTone();
} else if (horn == false and strobe == false and trouble == true){
troubleAck = true;
noTone();
}
}
if (digitalRead(34) == HIGH and horn != true){ //DRILL BUTTON
if (drill == 2000){
horn = true;
strobe = true;
} else {
drill++;
}
} else {
drill = 0;
}
}
void alarm(){
if (horn == true){
if (codeWheel == 0){
if (codeWheelTimer == 0){ //temporal code 3
digitalWrite(13, LOW);
} else if (codeWheelTimer == 500) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 1000) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 1500) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 2000) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 2500) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 4000) {
codeWheelTimer = -1;
}
} else if (codeWheel == 1) {
if (codeWheelTimer == 0){ //marchtime
digitalWrite(13, LOW);
} else if (codeWheelTimer == 250){
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 500){
codeWheelTimer = -1;
}
} else if (codeWheel == 2) { //4-4
if (codeWheelTimer == 0) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 300) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 600) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 900) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 1200) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 1500) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 1800) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 2100) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 2850) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 3150) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 3450) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 3750) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 4050) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 4350) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 4650) {
digitalWrite(13, LOW);
} else if (codeWheelTimer == 4950) {
digitalWrite(13, HIGH);
} else if (codeWheelTimer == 14950) {
codeWheelTimer = -1;
}
} else if (codeWheel == 3) { //continuous
digitalWrite(13, LOW);
}
codeWheelTimer++;
alarmLedTimer++;
if (alarmLedTimer >= 750){
if (digitalRead(25) == true){
digitalWrite(25, LOW);
alarmLedTimer = 0;
} else {
digitalWrite(25, HIGH);
alarmLedTimer = 0;
}
}
} else {
digitalWrite(13, HIGH);
codeWheelTimer = 0;
}
}
void lcdUpdate(){
if (trouble==false and fullAlarm==false and horn==false and strobe==false){
lcd.clear();
lcd.setCursor(2,0);
lcd.print("System Normal");
currentScreen = 0;
} else if (trouble==true){
if (troubleType == 0 and currentScreen != 1){
lcd.clear();
lcd.setCursor(1,0);
lcd.print("*** Trouble ***");
lcd.setCursor(2,1);
lcd.print("Unknown Trouble");
currentScreen = 1;
} else if (troubleType == 1 and currentScreen != 2){
lcd.clear();
lcd.setCursor(1,0);
lcd.print("*** Trouble ***");
lcd.setCursor(2,1);
lcd.print("Ground Fault");
currentScreen = 2;
} else if (fullAlarm == true and currentScreen != 3){
lcd.clear();
lcd.setCursor(0,0);
lcd.print("*** FIRE ALARM ***");
lcd.setCursor(2,1);
lcd.print("zone info here");
currentScreen = 3;
}
}
}
void loop() {
delay(1);
checkKey(); //check to see if the key is inserted
checkDevices(); //check pull stations and smoke detectors
if (keyInserted == true or keyRequired == false){
checkButtons(); //check if certain buttons are pressed
}
troubleCheck(); //trouble check
alarm(); //alarm codewheel
if (lcdUpdateTimer == 1000){
lcdUpdate();
lcdUpdateTimer=0;
} else {
lcdUpdateTimer++;
}
Serial.println(digitalRead(35));
}

11
facp/test/README Normal file
View File

@ -0,0 +1,11 @@
This directory is intended for PlatformIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html