#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_PCD8544.h"

Adafruit_PCD8544 display = Adafruit_PCD8544(6, 7, 8, 9, 10); //SCLK, DIN, DC, CE, RST

unsigned int gasLevel;                        //Var for current gas level
unsigned int gasLimit = 150;                  //Var for setting the gas warning
const unsigned int gasInterval = 50;          //Var for setting the interval between warning and alarm
unsigned int gasAlarm = gasLimit+gasInterval; //Var for calculating the alarm value
const unsigned int preHeatSecs = 30;          //Preheat time in seconds
bool suppressAlarmState = false;              //Alarm suppression status
const unsigned int gasInputPin = A0;          //Input pin for gas sensor
const unsigned int knapSetLimitPin = 11;      //Input pin for limit set button
const unsigned int knapResetAlarmPin = 12;    //Input pin for alarm reset button
const unsigned int buzzerPin = 13;            //Output pin for piezo buzzer
const unsigned int R = 5;                     //Output pin for alarm LED
const unsigned int Y = 4;                     //Output pin for warning LED
const unsigned int G = 3;                     //Output pin for OK LED

static const unsigned char PROGMEM warning_image[] =
{
  0b00000001, 0b10000000, //        ##       
  0b00000011, 0b11000000, //       ####      
  0b00000010, 0b01000000, //       #  #      
  0b00000110, 0b01100000, //      ##  ##     
  0b00000100, 0b00100000, //      #    #     
  0b00001101, 0b10110000, //     ## ## ##    
  0b00001001, 0b10010000, //     #  ##  #    
  0b00011001, 0b10011000, //    ##  ##  ##   
  0b00010001, 0b10001000, //    #   ##   #   
  0b00110001, 0b10001100, //   ##   ##   ##  
  0b00100001, 0b10000100, //   #    ##    #  
  0b01100000, 0b00000110, //  ##          ## 
  0b01000001, 0b10000010, //  #     ##     # 
  0b11000001, 0b10000011, // ##     ##     ##
  0b10000000, 0b00000001, // #              #
  0b11111111, 0b11111111, // ################
};

void setup() {
  Serial.begin(9600);                         //Initialize serial port - 9600 bps
  pinMode(G, OUTPUT);                         //Set pin for green LED as output
  pinMode(Y, OUTPUT);                         //Set pin for yellow LED as output
  pinMode(R, OUTPUT);                         //Set pin for red LED as output
  pinMode(buzzerPin, OUTPUT);                 //Set pin for the buzzer as output
  pinMode(knapSetLimitPin,INPUT);             //Set pin for the limit button as input
  pinMode(knapResetAlarmPin,INPUT);           //Set pin for the suppression button as input
  for (int i = 0; i < 2; i++) beep(50,75);    //Beep twice to inform of power on
  initDisplay();                              //Initialize and set up the display
  preHeat(preHeatSecs);                       //Start preheating the sensor
}

void loop() {
  gasLevel = analogRead(gasInputPin);
  printSerialLine();
  if (gasLevel < gasLimit) { //Lav
    digitalWrite(G, HIGH);
    digitalWrite(Y, LOW);
    digitalWrite(R, LOW);
    suppressAlarmState = false;
  } else if (gasLevel >= gasAlarm) { //Høj
    digitalWrite(G, LOW);
    digitalWrite(Y, LOW);
    digitalWrite(R, HIGH);
    if (!suppressAlarmState) beep(500,0);
    if (digitalRead(knapResetAlarmPin)) suppressAlarmState = true;
  } else { //Middel
    digitalWrite(G, LOW);
    digitalWrite(Y, HIGH);
    digitalWrite(R, LOW);
    suppressAlarmState = false;
  }
  displayGas();
  for (int j = 0; j < 7; j++) {
    bool l = false;
    while (digitalRead(knapSetLimitPin)) {
      if (l) {
        digitalWrite(G, HIGH);
        digitalWrite(Y, HIGH);
        digitalWrite(R, HIGH);
        l = false;
      } else {
        digitalWrite(G, LOW);
        digitalWrite(Y, LOW);
        digitalWrite(R, LOW);
        l = true;
      }
      gasLimit = gasLevel+gasInterval;
      gasAlarm = gasLimit+gasInterval;
      displaySetGas();
      delay(100);
    }
    delay(50);
  }
}

void beep(unsigned int delayms1,unsigned int delayms2) {
  analogWrite(buzzerPin, 10);
  delay(delayms1);
  analogWrite(buzzerPin, 0);
  delay(delayms2);
}

void printSerialLine() {
  Serial.print("Current gas level: ");
  Serial.print(gasLevel);
  Serial.print(". Soft limit is set to ");
  Serial.print(gasLimit);
  Serial.print(". Hard limit is set to ");
  Serial.print(gasAlarm);
  Serial.print(". Interval is set to ");
  Serial.print(gasInterval);
  Serial.println(".");
}

void initDisplay() {
  display.begin();
  display.setContrast(55);
  display.clearDisplay();
}

void preHeat(unsigned int seconds) {
  for (int k = seconds; k > 0; k--) {
      display.clearDisplay();
      if (k%2) {
        display.drawBitmap(3, 25, warning_image, 16, 16, 1);
        display.drawBitmap(65, 25, warning_image, 16, 16, 1);
      }
      display.drawRect(0,0,84,22,BLACK);
      display.setCursor(0, 3);
      display.setTextSize(1);
      display.println("  Preheating");
      display.println("    sensor");
      display.println();
      display.setTextSize(2);
      if (k < 10) display.setCursor(38, 26);
      else display.setCursor(32, 26);
      display.print(k, DEC);
      display.display();
    delay(1000);
  }
  delay(500);
  display.clearDisplay();
  display.display();
  beep(200,500);
  
}

void displayGas() {
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0, 0);
  display.println("  Gas level:");
  display.setTextSize(2);
  if (gasLevel > 99) display.print("  ");
  else display.print("   ");
  if (gasLevel >= gasAlarm) {
    display.setTextColor(WHITE,BLACK);
    display.drawBitmap(5, 7, warning_image, 16, 16, 1);
    display.drawBitmap(63, 7, warning_image, 16, 16, 1);
  }
  display.println(gasLevel, DEC);
  display.setTextColor(BLACK);
  display.setTextSize(1);
  display.print("Limit    Alarm");
  display.setTextSize(2);
  display.print(gasLimit, DEC);
  display.print(" ");
  display.println(gasAlarm, DEC);
  display.display();
}

void displaySetGas() {
  display.clearDisplay();
  display.setTextSize(1);
  display.println();
  display.println(" Limit set to:");
  display.setTextSize(2);
  display.print("  ");
  display.println(gasLimit, DEC);
  display.display();
}