/*
    parking access is demo application born to show a state 
    machine implementation.
   
        Copyright (C) 2022 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/>.
*/


/* 
    Parking access application
    Pulsante verde per simulare la barriera IR
    https://www.adafruit.com/product/2168
    https://www.adafruit.com/product/2167

    IR Break Beam Sensor with Premium Wire Header Ends - 5mm LEDs
*/

#include <IRremote.h>
#include <LiquidCrystal.h>
#include <Servo.h>

#define PIN_RECEIVER 2   // Signal Pin of IR receiver

IRrecv receiver(PIN_RECEIVER);
Servo RCservo;

LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

/* SERVO_UP servo in posizione verticale */
#define SERVO_UP      180
/* SERVO_UP servo in posizione orizzontale */
#define SERVO_DOWN    90

/* PIN_IR_BARRIER contatto pulito relay IR RX */
const byte PIN_IR_BARRIER   = 4;

// g_state è la variabile di stato
uint8_t   g_state       = 0;
uint32_t  g_saveMillis  = 0;
uint8_t   g_servoPos    = SERVO_DOWN;

/* 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

void setup() {
    Serial.begin(115200);
    pinMode(PIN_IR_BARRIER, INPUT_PULLUP);
    
    receiver.enableIRIn(); // Start the receiver

    lcd.begin(16, 2);

    lcd.print("Press play");
    
    RCservo.attach(5);
    RCservo.write(g_servoPos);
}


void loop() {

    uint8_t command = 0;

    if (receiver.decode()) {
        command = receiver.decodedIRData.command;
        receiver.resume();  // Receive the next value
    }

    switch (g_state) {
        
        case S_START:
            if (command == IRCMD_PLAY) {
                /* CHANGE STATE */
                g_state = S_INOPENING;     
            }      
            break;

        case S_INOPENING:
            
            if (millis() - g_saveMillis > 35) {
                g_saveMillis = millis();
                
                if (g_servoPos <= SERVO_UP) {
                    g_servoPos++;
                    RCservo.write(g_servoPos);
                } 
                if (g_servoPos == SERVO_UP) {
                    /* CHANGE STATE */
                    g_state = S_ISUP;
                    g_saveMillis = millis();
                }
                
            }
            break;

        case S_ISUP:
            if (millis() - g_saveMillis > 2000) {
                /* CHANGE STATE */
                g_state = S_INCLOSING;
            }
            /* CHECK IR BARRIER */
            if (digitalRead(PIN_IR_BARRIER) == LOW) {
                /* RESTART TIMER */
                g_saveMillis = millis();
            }
            break;

        case S_INCLOSING:
            if (millis() - g_saveMillis > 50) {
                g_saveMillis = millis();
                  
                if (g_servoPos >= SERVO_DOWN) {
                    g_servoPos--;
                    RCservo.write(g_servoPos);
                } 
                if (g_servoPos == SERVO_DOWN) {
                    /* CHANGE STATE */
                    g_state = S_START;
                }
            }
            /* CHECK IR BARRIER */
            if (digitalRead(PIN_IR_BARRIER) == LOW) {
                /* CHANGE STATE */
                g_state = S_INOPENING;
            }
            break;
    } // end switch
} // end loop()