/*
parking-access-s01 is demo application of parking access.
https://programmersqtcpp.blogspot.com/2022/03/applicazione-accesso-parcheggio-entry.html
Copyright (C) 2023 Maurilio Pizzurro
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Pulsante verde per simulare la barriera IR
Pulsante giallo per simulare il contatto chiave
*/
#include <LiquidCrystal.h>
#include <Servo.h>
#include "genFSM.h" // (1) include genFSM
Servo bar0;
Servo bar1;
GenericFSM bar0State; // (2) Crea istanza del nuovo gestore di stati
GenericFSM bar1State; // (2) Crea istanza del nuovo gestore di stati
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
/* SERVO_UP servo in posizione verticale */
#define SERVO_UP 180
/* SERVO_DOWN servo in posizione orizzontale */
#define SERVO_DOWN 90
/* S_XXX stati della macchina a stati g_state */
#define S_START 0
#define S_INOPENING 1
#define S_ISUP 2
#define S_INCLOSING 3
#define IRCMD_PLAY 168
uint8_t g_servoPos0 = SERVO_DOWN;
uint8_t g_servoPos1 = SERVO_DOWN;
//uint32_t g_saveMillis = 0;
/* PIN_IR_BARRIER contatto pulito relay IR RX */
const byte PIN_IR_BARRIER0 = 4;
const byte PIN_IR_BARRIER1 = A4;
/* PIN_KEY contatto pulito comando chiave */
const byte PIN_KEY0 = 6;
const byte PIN_KEY1 = A5;
void setup()
{
Serial.begin(115200);
pinMode(PIN_IR_BARRIER0, INPUT_PULLUP);
pinMode(PIN_IR_BARRIER1, INPUT_PULLUP);
pinMode(PIN_KEY0, INPUT_PULLUP);
pinMode(PIN_KEY1, INPUT_PULLUP);
pinMode(LED_BUILTIN, OUTPUT);
pinMode(A0, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A1, OUTPUT);
lcd.begin(16, 2);
lcd.setCursor(0, 1);
lcd.print((char)223);
lcd.setCursor(6,1);
lcd.print("Tms: ");
Serial.print("Press play or\nyellow button\n");
bar0.attach(5);
bar0.write(g_servoPos0);
lcdPrintPos(g_servoPos0);
bar1.attach(A2);
bar1.write(g_servoPos1);
lcdPrintTimeout(0);
bar0State.setState(S_START); // (3) inizializzazione opzionale
}
/* lcdPrintPos() visualizza su lcd la posizione angolare del servo*/
void lcdPrintPos(uint8_t pos) {
char posBuff[4];
posBuff[ 4 - 1 ] = '\0';
sprintf(posBuff, "%#3u", pos);
lcd.setCursor(1, 1);
lcd.print(posBuff);
}
/* lcdPrintState() visualizza su lcd lo stato corrente */
void lcdPrintState(uint8_t n) {
char *s[] = {"S_START "
, "S_INOPENING"
, "S_ISUP "
, "S_INCLOSING"};
lcd.setCursor(0, 0);
lcd.print("RUN ");
lcd.setCursor(5, 0);
lcd.print(s[n]);
}
/* flashingLight() accendo/spegne il lampeggiante */
void flashingLight(bool tf) {
#define FL_TIMING 200
static uint32_t timer = 0;
static uint8_t timing = 0;
if (!tf) {
digitalWrite(LED_BUILTIN, LOW);
digitalWrite(A0, LOW);
timer = 0;
timing = 0;
return;
}
if (millis() - timer > timing) {
bool yelIsOn = !digitalRead(A0);
timer = millis();
timing = FL_TIMING;
digitalWrite(LED_BUILTIN, !yelIsOn);
digitalWrite(A0, yelIsOn);
}
}
/* flashingLight() accendo/spegne il lampeggiante */
void flashingLight1(bool tf) {
#define FL_TIMING 200
static uint32_t timer = 0;
static uint8_t timing = 0;
if (!tf) {
digitalWrite(A3, LOW);
digitalWrite(A1, LOW);
timer = 0;
timing = 0;
return;
}
if (millis() - timer > timing) {
bool yelIsOn = !digitalRead(A1);
timer = millis();
timing = FL_TIMING;
digitalWrite(A3, !yelIsOn);
digitalWrite(A1, yelIsOn);
}
}
/* lcdPrintTimeout() visualizza su lcd il timeout residuo */
void lcdPrintTimeout(uint16_t t) {
char timeBuff[5];
timeBuff[ 5 - 1 ] = '\0';
sprintf(timeBuff, "%#4u", t);
lcd.setCursor(11, 1);
lcd.print(timeBuff);
}
void loop() {
flashingLight(bar0State.getState()); // (4)
flashingLight1(bar1State.getState()); // (4)
uint8_t command0 = 0;
uint8_t command1 = 0;
if (digitalRead(PIN_KEY0) == LOW) {
command0 = IRCMD_PLAY;
} else if (digitalRead(PIN_KEY1) == LOW) {
command1 = IRCMD_PLAY;
}
bar0State.run(); // (5)
bar1State.run(); // (5)
switch (bar0State.getState()) { // (6)
case S_START:
/* ENTRY STATE */
if (bar0State.onEnter()) { // (7)
lcdPrintState(bar0State.getState());
Serial.println(F("Enter to S_START"));
}
/* RUN STATE */
if (command0 == IRCMD_PLAY) {
//g_state = S_INOPENING;
bar0State.setState(S_INOPENING); // (8)
}
/* EXIT STATE */
if (bar0State.onExit()) { // (9)
Serial.println(F("Exit from S_START"));
}
break;
case S_INOPENING:
/* ENTRY STATE */
if (bar0State.onEnter()) { // (10)
lcdPrintState(bar0State.getState());
Serial.println(F("Enter to S_INOPENING"));
}
/* RUN STATE */
if (bar0State.isElapsed(25)) { // (11)
//g_saveMillis = millis();(
bar0State.setTimer(); // (12)
if (g_servoPos0 <= SERVO_UP) {
g_servoPos0++;
bar0.write(g_servoPos0);
lcdPrintPos(g_servoPos0);
}
if (g_servoPos0 == SERVO_UP) {
/* CHANGE STATE */
bar0State.setState(S_ISUP); // (13)
//g_saveMillis = millis();
}
}
/* EXIT STATE */
if (bar0State.onExit()) {
Serial.println(F("Exit from S_INOPENING"));
}
break;
case S_ISUP:
/* ENTRY STATE */
if (bar0State.onEnter()) {
lcdPrintState(bar0State.getState());
Serial.println(F("Enter to S_ISUP"));
}
/* RUN STATE */
if (bar0State.isElapsed(2000)) {
/* CHANGE STATE */
bar0State.setState(S_INCLOSING);
lcdPrintTimeout(0);
} else {
uint32_t dt = millis() - bar0State.getTimer();
lcdPrintTimeout(2000 - dt);
}
/* CHECK IR BARRIER */
if (digitalRead(PIN_IR_BARRIER0) == LOW) {
/* RESTART TIMER */
//g_saveMillis = millis();
bar0State.setTimer();
}
/* EXIT STATE */
if (bar0State.onExit()) {
Serial.println(F("Exit from S_ISUP"));
}
break;
case S_INCLOSING:
/* ENTRY STATE */
if (bar0State.onEnter()) {
lcdPrintState(bar0State.getState());
Serial.println(F("Enter to S_INCLOSING"));
}
/* RUN STATE */
if (bar0State.isElapsed(35)) {
//g_saveMillis = millis();
bar0State.setTimer();
if (g_servoPos0 >= SERVO_DOWN) {
g_servoPos0--;
bar0.write(g_servoPos0);
lcdPrintPos(g_servoPos0);
}
if (g_servoPos0 == SERVO_DOWN) {
/* CHANGE STATE */
bar0State.setState(S_START);
}
}
/* CHECK IR BARRIER */
if (digitalRead(PIN_IR_BARRIER0) == LOW) {
/* CHANGE STATE */
bar0State.setState(S_INOPENING);
}
/* EXIT STATE */
if (bar0State.onExit()) {
Serial.println(F("Exit from S_INCLOSING"));
}
break;
} // end switch
// seconda barra
switch (bar1State.getState()) { // (6)
case S_START:
/* ENTRY STATE */
if (bar1State.onEnter()) { // (7)
Serial.println(F("\tbar1, Enter to S_START"));
}
/* RUN STATE */
if (command1 == IRCMD_PLAY) {
//g_state = S_INOPENING;
bar1State.setState(S_INOPENING); // (8)
}
/* EXIT STATE */
if (bar1State.onExit()) { // (9)
Serial.println(F("\tbar1, Exit from S_START"));
}
break;
case S_INOPENING:
/* ENTRY STATE */
if (bar1State.onEnter()) { // (10)
Serial.println(F("\tbar1, Enter to S_INOPENING"));
}
/* RUN STATE */
if (bar1State.isElapsed(25)) { // (11)
//g_saveMillis = millis();(
bar1State.setTimer(); // (12)
if (g_servoPos1 <= SERVO_UP) {
g_servoPos1++;
bar1.write(g_servoPos1);
}
if (g_servoPos1 == SERVO_UP) {
/* CHANGE STATE */
bar1State.setState(S_ISUP); // (13)
//g_saveMillis = millis();
}
}
/* EXIT STATE */
if (bar1State.onExit()) {
Serial.println(F("\tbar1, Exit from S_INOPENING"));
}
break;
case S_ISUP:
/* ENTRY STATE */
if (bar1State.onEnter()) {
Serial.println(F("\tbar1, Enter to S_ISUP"));
}
/* RUN STATE */
if (bar1State.isElapsed(2000)) {
/* CHANGE STATE */
bar1State.setState(S_INCLOSING);
}
/* CHECK IR BARRIER */
if (digitalRead(PIN_IR_BARRIER1) == LOW) {
/* RESTART TIMER */
//g_saveMillis = millis();
bar1State.setTimer();
}
/* EXIT STATE */
if (bar1State.onExit()) {
Serial.println(F("\tbar1, Exit from S_ISUP"));
}
break;
case S_INCLOSING:
/* ENTRY STATE */
if (bar1State.onEnter()) {
Serial.println(F("\tbar1, Enter to S_INCLOSING"));
}
/* RUN STATE */
if (bar1State.isElapsed(35)) {
//g_saveMillis = millis();
bar1State.setTimer();
if (g_servoPos1 >= SERVO_DOWN) {
g_servoPos1--;
bar1.write(g_servoPos1);
}
if (g_servoPos1 == SERVO_DOWN) {
/* CHANGE STATE */
bar1State.setState(S_START);
}
}
/* CHECK IR BARRIER */
if (digitalRead(PIN_IR_BARRIER1) == LOW) {
/* CHANGE STATE */
bar1State.setState(S_INOPENING);
}
/* EXIT STATE */
if (bar1State.onExit()) {
Serial.println(F("\tbar1, Exit from S_INCLOSING"));
}
break;
} // end switch
} // end loop()