/*
    VUT FEKT UTKO
    ID 173711
    xmozny03
    Radek Možný 
    Bakalářská práce - IR senzor pro detekci pohybu

    Program STANICE EZS

    Všechny příkazy  Serial.print() slouží k testovacím účelům a nemusí být implementovány.
    Část pr odesílání odezvy senzoru taktéž slouží pro testování funkčnosti programu.
*/


//definice knihoven
#include <HCuOLED.h>
#include <SPI.h>
#include <RH_RF22.h>

#define PINBAT A1                                        //definice pinu A1 pro měření napětí baterie
double percentage;                                       // proměnná procenta baterie ústředny EZS
double temperature;                                      //promenná teplota SI4432 ústředny EZS
const byte interruptPin = 3;                             //definice pinu 3 pro tlačítko změny programu
#define LED 4                                            // LED na pinu 4
#define pinSpeaker 5                                     // bzučák na pinu 5
int mode = 1;                                            // zvolený program 0 = střeženo, 1 = odstřeženo


#define RST_DI 7                                         //číslo pinu pro reset pin displeje
                                                         
#define CS_DI 8                                          //číslo pinu pro select(SS) pin displeje
                                                         
#define DC_DI 9                                          //číslo pinu pro datový/příkazový pin displeje

/* indexy pro koordináty X a Y */
#define X1 0
#define Y1 1
#define X2 2
#define Y2 3

RH_RF22 rf22;     //jméno pro driver z knihovny RH_RF22

void siren();    //funkce sirény


unsigned long previousMillis = 0;        // poslední uložený čas pro periodické nastavování displeje
unsigned long alarm_previousMillis = 0;

const long interval = 500;           // interval 0,5s pro periodiské nastavování displeje
const long alarm_interval = 3000;           // interval 3s pro vyhlášený poplach

float currentCounter_PIR1 = 0;       // proměnné pro časovače o rozhodnutí, zda byl senzor vypnut nebo zničen
float lastCounter_PIR1 = 0;
float currentCounter_PIR2 = 0;
float lastCounter_PIR2 = 0;
long casovac_PIR1 = 0, casovac_PIR2 = 0;

HCuOLED HCuOLED(SH1106, CS_DI, DC_DI, RST_DI); // definice pro SH1106 dipleje (HCMODU0058 & HCMODU0059)

String who;                //proměnná pro označení odesílatele
int PIR1_bat_number;       //procenta baterie PIR1
int PIR1_temp_number;       //teplota PIR1
char PIR1_state[10];       //stav PIR1
int PIR2_bat_number;       //procenta baterie PIR2
int PIR2_temp_number;       //teplota PIR2
char PIR2_state[10];       //stav PIR2
String PIR1_state_message;
String PIR2_state_message;


//funkce pro nastavení doby trvání zvuku bzučáku a frekvence bzučáku duration v milisekundách, frequence v Hz
void playTone(long duration, int freq) 
{
    duration *= 1000;
    int period = (1.0 / freq) * 1000000;
    long elapsed_time = 0;
    while (elapsed_time < duration) 
    {
    digitalWrite(pinSpeaker,HIGH);
    delayMicroseconds(period / 2);
    digitalWrite(pinSpeaker, LOW);
    delayMicroseconds(period / 2);
    elapsed_time += (period);
   }
}
 
void breach() {  //funkce vykonaná po stisku tlačítka změny programu - odstřežení a zrušení poplachu
  if(digitalRead(interruptPin) == LOW){
  playTone(200, 300);
  PIR1_state_message = "ok";
  //PIR1_state[10] = "ok";
  PIR2_state_message = "ok";
  //PIR2_state[10] = "ok";
  if(mode == 0){
  mode =1;
  }
  else{
  mode -= mode;
  }
}
}

void setup() //funkce proběhne jen jedenkrát
{
  /*nstavení vstupů/výstupů*/
  pinMode(pinSpeaker, OUTPUT);                                           
  pinMode(interruptPin, INPUT_PULLUP);                                    //nastavení pinu pro tlařítko přerušení jako vstup s aktivním pullup rezistorem
  attachInterrupt(digitalPinToInterrupt(interruptPin), breach, RISING);   //aktivace přerušení pro tlačítko reagující na nástupnou hranu a následně vykonávající funkci breach
  pinMode (PINBAT, INPUT);                                                                                           
  pinMode (LED, OUTPUT);
  pinMode (10, OUTPUT);
  pinMode (7, OUTPUT);
  Serial.begin(9600); //aktivace sériové komunikace o rychlosti 9600 baud

  /* Reset displeje */
  HCuOLED.Reset();

 //-----měření napětí baterie pomocí děliče po zapnutí senzoru------------ 
      delay(200);
      int sensorValue=analogRead(PINBAT);      //čtení digitální hodnoty napětí
      double d =3.3/1024*sensorValue*2;        // výpočet napětí ve voltech
      Serial.print(d,4);                       //výpis na 4 de. místa  
      Serial.println(" V");
      Serial.print("- Battery level: ");
      percentage = ((d -3.3)/0.9)*100;         //výpočet procet baterie v rozmezí 4,2V až 3,3V
      int temperature_val = rf22.temperatureRead(); //čtení digitální hodnoty teploty z SI4432
      temperature=temperature_val*0.5-64;      //výpočet teploty dle datasheetu SI4432 str 60 range 1 ->ADC8value x ADC8LSB + lowest temp -> ADC8LSB = 0,5; Lowest temp = -64 C
  
  rf22.init();   //inicializace komunikačního modulu DrF4432F20 

  if (!rf22.init()){ //při nezdařilé inicializaci se ohlásí chyba
    Serial.println("init failed");  
    Serial.flush();
  // Defaultní nastavení po inicializaci: 434.0MHz, 0.05MHz AFC pull-in, modulace FSK_Rb2_4Fd36
  }else{
    Serial.println("init ok");  
    Serial.flush();
  }
}





void loop() //opakující se funkce
{
  
uint8_t buf[RH_RF22_MAX_MESSAGE_LEN];
uint8_t len = sizeof(buf);



//---------------příjem zprávy-------------------------------------------------------------------------------
if (rf22.available())
  {
    // Should be a message for us now   
    if (rf22.recv(buf, &len))
    {
//--------------rozdělění zprávy na části jejich uložení do proměnných--------------------
String zprava = (char*)buf;                                                       //převedení string na char
int commaIndex = zprava.indexOf(';');                                             //zvolení oddělovače ;
int secondCommaIndex = zprava.indexOf(';', commaIndex + 1);
int thirdCommaIndex = zprava.indexOf(';', secondCommaIndex + 1);

who = zprava.substring(0, commaIndex);                                            //uložení odesílatele do proměnné who
if(who == "PIR1"){                                                                //uložení procent baterií, teplot a stavů PIR1 a PIR2
String PIR1_bat = zprava.substring(commaIndex + 1, secondCommaIndex);             //příklad výběru části zprávy pře oddělovačem a její uložení do proměnné typu string
String PIR1_temp = zprava.substring(secondCommaIndex+1, thirdCommaIndex);
PIR1_state_message = zprava.substring(thirdCommaIndex+1);
PIR1_bat_number = PIR1_bat.toInt();                                               //převedení string na int
PIR1_temp_number = PIR1_temp.toInt();
PIR1_state_message.toCharArray(PIR1_state,10);
}  
if(who == "PIR2"){ 
String PIR2_bat = zprava.substring(commaIndex + 1, secondCommaIndex);
String PIR2_temp = zprava.substring(secondCommaIndex+1, thirdCommaIndex);
PIR2_state_message = zprava.substring(thirdCommaIndex+1);
PIR2_bat_number = PIR2_bat.toInt();
PIR2_temp_number = PIR2_temp.toInt();
PIR2_state_message.toCharArray(PIR2_state,10);
}
//------------------------------------------------------------  

     digitalWrite (LED, HIGH); 
     if( who == "PIR1"){                                              //resetování časovače 1 v příade zpávy od PIR1
     casovac_PIR1 = millis(); 
     lastCounter_PIR1 = millis(); 
     }
     if( who == "PIR2"){                                              //resetování časovače 2 v příade zpávy od PIR2 
     casovac_PIR2 = millis(); 
     lastCounter_PIR2 = millis(); 
     }

//---------------------------měření baterie a teploty----------------------
      delay(200);
      int sensorValue=analogRead(PINBAT);                             // přečtení hodnoty napětí pinu A1 v rozmezí 0 až 1023
      double d =3.3/1024*sensorValue*2;                               // výpočet napětí - dělič 1:1
      Serial.print(d,4);
      Serial.println(" V");
      Serial.print("- Battery level: ");
      percentage = ((d -3.3)/0.9)*100;                                //výpočet procent baterie v rozmezí 4,2V až 3,3V               
     
      digitalWrite (LED, LOW);   
      Serial.println("got message: ");
      Serial.println((char*)buf);                                     // výpis buf v datovém typu char
      Serial.print("RSSI: ");
      Serial.println(rf22.lastRssi(), DEC);                           // výpis RSSI od posledního vysílače 
      uint8_t data[] = "PIR OK";                                      
      rf22.send(data, sizeof(data));                                  //vyslání odezvy vysílači, služí jen pro testovací účely
      rf22.waitPacketSent();                                          //čekání na potvrzení odeslání zprávy
      Serial.println("Sent a reply");
      int temperature_val = rf22.temperatureRead();                   // hodnota teploty z SI4432
      temperature=temperature_val*0.5-64;                             //výpočet teploty dle datasheetu SI4432 str 60 range 1 ->ADC8value x ADC8LSB + lowest temp -> ADC8LSB = 0,5; Lowest temp = -64 C
      Serial.print("Central Temperature: ");
      Serial.print(temperature_val);
      Serial.print(" , ");
      Serial.println(temperature);
      Serial.println();
    }
    else
    {
      Serial.println("recv failed");
      Serial.println();
    }
  }


Serial.println(mode);


  
//-----------------------část programu pro periodické nastavování displeje a vyhlašování poplachů --------------------  
 unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
  HCuOLED.SetFont(Terminal_8pt);         //nstavení fotnu displeje                         
  if(who == "PIR1"){                     // výpis informací o PIR 1 na Displej
  HCuOLED.Erase(0,0,128,24);             //příklad mazání části displeje z bufferu displeje
  }
  HCuOLED.Cursor(0,0);                  //příklad nastvení kurzoru displeje
  HCuOLED.Print("PIR1:");                //příklad výpisu informací na displej
  HCuOLED.Cursor(60,0);
  if(strlen(PIR1_state) == 0)             //výpis OFF v případě, že stanice ještě neobdržela zprávu od PIR1 za dobu své funkce
    {
    HCuOLED.Print("OFF");
    }
  else
    {
    HCuOLED.Erase(60,0,128,24);
    HCuOLED.Print(PIR1_state);
    } 
  HCuOLED.Cursor(0,10);
  HCuOLED.Print(PIR1_bat_number);
  HCuOLED.Cursor(25,10);
  HCuOLED.Print("%,");
  HCuOLED.Cursor(50,10);
  HCuOLED.Print(PIR1_temp_number);
  HCuOLED.Cursor(75,10);
  HCuOLED.Print("C");
  
  
  if(who == "PIR2"){                               // výpis informací o PIR 1 na Displej
  HCuOLED.Erase(0,25,128,49);
  }
  HCuOLED.Cursor(0,25);
  HCuOLED.Print("PIR2:");
  HCuOLED.Cursor(60,25);
  if(strlen(PIR2_state) == 0)                       //výpis OFF v případě, že stanice ještě neobdržela zprávu od PIR2 za dobu své funkce
    {
    HCuOLED.Print("OFF");
    }
  else
    {
    HCuOLED.Erase(60,25,128,49);
    HCuOLED.Print(PIR2_state);
    } 
  HCuOLED.Cursor(0,35);
  HCuOLED.Print(PIR2_bat_number);
  HCuOLED.Cursor(25,35);
  HCuOLED.Print("%,");
  HCuOLED.Cursor(50,35);
  HCuOLED.Print(PIR2_temp_number);
  HCuOLED.Cursor(75,35);
  HCuOLED.Print("C"); 
  
  HCuOLED.Cursor(0,50);              //výpis informací o stanici EZS na displej - baterie a teplota
  HCuOLED.Erase(0,50,128,64);
  if(mode == 1){                     //zobrazení módu
  HCuOLED.Print("Od:");               //odstřeženo
  } 
  if(mode == 0)                      //střeženo
  {
  HCuOLED.Print("St:");  
  }
  HCuOLED.Cursor(25,50);
  HCuOLED.Print(percentage);
  HCuOLED.Cursor(45,50);
  HCuOLED.Print("%,");
  HCuOLED.Cursor(65,50);
  HCuOLED.Print(temperature);
  HCuOLED.Cursor(90,50);
  HCuOLED.Print("C");

  
  
   
   
  HCuOLED.Refresh();               //obnovení displeje - aktualizace informací
 
  Serial.println(PIR2_state);
Serial.println(PIR1_state);
//----------------------vyhlašování poplachů---------------------
//unsigned long alarm_currentMillis = millis();
//  if (alarm_currentMillis - alarm_previousMillis >= alarm_interval) {
//    alarm_previousMillis = alarm_currentMillis;
  if (PIR1_state_message == "Alarm" || PIR2_state_message == "Alarm" || PIR1_state_message == "breach" || PIR2_state_message == "breach" && mode == 0)
  {
  if(mode == 0){
    digitalWrite (LED, HIGH); 
  playTone(200, 700);
  playTone(200, 300);
  playTone(200, 700);
  playTone(200, 300);
  playTone(200, 700);
  playTone(200, 300);
  playTone(200, 700);
  playTone(200, 300);
  playTone(200, 700);
  playTone(200, 300);
    digitalWrite (LED, LOW);
  } 
  }
  
  else if (PIR1_state_message == "Batt!" || PIR2_state_message == "Batt!")
  {
    if(mode == 0){
    digitalWrite (LED, HIGH);
    playTone(500, 700);
    delay(100);
    playTone(500, 300); 
    digitalWrite (LED, LOW); 
    }
  }
  }
//-------------------------------------------------------------------



  if (millis() > (60000 + casovac_PIR1) && strlen(PIR1_state) != 0 && mode == 0){  //kontrolní časovač - v případě neohlášení PIR 1 vyhlášen krátký poplach, ošetření pro zaezení vyhlášení
  if(mode == 0){
  HCuOLED.Erase(0,0,128,24);                                         // poplachu v případě, že stanice nikdy neobdržela zprávu od PIR1
  HCuOLED.Cursor(0,0);
  HCuOLED.Print("PIR1:");
  HCuOLED.Cursor(60,0);
  HCuOLED.Print("LOST");
  HCuOLED.Refresh();
  playTone(500, 500);
  playTone(500, 100);
  playTone(500, 500);
  playTone(500, 100);
  playTone(500, 500);
  }
  casovac_PIR1 = millis(); 
  lastCounter_PIR1 = millis();                                       //reset časovače
  HCuOLED.Erase(0,0,128,24);
  }

  if (millis() > (60000 + casovac_PIR2) && strlen(PIR2_state) != 0 && mode == 0){ //kontrolní časovač - v případě neohlášení PIR 2 vyhlášen krátký poplach, ošetření pro zaezení vyhlášení
  if(mode == 0){
  HCuOLED.Erase(0,25,128,49);                                        // poplachu v případě, že stanice nikdy neobdržela zprávu od PIR2
  HCuOLED.Cursor(0,25); 
  HCuOLED.Print("PIR2:");
  HCuOLED.Cursor(60,25);
  HCuOLED.Print("LOST");
  HCuOLED.Refresh();
  playTone(500, 500);
  playTone(500, 100);
  playTone(500, 500);
  playTone(500, 100);
  playTone(500, 500);
  }
  casovac_PIR2 = millis(); 
  lastCounter_PIR2 = millis();                                       //reset časovače
  HCuOLED.Erase(0,25,128,49);
  }


  

}



