APS SO

Dependencies:   WebSocketClient mbed

Fork of APS_SO by Ian Bolfarini

main.cpp

Committer:
ianwillianb
Date:
2017-12-15
Revision:
2:27a7a42b2bae
Parent:
1:3da12598c635

File content as of revision 2:27a7a42b2bae:

#include "mbed.h"
#include "rtos.h"
#include "Rtc_Ds1307.h"
#include "EthernetInterface.h"
#include "Websocket.h"
#include <iostream>   
#include <string>     


//Objeto da ethernet
EthernetInterface eth;
//Inicialização do RTC
Rtc_Ds1307 rtc(D14,D15);
//Estrutura responsável por armazenar os dados do RTC
Rtc_Ds1307::Time_rtc alarm_time ; 
//Estrutura responsável por armazenar a data/hora de ativação do alarme
Rtc_Ds1307::Time_rtc a_time_start ;
Rtc_Ds1307::Time_rtc a_time_end ; 
int range = 3; // uma flag mantida em "1" caso o tempo atual lido do rtc esteja dentro do intervalo de funcionamento do alarme e, caso contrário, setada para "0".
//Estabelece comunicação serial para DEBUG
Serial gSerial(USBTX, USBRX);
//variavel de estado do alarme: 0 - desarmado devido ao horario, 1 - armado, 2 - disparando, 3- desarmado pelo usuario
int state = 0; //incia em zero desarmado, é ajustado na thread de controle caso o horario esteja no range de alarme ativado
DigitalIn enable(D8); //a variável enable lê o sinal do sensor de presença, que está conectado na entrada D8. Variável enable será true ou false conforme haja sinal ou não do sensor.
DigitalOut led_red(LED_RED); //led vermelho
DigitalOut led_green(LED_GREEN); //led verde
DigitalOut led_blue(LED_BLUE); //led azul
DigitalOut buzzer(D9); //buzzer


//Declaracao das Threads
Thread *RtcRead; //le o RTC e atualiza a estrutura 
Thread *SetRange; //Verifica se está dentro do range - entre tempo de inicio e tempo de fim
Thread *LedThread; //controla leds de status e buzzer
Thread *SetState; //verifica e ajusta os estados - armado, desarmado, disparando, desarmado forçado 
Thread *PrintRange; //imprime valores de estado e range e hora atual - para debug
Thread *SocketThread; //thread das sockets

//Ajuste da hora atraves da interface serial, so para ajuste do relogio              
 void set_time_serial()
 {
    int hora, min, seg, dia, mes, ano, opt, d_sem;
    
    gSerial.printf("\n1-Ajuste de Hora, 2-Ajuste de Data, 3-Ajuste de Data/Hora: ");
    gSerial.scanf("%d",&opt);
   
    
    if(opt == 1 || opt ==3 ) {
                    
    gSerial.printf("\nInsira a hora(HH MM SS): ");
    gSerial.scanf("%d %d %d", &hora, &min, &seg);
    
    if( (hora < 24 && hora>=0) && (min>=0 && min <60) && (seg>=0 && seg <60)) 
            {
                   
                   rtc.getTime(alarm_time);
                   alarm_time.hour = hora;
                   alarm_time.min = min;
                   alarm_time.sec = seg;      
                   rtc.setTime(alarm_time, true, false);
                   rtc.getTime(alarm_time);
                   gSerial.printf("\nHora Ajustada: %2d:%02d:%02d \n",alarm_time.hour,alarm_time.min,alarm_time.sec);
                                                                                
                                                                                
            }                
            
            else  gSerial.printf("Entrada Incorreta.\n");
                
              
             } 
             
             
          if(opt==2 || opt ==3)
             {
                 
                gSerial.printf("Insira a data(DIA MES ANO DIA-SEMANA(1-7)): ");
                gSerial.scanf("%d %d %d %d", &dia, &mes, &ano, &d_sem);
                if((dia < 32 && dia >0 && mes<13 && mes>0  && ano>2000) && !(mes == 2 && dia >=29 ) && !((mes == 4 || mes == 6 || mes == 9 || mes == 11)  && dia >30) && (d_sem>0 &&d_sem<8))
                {
                 
                    
                   rtc.getTime(alarm_time);
                   alarm_time.wday = d_sem;
                   alarm_time.date = dia;
                   alarm_time.mon = mes;
                   alarm_time.year = ano;      
                   rtc.setTime(alarm_time, true, false);
                   rtc.getTime(alarm_time);
                   gSerial.printf("\nData Ajustada: %2d/%02d/%d \n",alarm_time.date,alarm_time.mon,alarm_time.year);
                 
                 }
                 
                 else gSerial.printf("Entrada Incorreta.\n");  
                 
                 
            } 
            
            else gSerial.printf("Opcao Invalida!.\n");         

             
 }     
 
 void set_range () {
     
    while(1) {
        /* pode-se ter 3 situações: 
        //  a hora de início da ativação do alarme é numericamente menor que a hora do encerramento
        //  a hora de início da ativação é igual à hora de fim
        //  a hora de início da ativação é numericamente maior que a hora de fim
        */
        if (a_time_start.hour < a_time_end.hour) { // Neste caso, o range está contido todo dentro de um dia (entre 0:00 e 23:59) mas as horas de início e fim do alarme são diferentes.
            if (a_time_start.hour < alarm_time.hour && alarm_time.hour < a_time_end.hour)  {// Neste caso o valor do RTC está entre o horário de ligada e o de desligada
                printf("muda range = 1\n");
                range = 1;  
                }
            else if (a_time_start.hour == alarm_time.hour) { // Neste caso a hora do RTC é igual à de um dos extremos (início do range)
                if (a_time_start.min <= alarm_time.min)
                    range = 1;
                else range = 0;    
            }
            else if (a_time_end.hour == alarm_time.hour) { // Neste caso a hora do RTC é igual à do último extremo (fim do range)
                if (a_time_end.min >= alarm_time.min)
                    range = 1;
                else range = 0;    
            }
            else range = 0;
        }
        
        else if (a_time_start.hour == a_time_end.hour) { // Neste caso a hora de ativamento e de desarme do alarme é a mesma. Mas o caso específico será destrinchado nos "ifs" aninhados
            if (a_time_start.min < a_time_end.min) {
                if (alarm_time.hour == a_time_start.hour) {
                    if (a_time_start.min <= alarm_time.min && alarm_time.min <= a_time_end.min)
                        range = 1;
                    else range = 0;    
                }
                else range = 0;
            }
            else if (a_time_start.min > a_time_end.min) {
                if (alarm_time.hour == a_time_end.hour) {
                    if (a_time_start.min > alarm_time.min && alarm_time.min > a_time_end.min)
                        range = 0;
                    else range = 1;    
                }
                else range = 1;
            }
            else if(a_time_start.min == a_time_end.min) range = 0;
        }
        
        else if (a_time_start.hour > a_time_end.hour) { // Neste caso, o range está contido em um período que compreende dois dias - alarme permanece ativado na transição de 23:59 para 0:00. As horas de início e fim do alarme são diferentes.
            if (a_time_start.hour > alarm_time.hour && alarm_time.hour > a_time_end.hour)
                range = 0;  
            else if (a_time_end.hour == alarm_time.hour) {
                if (a_time_end.min < alarm_time.min)
                    range = 0;
                else range = 1;    
            } 
            else if (a_time_start.hour == alarm_time.hour) {
                if (a_time_start.min > alarm_time.min)
                    range = 0;
                else range = 1;    
            } 
            else range = 1;
        }
                
    }
        
}      

 void set_state () {
 
    while (1) {
        
        if (state != 3) { //se estado é 3 o alarme foi desabilitado pelo usuario, logo não são necessarios teste
            if (range == 0 && state == 1) state = 0; //se nao esta no range e estado =1(armado), desarma automatico 
            if (range == 1 && state == 0) state = 1; //se esta no range mas estado = 0 (desarmado), arma automatico 
            if (range == 1 && state == 1) { //estado armado e no range
                if (enable) state = 2;  //se o sensor pir mandar um sinal em alto, manda para o estado 2 (armado)
            }
        }    
         
         

         
    }    
 
 }

 //thread resposavel por verificar a hora
 void rtc_read (){
 
 while(1){
        rtc.getTime(alarm_time);
        }
        
 
 }
 
void led_thread()
{
    //apaga todos os leds antes de acender os leds desejados
    led_blue=1;
    led_green=1;
    led_blue =1;
    
    
 while(true){   
    
if(state == 0 || state==3) { //neste caso o alarme não está ativo - estado desarmado ou desarmado forçado
    
    
    led_green = 1;
    led_blue = 1;
    led_red =0;
       
    
    }    
    
    
    if(state == 1) //se estiver armado só liga o led verde
    
    {
    
    led_green = 0; 
    led_blue = 1;
    led_red =1;    
        
        
        
    }
    
    
    if(state == 2) //estado disparado: acionamento dos leds vermelho e azul alternado em 0.5s, buzzer é ativo junto com os leds na mesma frequência
    
    {   //desliga todos os leds para assegurar que somente os desejados estarão ligados neste estado
        led_red=1;
        led_blue=1;
        led_green =1;
        
        led_red =0; //liga o led vermelho
        buzzer = 0;  //liga o buzzer, ativo em 0 devido ao transistor PNP
        wait(0.5); //aguarda meio segundo
        led_red = 1; //desliga o led vermelho
        led_blue = 0; //liga o led azul
        buzzer = 1; //desliga o buzzer 
        wait(0.5);  //aguarda 0.5s
        led_blue=1; //desliga o led azul    
        
        
        
        }
    
    }
    
    
}

//thread para estabelecer comunicação via sockets
void socket_thread(){
    
        //inicia um comunicação via socket com o seguinte servidor
        Websocket ws("ws://192.168.2.2:8555/ws", &eth);
        //conecta
        int connect_error = ws.connect();
        //wait para o sensor exibir mensagem de comunicação
        wait(1);


    
//buffer de entrada, guarda dados do servidor
char buf_in[20];
//ponteiro usado na função strtok_r
char *token;
//char para o codigo para indicar que o servidor deve exibir o menu
char menu_return[2];


        
        
   //loop da thread     
   while(true){     
   
        

          //se receber dados via socket     
         if (ws.read(buf_in)) {
             //cria uma cópia do buffer para ser "thread safe"
             char *rest = buf_in;
             //corta a string entre espaços
             token = strtok_r(rest, " ", &rest);
             //converte o primeiro dado para int. opt indica qual operação sera realiza, é sempre o primeiro dado da string recebida
             int opt = atoi(token); 
             //se for 1, realiza a modificação do horario de inicio e fim de operação do alarme 
             if(opt ==1){
            //divide a string e converte os dados para int   
             token = strtok_r(rest, " ", &rest);
             int start_hour = atoi(token);
             token = strtok_r(rest, " ", &rest);
             int start_min = atoi(token);
             token = strtok_r(rest, " ", &rest);
             int start_sec = atoi(token);
            token = strtok_r(rest, " ", &rest);
             int end_hour = atoi(token);
             token = strtok_r(rest, " ", &rest);
             int end_min = atoi(token);
             token = strtok_r(rest, " ", &rest);
             int end_sec = atoi(token); 
             //faz atribuições
             a_time_start.hour  = start_hour;
             a_time_start.min  = start_min;
             a_time_start.sec  = start_sec;
             a_time_end.hour  = end_hour;
             a_time_end.min  = end_min;
             a_time_end.sec  = end_sec;

            
            sprintf (menu_return, "99"); //codigo de retorno ao menu para a aplicação no pc
            ws.send(menu_return); //envia código indicando que a operação foi finalizada e aplicação deve retornar ao menu
            
            
            
             }
             
             
             //opção 2 usuario habilita ou desabilita o alarme mesmo que esteja dentro do range de tempo de funcionamento
             if(opt == 2)
             {
                 char en_dis[25];
                 //se o estado for diferente de 3 (desarmado pelo usuario), seta em 3
                 if(state!=3){
                  
                 printf("opt: %d\n",opt);
                 state =3;
                 
                 printf("state: %d\n",state);
                  //envia feedback para a aplicação
                    sprintf (en_dis, "Sistema Desabilitado");        
                    ws.send(en_dis);
                 
                 }
                 //caso for 3 habilita o alarme
                 else if(state==3){
                     
                 printf("opt: %d\n",opt);
                 state =0;
                 
                  //envia feedback para a aplicação
                 sprintf (en_dis, "Sistema Habilitado");        
                 ws.send(en_dis);
                


                     
                     }
                    wait(1);
                    sprintf (menu_return, "99"); //codigo de retorno ao menu
                    ws.send(menu_return);
             }
             
            // envia para a aplicação feedback de seu status
             if(opt == 3) 
             {  char state_text[60];
                
                if(state == 0){
                    sprintf (state_text, "Alarme Desabilitado - Fora do Periodo de Funcionamento");        
                    ws.send(state_text);
                    }
                if(state == 1){
                    sprintf (state_text, "Alarme Habilitado");        
                    ws.send(state_text);
                    }
                if(state == 2){
                    sprintf (state_text, "Alarme Disparado!!!");        
                    ws.send(state_text);
                    }
                if(state == 3){
                    sprintf (state_text, "Alarme Desabilitido pelo Usuario");        
                    ws.send(state_text);
                    }       
                                wait(1);
                                sprintf (menu_return, "99"); //codigo de retorno ao menu
                                ws.send(menu_return);
                 
            }  //fim do opt==3
             
                
                 
                //informa para a aplicação, que deve voltar ao menu principal       
                 if(opt == 8 || opt == 6)
                     
                     {
                         char back_to_menu1[2];
                         sprintf(back_to_menu1,"99");
                        ws.send(back_to_menu1);
                         
                         
                     }


         }
         
         //caso dispare
         if(state==2){
                        //buffer de entrada
                        char state_2[1];
                        //para sair do loop
                        int input =1; 
                        //manda código para a apicação informando que o alarme disparou
                        char disp[2];
                        //int resposavel por armazenar a resposta da aplicação
                        int state_20;
                        sprintf(disp,"88"); //codigo 88 alarme disparado
                        ws.send(disp);
                        //loop para receber a resposta
                        while(input){
                            //se receber dados da aplicação
                            if(ws.read(state_2)){ 
                            
                            
                            //converte para int o dado recebido
                            state_20 = atoi(state_2);
                            
                      
                            
                            }
                            
                                //se for 9 (indica que o usuario desabilitou o alarme)
                                if(state_20 == 9) {
                                
                                
                                 //alarme desabilitado, volta para 0, deixa para a thread set_state decidir o proximo estado
                                state = 0;
                               //condicao para sair do loop
                               input = 0;

                               
                               }
                                
                            
                         
                            }//fim do while do state 2
                        

             
         }//fim do if state=2
        
        
        
                
              }//fim do while
                
            
            
            

    
    
    }


//thread explicitamente usada para debug, nao realiza trabalho útil. É dispensável para o funcionamento do sistema
void print_range(){

while(true){

//hora do rtc
gSerial.printf("Hora: %2d:%02d:%02d \n",alarm_time.hour,alarm_time.min,alarm_time.sec);  
//valor do range
gSerial.printf("Valor Range: %d\n", range);
//valor de hora de inicio e fim da ativação ajustado via aplicação
gSerial.printf("para a estrutura: start_hour: %d start_min: %d start_sec: %d end_hour: %d end_min: %d end_sec: %d \n",a_time_start.hour,a_time_start.min,a_time_start.sec,a_time_end.hour,a_time_end.min,a_time_end.sec);  

wait(1);



}


}



 
 int main()
 {       
         buzzer = 1; //desativa o buzzer. Como usamos um transistor pnp para chavear o buzzer, a lógica é inversa. O buzzer deve ser desativado pois a saida default da porta é 0
         enable.mode(PullDown); //coloca na entrada um resistor de pull-down para ler 0, a não ser que exista uma entrada em 1 vindo do sensor PIR    
          
        int x = eth.set_dhcp(true); //ativa dhcp
        int i=eth.connect(); //conecta
        //verifica conexão para debug apenas
        gSerial.printf("DHCP status: %i \r\n",x);
        gSerial.printf("connect status: %i \r\n",i);
        gSerial.printf("IP Address is %s\n\r", eth.get_ip_address());
        

        
        
         
        //Iniciando o alarme com valor default inicial
        a_time_start.hour = 0;
        a_time_start.min = 10;
        
        //Iniciando o alarme com valor default final
        a_time_end.hour = 6;
        a_time_end.min = 50;        
  

           
        wait(2); //aguarda 2s para o sensor PIR gerar uma saida consistente   
        
        //Inicialização das Threads
         SetRange = new Thread(set_range);
         RtcRead = new Thread(rtc_read);
         PrintRange = new Thread(print_range);
         SetState = new Thread(set_state);
         LedThread = new Thread(led_thread); 
         SocketThread = new Thread(socket_thread);
        
  
   
         
         

}