#include <OPC.h>
#include <Bridge.h>
#include <Ethernet.h>
#include <SPI.h>

OPCSerial aOPCSerial; // Declarando o protocolo OPC Serial

long _dog2 = 0;      // variavel de comparação de tempo do watchdog
long _tempo = 1000;  // variavel de determinação do flip-flop
int _led = LOW;      // estado inicial da variável (Pino 50 ligar LED externo)

// Criando a função de retorno de cada item OPC

int callback(const char *ANALOG, const opcOperation opcOP, const int value)
{
  int port_ea = atoi(&ANALOG[1]);  // Transformando *ANALOG de char -> int
   
  switch (port_ea)                
   {     
      case 0:      
         return analogRead(port_ea);  
         break;   
      case 1:     
         return analogRead(port_ea); 
         break; 
      case 2:     
         return analogRead(port_ea); 
         break;
      case 3:     
         return analogRead(port_ea); 
         break;
      case 4:     
         return analogRead(port_ea); 
         break;
      case 5:     
         return analogRead(port_ea); 
         break;
      case 6:     
         return analogRead(port_ea); 
         break;
      case 7:     
         return analogRead(port_ea); 
         break;
      case 8:     
         return analogRead(port_ea); 
         break;
      case 9:     
         return analogRead(port_ea); 
         break;
      case 10:     
         return analogRead(port_ea); 
         break;
      case 11:     
         return analogRead(port_ea); 
         break;
      case 40:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;         
      case 41:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 42:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 43:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 44:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 45:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 46:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 47:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 48:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
      case 49:
         if (opcOP == opc_opwrite)
         {
          digitalWrite(port_ea, value);
         }  
         else
          return digitalRead(port_ea);
         break;
   } 
}

bool item_bool(const char *ENT_DIG, const opcOperation opcOP, const bool value)
{
  int port_ed = atoi(&ENT_DIG[1]);  // Transformando *ENT_DIG de char -> int

    switch (port_ed)
    {     
      case 25:      
         return digitalRead(port_ed);  
         break;
      case 26:
         return digitalRead(port_ed);  
         break; 
      case 27:
         return digitalRead(port_ed);  
         break;
      case 28:
         return digitalRead(port_ed);  
         break;
      case 29:
         return digitalRead(port_ed);  
         break;
      case 30:
         return digitalRead(port_ed);  
         break;
      case 31:
         return digitalRead(port_ed);  
         break;
      case 32:
         return digitalRead(port_ed);  
         break;
      case 33:
         return digitalRead(port_ed);  
         break;
      case 34:
         return digitalRead(port_ed);  
         break;        
      case 39:
         return digitalRead(port_ed);  
         break;        
    }
}

void setup() {
  
  pinMode(25, INPUT); // definição das entradas digitais 25 -> 34
  pinMode(26, INPUT);
  pinMode(27, INPUT);
  pinMode(28, INPUT);
  pinMode(29, INPUT);
  pinMode(30, INPUT);
  pinMode(31, INPUT);
  pinMode(32, INPUT);
  pinMode(33, INPUT);  
  pinMode(34, INPUT);
  pinMode(39, OUTPUT); // watchdog externo
  pinMode(40, OUTPUT); // definição das saídas digitais 40 -> 49
  pinMode(41, OUTPUT);
  pinMode(42, OUTPUT);
  pinMode(43, OUTPUT);
  pinMode(44, OUTPUT);
  pinMode(45, OUTPUT);
  pinMode(46, OUTPUT);
  pinMode(47, OUTPUT);
  pinMode(48, OUTPUT);
  pinMode(49, OUTPUT);
  
  Serial.begin(9600);
  aOPCSerial.setup();

  aOPCSerial.addItem("A00",opc_read, opc_int, callback); // Adicionando analogicas a matriz OPC
  aOPCSerial.addItem("A01",opc_read, opc_int, callback);
  aOPCSerial.addItem("A02",opc_read, opc_int, callback);
  aOPCSerial.addItem("A03",opc_read, opc_int, callback);
  aOPCSerial.addItem("A04",opc_read, opc_int, callback);
  aOPCSerial.addItem("A05",opc_read, opc_int, callback);
  aOPCSerial.addItem("A06",opc_read, opc_int, callback);
  aOPCSerial.addItem("A07",opc_read, opc_int, callback);
  aOPCSerial.addItem("A08",opc_read, opc_int, callback);
  aOPCSerial.addItem("A09",opc_read, opc_int, callback);
  aOPCSerial.addItem("A10",opc_read, opc_int, callback);
  aOPCSerial.addItem("A11",opc_read, opc_int, callback);
  
  aOPCSerial.addItem("D25",opc_read, opc_bool, item_bool); // adicionando entradas digitais a matriz OPC 
  aOPCSerial.addItem("D26",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D27",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D28",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D29",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D30",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D31",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D32",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D33",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D34",opc_read, opc_bool, item_bool);
  aOPCSerial.addItem("D39",opc_read, opc_bool, item_bool);
    
  aOPCSerial.addItem("D40",opc_readwrite, opc_bool, callback); // adicionando saídas digitais a matriz OPC
  aOPCSerial.addItem("D41",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D42",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D43",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D44",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D45",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D46",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D47",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D48",opc_readwrite, opc_bool, callback);
  aOPCSerial.addItem("D49",opc_readwrite, opc_bool, callback);
  
}

void loop()
{
 
  unsigned long _dog1 = millis(); // inicializando variavel de tempo
  
  if(_dog1 - _dog2 > _tempo)
  {                                // Fazendo a condicional 
    _dog2 = _dog1;                 // Condiconal sendo verdadeira executa funções
    if(_led==LOW)
    {                              // Se "_led" estiver apagado 
      digitalWrite(39,HIGH);       // Escreve na saída 39 o nível alto
      _led=HIGH;                   // Seta a variável _led para o nivel alto
    }
    else                           // senão
    {                          
     digitalWrite(39,LOW);         // Escreve na saída 39 o nível baixo
     _led=LOW;                     // Seta a variável "_led" para o nivel baixo
    }   
  }
   
  aOPCSerial.processOPCCommands(); // processando os comandos OPC

}
