/*
GYEREKSZOBA 1. EGYSÉG

IN1 - redőny le
IN2 - redőny fel
IN3 - Világítás 1
IN4 - LED 1
IN5 - Nappali villany

DS/TSOP -> TSOP

OUT1 - redőny le
OUT2 - redőny fel
OUT3 - világítás1

PWM1 - LED 1
PWM2 - Éjszakai LED

*/

#include <Arduino.h>
#include <avr/power.h>
#include "config.h"
#include "ports.h"
#include "globalvars.h"
#include "buttonvars.h"
#include <avr/wdt.h>
#include <EthernetENC.h>
#include "networking.h"
#include <EthernetUdp.h>
EthernetUDP udp_rx;
EthernetUDP udp_tx;

int readPin(uint8_t pin)
{
  for (uint16_t samples = 0; samples < button_poll_sample_count; samples++)
  {
    if (digitalRead(pin))
      return 1;
    else
      delay(button_poll_sample_interval);
  }
  return 0;
}

void getButtonState(unsigned short buttonID)
{

  if (readPin(buttonPins[buttonID]) == 0)
  {

    if (buttonStates[buttonID] == 0)
    {

      buttonStates[buttonID] = 1;
      return;
    }

    if ((millis() - buttonTimers[buttonID] > longPressTime) && (buttonStates[buttonID] != 2))
    {

      buttonStates[buttonID] = 2;
      return;
    }
  }
  else
  {

    if (buttonStates[buttonID] > 0)
    {
      buttonStates[buttonID] = 0;
      return;
    }
  }
}

void fireEvent(uint8_t buttonID, uint8_t oldValue, uint8_t newValue)
{
  switch (buttonID)
  {
  case 0:
    /* IN5 LDR  */
    break;
  case 1:
    /* Redőny LE */
    if (oldValue == 0 && newValue == 1)
    {
      digitalWrite(OUT1, HIGH);
      digitalWrite(OUT2, LOW);
    }
    else if (newValue == 0)
    {
      digitalWrite(OUT1, LOW);
      digitalWrite(OUT2, LOW);
    }
    break;
  case 2:
    /* Redőny FEL */
    if (oldValue == 0 && newValue == 1)
    {
      digitalWrite(OUT1, LOW);
      digitalWrite(OUT2, HIGH);
    }
    else if (newValue == 0)
    {
      digitalWrite(OUT1, LOW);
      digitalWrite(OUT2, LOW);
    }
    break;
  case 3:
    /* Relés 3 nagyvillany kapcsolója  */
    if (oldValue == 0 && newValue == 1)
    {
      relay3_state = !relay3_state;
      digitalWrite(OUT3, relay3_state);
    }
    break;
  case 4:
    /* Dimmelős ledes gomb */
    break;
  }
}

void reportButtonUdp(uint16_t buttonID, uint8_t buttonState)
{
  if (udp_tx.begin(buttonPorts[buttonID]) == 1)
  {
    udp_tx.beginPacket(udp_server, buttonPorts[buttonID]);
    if (buttonState == 0)
      udp_tx.write("0");
    else if (buttonState == 1)
      udp_tx.write("1");
    else if (buttonState == 2)
      udp_tx.write("2");
    udp_tx.endPacket();
    udp_tx.stop();
  }
}

void buttonTriggers()
{
  for (uint8_t i = 0; i < 5; i++)
  {
    if (previousButtonStates[i] != buttonStates[i])
    {
      disableButtonReadTicks = millis();
      if (onlineMode == false)
        fireEvent(i, previousButtonStates[i], buttonStates[i]);
      else
        reportButtonUdp(i, buttonStates[i]);
      previousButtonStates[i] = buttonStates[i];
      return;
    }
  }
}

void setup()
{
  // clock_prescale_set(clock_div_2);

  wdt_enable(WDTO_8S);
  Serial.end();
  UCSR0B = 0;

  pinMode(IN1, INPUT);
  pinMode(IN2, INPUT);
  pinMode(IN3, INPUT);
  pinMode(IN4, INPUT);
  pinMode(LDR, INPUT);

  pinMode(OUT1, OUTPUT);
  pinMode(OUT2, OUTPUT);
  pinMode(OUT3, OUTPUT);
  pinMode(SHT_CLOCK, INPUT);
  pinMode(SHT_DATA, INPUT);

  pinMode(PWM1, OUTPUT);
  pinMode(PWM2, OUTPUT);

  analogWrite(PWM1, 0);
  analogWrite(PWM2, 0);

  digitalWrite(OUT1, LOW);
  digitalWrite(OUT2, LOW);

  delay(200);
  Ethernet.begin(mac, ip);
  for (uint8_t j = 0; j < 2; j++)
  {
    for (uint8_t i = 0; i < 20; i++)
    {
      analogWrite(PWM2, i);
      delay(20);
    }
    for (uint8_t i = 20; i > 0; i--)
    {
      analogWrite(PWM2, i);
      delay(20);
    }
  }
  udp_rx.begin(receive_port);
}

void action_callback(char cmd, int value)
{
  /* PWM 1 */
  if (cmd == 'A')
  {
    if (value >= 0 && value <= 255)
      analogWrite(PWM1, value);
    return;
  }
  /* PWM 2*/
  if (cmd == 'B')
  {
    if (value >= 0 && value <= 255)
      analogWrite(PWM2, value);
    return;
  }
  /* Redőnymotor */
  if (cmd == 'E')
  {
    if (value == 0)
    {
      digitalWrite(OUT1, LOW);
      digitalWrite(OUT2, LOW);
    }
    else if (value == 1)
    {
      digitalWrite(OUT1, HIGH);
      digitalWrite(OUT2, LOW);
    }
    else if (value == 2)
    {
      digitalWrite(OUT1, LOW);
      digitalWrite(OUT2, HIGH);
    }
    return;
  }
  /* 3-as relé*/
  if (cmd == 'G') // 3-as relé kapcsolása
  {
    if (value == 0) // Ha az üzenet értéke 0 -> kikapcsoljuk
    {
      digitalWrite(OUT3, LOW);
      relay3_state = false;
    }
    else if (value == 1) // Ha az üzenet értéke 1 -> bekapcsoljuk
    {
      digitalWrite(OUT3, HIGH);
      relay3_state = true;
    }
    else if (value == 2) // Ha az üzenet értéke 2 -> váltjuk és jelentjük, hogy mire sikerült
    {
      relay3_state = !relay3_state;
      digitalWrite(OUT3, relay3_state); // Átváltás
    }
    if (udp_tx.begin(UDP_PORT_REPORT_RELAY3) == 1)
    {
      udp_tx.beginPacket(udp_server, UDP_PORT_REPORT_RELAY3);
      if (relay3_state)
        udp_tx.write("1");
      else
        udp_tx.write("0");
      udp_tx.endPacket();
      udp_tx.stop();
    }
    return;
  }
}
void checkRX()
{
  if (udp_rx.parsePacket() > 0)
  {
    lastreceived = OFFLINE_THRESHOLD_SECONDS;
    if (!onlineMode)
      onlineModeRequest = true;
    for (int i = 0; i < RX_BUFFER_SIZE; i++)
      rx_packet_buffer[i] = 0x00;
    udp_rx.read(rx_packet_buffer, RX_BUFFER_SIZE);
    action_callback(rx_packet_buffer[0], atoi(&rx_packet_buffer[1]));
  }
  udp_rx.flush();
}

void clock_tick()
{
  /* Ebben a függvényben futnak le a másodpercenkénti feladatok */

  /* Utoljára fogadott adat alapján offline/online mód váltás */
  if (lastreceived > 0)
  {
    lastreceived--;
    if (lastreceived == 0)
    {
      onlineMode = false;
      onlineModeRequest = false;
      digitalWrite(OUT1, LOW);
      digitalWrite(OUT2, LOW);
    }
  }
  /* Online módra váltás és kapcsolódott állapot kijelzés */
  if (onlineModeRequest == true)
  {
    digitalWrite(OUT1, LOW);
    digitalWrite(OUT2, LOW);
    onlineModeRequest = false;
    onlineMode = true;
    if (udp_tx.begin(UDP_PORT_KEEPALIVE) == 1)
    {
      udp_tx.beginPacket(udp_server, UDP_PORT_KEEPALIVE);
      udp_tx.write("cd");
      udp_tx.endPacket();
      udp_tx.stop();
      return;
    }
  }

  /* Online mód esetén életjel küldése */
  if (onlineMode)
  {
    currentKeepAliveTicks++;
    if (currentKeepAliveTicks >= sendKeepaliveInterval)
    {
      currentKeepAliveTicks = 0;
      if (udp_tx.begin(UDP_PORT_KEEPALIVE) == 1)
      {
        udp_tx.beginPacket(udp_server, UDP_PORT_KEEPALIVE);
        udp_tx.write("a");
        udp_tx.endPacket();
        udp_tx.stop();
      }
    }
  }
}

void loop()
{
  wdt_reset();
  currentMillis = millis();

  /* Gombok kiolvasása, minden programciklusban egyet */
  if (currentMillis - disableButtonReadTicks > buttonPollingGap)
  {
    getButtonState(buttonreader);
    buttonreader++;
    if (buttonreader > 4)
      buttonreader = 0;
  }

  /* Kiolvasott gombok alapján balhé indítása */
  buttonTriggers();

  /* Málna felől fogadás */
  checkRX();

  /* Másodpercenkénti időzített feladat futtatás */
  if (currentMillis - secondTicks > 1000)
  {
    secondTicks = currentMillis;
    clock_tick();
  }
}
