/*
Ovladani domu rozvadec 2. n.p.

Syntaxe prikazu:

<Roleta/Svetlo><#patro><#mistnost><Nord/Jih/Vychod/Zapad/A/B><Up/Down>
R2aNU - roleta, 2. n.p., mistnost 10, sever, nahoru
S12A  - svetlo, 1. n.p., mistnost 2, prostredni

Rozmisteni desek:

               [IN D]
                       [OUT E]
 [IN H]        [IN J]    
                       [OUT B]
              [CPU]    

 [OUT G] [CAN] [OUT A] [OUT F]

*/
#include "main.h"

#case
#use fast_io(A)      // Aby se neztracely znaky pri cteni prikazu
#use fast_io(B)
#use fast_io(E)
#use fast_io(F)
#use fast_io(D)
#use fast_io(J)
#use fast_io(H)
#use fast_io(G)

#define  T_REVERS      2        // 2*256 ms = 0,5 s; pred prepnutim rele (zastaveni motoru a vybiti kondenzatoru)
#define  T_START       1        // 1*256 ms = 0,3 s; po prepnuti rele do sepnuti triaku
#define  T_GO          117      // 117*256 ms = 30 s; max. beh rolety
#define  T_GO_ZALUZIE  2500/256 // cca 2 s; beh zaluzie (pouze na preklopeni lamel)
#define  T_RECEIVE     10       // cca 2,6 s
#define  TIMEOUT_SPAJZ 255      // Timeout svetlo spajz cca minuta
#define  ZAKMIT        2000     // pocet pruchodu hlavni smyckou pred opetovnou detekci prepnuti vypinace

//!!! STUDENAK na triaku spolecny vyvod !!! #define O PIN_A0  // t1 
#define OR110N PIN_A1  // t2 Zaluzie koupelna dole sever
#define OR104V PIN_A2  // t3 Roleta lab vychod
#define OR104J PIN_A3  // t4 Roleta lab jih
#define OR103V PIN_A4  // t5 Roleta loznice
#define OR202J PIN_A5  // t6 Roleta Kaklik
#define OR204Z PIN_A6  // t7 Roleta radiomistnost
#define OR207V PIN_A7  // t8 Roleta klubovna

#define OR208V PIN_F0   // t1 Roleta Zizala vychod
#define OR208J PIN_F1   // t2 Roleta Zizala jih
//???  #define OR107 PIN_F2   // t3 Roleta satna
#define OR106J PIN_F3   // t4 Roleta trucovna jih
#define OR201Z PIN_F4   // t5 Roleta chodba nahore
#define OR205N PIN_F5   // t6 Roleta puda
//??? #define OR105 PIN_F6   // t7 Roleta kuchyn
#define OR106Z PIN_F7   // t8 Roleta trucovna zapad


#define OS103J  PIN_B0  // t1 Svetla loznice
#define OS105Z  PIN_B1  // t2 Svetlo kuchyn nad lavici
#define OS110N  PIN_B2  // t3 Svetlo koupelna dole zachod a sprhca
#define OS106A  PIN_B3  // t4 Svetlo trucovna stred
#define OS107A  PIN_B4  // t5 Svetlo satna
#define OS109A  PIN_B5  // t6 Svetlo technologicka mistnost
#define OS205A  PIN_B6  // t7 Svetlo puda
#define OS204A  PIN_B7  // t8 Svetlo radiomistnost

//#define OS105C PIN_C2 
//#define PIN_C3  31763
//#define PIN_C4  31764
//#define PIN_C5  31765
//#define PIN_C6  31766 //TX
//#define PIN_C7  31767 //RX

#define OS102A  PIN_E0  // t1 Svetlo chodba
#define OS105A  PIN_E1  // t2 Svetlo kuchyne stred
#define OS207A  PIN_E2  // t3 Svetlo klubovna
#define OS104A  PIN_E3  // t4 Svetlo laborator
#define OS202A  PIN_E4  // t5 Svetlo Kaklik stred
#define OS209A  PIN_E5  // t6 Svetlo Zizala koupelna
#define OS203A  PIN_E6  // t7 Svetlo Kaklik koupelna
#define RE      PIN_E7  // t8 Rele pro rizeni smeru rolet

//#define O....  PIN_G0  // t8 
//#define O....  PIN_G1  // t7 
#define OS108A  PIN_G2  // t6 Svetlo spajz
#define OS208A  PIN_G3  // t5 Svetlo Zizala stred
#define OS100A  PIN_G4  // t4 Svetlo prujezd venku

//#define I....   input(PIN_D0)  // A
#define IS201AZ   input(PIN_D1)  // B Vypinac chodba 2.n.p. zapad u Kaklika
#define IS207AJ   input(PIN_D2)  // C Vypinac klubovna
#define IR207VD   input(PIN_D3)  // D Vypinac roleta klubovna dolu
#define IR207VU   input(PIN_D4)  // E Vypinac roleta klubovna nahoru
#define IS201AV   input(PIN_D5)  // F Vypinac chodba 2.n.p. vychod
#define IS209AJ   input(PIN_D6)  // G Vypinac koupelna Zizala
#define IS203AJ   input(PIN_D7)  // H Vypinac koupelna Kaklik

#define IS202AN   input(PIN_J0)  // A Vypinac svetlo Kaklik stred u dveri na chodbu
#define IR202ND   input(PIN_J1)  // B Vypinac roleta Kaklik dolu u dveri
#define IR202NU   input(PIN_J2)  // C Vypinac roleta Kaklik nahoru u dveri
#define IS205A    input(PIN_J3)  // D Vypinac svetlo puda
#define IS204AJ   input(PIN_J4)  // E Vypinac svetlo radiomistnost u dveri na chodbu
#define IR204ZD   input(PIN_J5)  // F Vypinac roleta radiomistnost dolu
#define IR204ZU   input(PIN_J6)  // G Vypinac roleta radiomistnost nahoru
#define IS108A    input(PIN_J7)  // H Mikrospinac spajz

#define IS208AN   input(PIN_H0)  // A Vypinac svetlo stred Zizala u dveri na chodbu //POZOR! Jsou prohozeny rolety J a V a smery U a D
#define IR208JD   input(PIN_H1)  // B Vypinac roleta vychod Zizala nahoru u dveri
#define IR208JU   input(PIN_H2)  // C Vypinac roleta vychod Zizala dolu u dveri
#define IR208VD   input(PIN_H3)  // D Vypinac roleta jih Zizala nahoru u dveri
#define IR208VU   input(PIN_H4)  // E Vypinac roleta jih Zizala dolu u dveri
//#define I....   input(PIN_H5)  // F 
//#define I....   input(PIN_H6)  // G 
#define Ispec   input(PIN_H7)  // H specialni vypinac u rozvadece 2.n.p.


int1  s201AV;
int1  s201AZ;
int1  s207AJ;
int1  s203AJ;
int1  s209AJ;
int1  r207VU;
int1  r207VD;
int1  s202AN;
int1  r202ND;
int1  r202NU;
int1  s205A; 
int1  s204AJ;  
int1  r204ZD;  
int1  r204ZU; 
int1  s208AN; 
int1  r208VU; 
int1  r208VD; 
int1  r208JU; 
int1  r208JD; 
int1  ispec;

#bit CREN = 0xFAB.4      // USART enable register

#define LED1 PIN_C0  // Vyvedeno na desku portu G
#define LED2 PIN_C1  // Vyvedeno na desku portu G

#define ON(port)  output_low(port);
#define OFF(port) output_high(port);

typedef enum {RUN, STOP} roleta_state;
roleta_state rol[18]; // Stavy rolet
#define R103V  0
#define R110N  1
#define R104V  2
#define R104J  3
#define R207V  4
#define R202J  5
#define R204Z  6
#define R208V  7
#define R208J  8
#define R106J  9
#define R106Z  10

typedef enum {UP, DOWN, REVERS_UP, REVERS_DOWN, RUN_UP, RUN_DOWN, RUN_UP_WAITING} relay_state;
relay_state relay;   // Stavy rele 

int8 timer_run;         // Bezpecnostni casovac behu rolety
int8 timer_run_zaluzie; // Casovac zaluzie na preklopeni lamel
int8 timer_revers;      // Prodleva na vybiti kondenzatoru pa zastaveni rolety pred prepnutim rele
int8 timer_start;       // Prodleva na prepnuti rele pred startem rolety
int8 timer;             // Casovac komunikace
int8 tS108;             // Casovac svetlo spajz

#int_TIMER0
void  TIMER0_isr(void) 
{
   if(timer>0) timer--;
   if(tS108>0) tS108--;
   if(timer_run>0) timer_run--;
   if(timer_revers>0) timer_revers--;
   if(timer_start>0) timer_start--;
   if(timer_run_zaluzie>0) timer_run_zaluzie--;
output_toggle(LED2);
}

void stop_all()      // Zastav vsechny rolety
{
   int8 n;
   
   output_a(0xFF);   
   output_f(0xFF);    
   for(n=0; n<18; n++) rol[n]=STOP;
}

void run_all()      // Spust rolety
{
   if (rol[R103V]==RUN) ON(OR103V);
   if (rol[R110N]==RUN) ON(OR110N);
   if (rol[R104V]==RUN) ON(OR104V);
   if (rol[R104J]==RUN) ON(OR104J);
   if (rol[R207V]==RUN) ON(OR207V);
   if (rol[R202J]==RUN) ON(OR202J);
   if (rol[R204Z]==RUN) ON(OR204Z);
   if (rol[R208V]==RUN) ON(OR208V);
   if (rol[R208J]==RUN) ON(OR208J);
   if (rol[R106J]==RUN) ON(OR106J);
   if (rol[R106Z]==RUN) ON(OR106Z);
}

void run(int8 roleta)      // Spust konkretni roletu
{
   switch (roleta)
   {
      case R103V: ON(OR103V); break;
      case R110N: ON(OR110N); break;
      case R104V: ON(OR104V); break;
      case R104J: ON(OR104J); break;
      case R207V: ON(OR207V); break;
      case R202J: ON(OR202J); break;
      case R204Z: ON(OR204Z); break;
      case R208V: ON(OR208V); break;
      case R208J: ON(OR208J); break;
      case R106J: ON(OR106J); break;
      case R106Z: ON(OR106Z); break;
   }
}

void stop(int8 roleta)      // Spust konkretni roletu
{
   switch (roleta)
   {
      case R103V: OFF(OR103V); break;
      case R110N: OFF(OR110N); break;
      case R104V: OFF(OR104V); break;
      case R104J: OFF(OR104J); break;
      case R207V: OFF(OR207V); break;
      case R202J: OFF(OR202J); break;
      case R204Z: OFF(OR204Z); break;
      case R208V: OFF(OR208V); break;
      case R208J: OFF(OR208J); break;
      case R106J: OFF(OR106J); break;
      case R106Z: OFF(OR106Z); break;
   }
}

void up(int8 roleta)  // Pozadavek, aby roleta jela nahoru
{
   if (rol[roleta]==RUN)
   {
      rol[roleta]=STOP;  // Roleta jela, tak zastav
      stop(roleta);
   }
   else
   {
      if ((relay==DOWN)||(relay==RUN_DOWN)) // Rele je prepnuto na druhou stranu!
      {
         relay=REVERS_UP;        // Reverzuj
         timer_revers=T_REVERS;  // Natahni casovac na vybiti kondenzatoru a reverz motoru
         stop_all();             // Vsechno zastav
      }
      if (relay==RUN_UP)
      {
         run(roleta);          // Jede se spravnym smerem, tak jenom pust roletu
      }

      rol[roleta]=RUN;  // Roleta stala, tak ji pust
      timer_run=T_GO;   // Natahni bezpecnostni casovac
   }
}


void down(int8 roleta)  // Pozadavek, aby roleta jela dolu
{
   if (rol[roleta]==RUN)
   {
      rol[roleta]=STOP;  // Roleta jela, tak zastav
      stop(roleta);
   }
   else
   {
      if ((relay==UP)||(relay==RUN_UP)||(relay==RUN_UP_WAITING)) // Rele je prepnuto na druhou stranu!
      {
         relay=REVERS_DOWN;      // Reverzuj
         timer_revers=T_REVERS;  // Natahni casovac na vybiti kondenzatoru a reverz motoru
         stop_all();             // Vsechno zastav
      }
      if (relay==RUN_DOWN)
      {
         run(roleta);          // Jede se spravnym smerem, tak jenom pust roletu
      }

      rol[roleta]=RUN;  // Roleta stala, tak ji pust
      timer_run=T_GO;   // Natahni bezpecnostni casovac
   }
}


void main()
{
   char buf[10];                 // Buffer pro prijem prikazu
   unsigned int16 zakmity=0;      // Osetreni zakmitu vypinacu
   
   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_CLOCK_DIV_2);
   setup_psp(PSP_DISABLED);
   setup_spi(SPI_SS_DISABLED);
   setup_wdt(WDT_OFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_8);
   setup_timer_1(T1_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
   setup_ccp1(CCP_OFF);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);
   
   set_tris_a(0);    // Vystupy
   set_tris_b(0);
   set_tris_e(0);
   set_tris_f(0);
   set_tris_g(0x20);
   set_tris_d(0xFF); // Vstupy
   set_tris_j(0xFF);
   set_tris_h(0xFF);

   output_a(0xFF);    // Vsechno zhasni a zastav
   output_b(0xFF);    
   output_f(0xFF);    
   output_e(0xFF);    
   output_g(0xFF);    
   stop_all();

   relay=RUN_UP_WAITING;    // Rele je na zacatku vypnuto

   {
      int n;
      
      for(n=0;n<10;n++)
      {
         output_low(LED1); // Indikace restartu (pockame na nabiti kondenzatoru ve vstupnich obvodech)
         delay_ms(100);   
         output_high(LED1);  
         delay_ms(100);
         restart_wdt();
      }
   }
   
   s201AV=IS201AV;    // Precteme vychozi stav vypinacu
   s201AZ=IS201AZ;
   s207AJ=IS207AJ;
   s203AJ=IS203AJ;
   s209AJ=IS209AJ;
   r207VU=IR207VU;
   r207VD=IR207VD;
   s202AN=IS202AN;
   r202ND=IR202ND;
   r202NU=IR202NU;
   s205A=IS205A; 
   s204AJ=IS204AJ;  
   r204ZD=IR204ZD;  
   r204ZU=IR204ZU; 
   s208AN=IS208AN; 
   r208VU=IR208VU; 
   r208VD=IR208VD; 
   r208JU=IR208JU; 
   r208JD=IR208JD; 
   ispec=Ispec;
  
   timer_run=0;            // Zastav vsechny casovace
   timer=0;
   timer_revers=0;
   timer_start=0;
   timer_run_zaluzie=0;
   zakmity=0;

   enable_interrupts(INT_TIMER0);   // Spust casovani
   enable_interrupts(GLOBAL);

   CREN=0; CREN=1;               // Reinitialise USART

   while(TRUE)
   {
      restart_wdt();

      if(kbhit()) // Chce po nas nekdo neco?
      {
         buf[0]=getc();
         if((buf[0]=='S')||(buf[0]=='R')) // Jinym znakem nesmi zacinat prikaz
         {
            int8 n=0;      // Ukazatel do prijimaciho bufferu         
            timer=T_RECEIVE; // Timeout pro prijem znaku
            
            do
            {
               if(kbhit())   // Je dalsi znak?
               {
                  n++;
                  buf[n]=getc();
               }
            } while ((buf[n]!='\r')&&(timer>0)&&(n<7));
            
            if (timer==0) { CREN=0; CREN=1; }   // Reinitialise USART

            output_toggle(LED1);  // Ukonceni prijimani prikazu
            
            if((timer>0))
            {

               if((buf[0]=='S')&&(n>=4))  // Zmena stavu svetla
               {
                  if(buf[1]=='1')
                  {
                     switch(buf[2])
                     {
                        case '2':
                           output_toggle(OS102A);
                           break;
                        case '3':
                           output_toggle(OS103J);
                           break;
                        case '4':
                           output_toggle(OS104A);
                           break;
                        case '5':
                           if(buf[3]=='A') {output_toggle(OS105A);}
                           if(buf[3]=='Z') {output_toggle(OS105Z);}
                           break;
                        case '6':
                           output_toggle(OS106A);
                           break;
                        case '7':
                           output_toggle(OS107A);
                           break;
                        case '8':
//                           output_toggle(OS108A);
                           break;
                        case '9':
                           output_toggle(OS109A);
                           break;
                        case 'a':
//                           output_toggle(OS110J);
                           output_toggle(OS110N);
                           break;
                     }
                  }
               }
               
               if((buf[0]=='R')&&(n>=5))  // Zmena stavu rolety
               {
                  if(buf[1]=='1')
                  {
                     switch(buf[2])
                     {
                        case '3':
                           if(buf[4]=='U') {up(R103V);} else {down(R103V);}
                           break;
                        case '4':
                           if(buf[3]=='V') if((buf[4]=='U')) {up(R104V);} else {down(R104V);}
                           if(buf[3]=='J') if((buf[4]=='U')) {up(R104J);} else {down(R104J);}
                           break;
                        case '6':
                           if(buf[3]=='J') if((buf[4]=='U')) {up(R106J);} else {down(R106J);}
                           if(buf[3]=='Z') if((buf[4]=='U')) {up(R106Z);} else {down(R106Z);}
                           break;
                        case 'a':
                           if((buf[4]=='U')) 
                           {//up(R110N);                        
                              if ((relay==DOWN)||(relay==RUN_DOWN)) // Rele je prepnuto na druhou stranu!
                              {
                                 relay=REVERS_UP;        // Reverzuj
                                 timer_revers=T_REVERS;  // Natahni casovac na vybiti kondenzatoru a reverz motoru
                                 stop_all();             // Vsechno zastav
                              }
                              if (relay==RUN_UP)
                              {
                                 run(R110N);          // Jede se spravnym smerem, tak jenom pust roletu
                              }
                        
                              rol[R110N]=RUN;  // Roleta stala, tak ji pust
                              timer_run=T_GO;   // Natahni bezpecnostni casovac
                           } 
                           else 
                           {//down(R110N);
                              if ((relay==UP)||(relay==RUN_UP)||(relay==RUN_UP_WAITING)) // Rele je prepnuto na druhou stranu!
                              {
                                 relay=REVERS_DOWN;      // Reverzuj
                                 timer_revers=T_REVERS;  // Natahni casovac na vybiti kondenzatoru a reverz motoru
                                 stop_all();             // Vsechno zastav
                              }
                              if (relay==RUN_DOWN)
                              {
                                 run(R110N);          // Jede se spravnym smerem, tak jenom pust roletu
                              }
                        
                              rol[R110N]=RUN;  // Roleta stala, tak ji pust
                              timer_run=T_GO;   // Natahni bezpecnostni casovac
                           }
                           timer_run_zaluzie=T_GO_ZALUZIE;
                           break;
                     }
                  }
               }
      
            }
         }
      }
            
      // mistni vypinace z 2. n.p.
      if (0==zakmity)
      {
         if(s201AV!=IS201AV) {s201AV=IS201AV; output_toggle(OS102A); zakmity=ZAKMIT;}
         if(s201AZ!=IS201AZ) {s201AZ=IS201AZ; output_toggle(OS102A); zakmity=ZAKMIT;}
         if(s207AJ!=IS207AJ) {s207AJ=IS207AJ; output_toggle(OS207A); zakmity=ZAKMIT;}
         if(s203AJ!=IS203AJ) {s203AJ=IS203AJ; output_toggle(OS203A); zakmity=ZAKMIT;}
         if(s209AJ!=IS209AJ) {s209AJ=IS209AJ; output_toggle(OS209A); zakmity=ZAKMIT;}
         if(s205A!=IS205A)   {s205A=IS205A;   output_toggle(OS205A); zakmity=ZAKMIT;}
         if(s204AJ!=IS204AJ) {s204AJ=IS204AJ; output_toggle(OS204A); zakmity=ZAKMIT;}
         if(s202AN!=IS202AN) {s202AN=IS202AN; output_toggle(OS202A); zakmity=ZAKMIT;}
         if(s208AN!=IS208AN) {s208AN=IS208AN; output_toggle(OS208A); zakmity=ZAKMIT;}
    
         if(r207VU!=IR207VU) {r207VU=IR207VU; up(R207V);   zakmity=ZAKMIT;}
         if(r207VD!=IR207VD) {r207VD=IR207VD; down(R207V); zakmity=ZAKMIT;}
         if(r202NU!=IR202NU) {r202NU=IR202NU; up(R202J);   zakmity=ZAKMIT;}
         if(r202ND!=IR202ND) {r202ND=IR202ND; down(R202J); zakmity=ZAKMIT;}
         if(r204ZU!=IR204ZU) {r204ZU=IR204ZU; up(R204Z);   zakmity=ZAKMIT;}
         if(r204ZD!=IR204ZD) {r204ZD=IR204ZD; down(R204Z); zakmity=ZAKMIT;}
         if(r208VU!=IR208VU) {r208VU=IR208VU; up(R208V);   zakmity=ZAKMIT;}
         if(r208VD!=IR208VD) {r208VD=IR208VD; down(R208V); zakmity=ZAKMIT;}
         if(r208JU!=IR208JU) {r208JU=IR208JU; up(R208J);   zakmity=ZAKMIT;}
         if(r208JD!=IR208JD) {r208JD=IR208JD; down(R208J); zakmity=ZAKMIT;}

         if(ispec!=Ispec) {ispec=Ispec; output_toggle(OS100A); zakmity=ZAKMIT;}
      }
      else zakmity--;
      
      // Spajz mikrospinac i svetlo
      if(IS108A) {output_high(OS108A); tS108=TIMEOUT_SPAJZ;}
      if((!IS108A)&&(tS108>0)) {output_low(OS108A);} else {output_high(OS108A);}
      
      switch (relay)
      {
         case UP:
               if (timer_start==0)  // Rele prepnuto, muzeme sepnout triaky
               {
                  relay=RUN_UP;     // Zmen stav na "jede se"
                  run_all();        // Sepni triaky u rolet, ktere maji jet
                  timer_run=T_GO;   // Natahni bezpecnostni casovac
               }
            break;
   
         case DOWN:
               if (timer_start==0)  // Rele prepnuto, muzeme sepnout triaky
               {
                  relay=RUN_DOWN;   // Zmen stav na "jede se"
                  run_all();        // Sepni triaky u rolet, ktere maji jet
                  timer_run=T_GO;   // Natahni bezpecnostni casovac
               }
            break;
            
         case RUN_UP:
               if (timer_run==0)    // Vyprsel bezpecnostni casovac
               {
                  timer=RUN_UP_WAITING;
                  stop_all();       // Vsechno zastav
               }
            break;
   
         case RUN_DOWN:
               if (timer_run==0)    // Vyprsel bezpecnostni casovac
               {
                  relay=REVERS_UP;  // Vsechno zastav a reverzuj pro prepnuti rele do klidove polohy bez energizace civky
                  stop_all();
                  timer_revers=T_REVERS;
               }
            break;
    
         case REVERS_UP:
               if (timer_revers==0) // Uz se snad vybil kondenzator, muzeme reverzovat
               {
                  relay=UP;            // Prepni rele 
                  OFF(RE);
                  timer_start=T_START; // Pockej na prepnuti rele
               }
            break;
   
         case REVERS_DOWN:
               if (timer_revers==0) // Uz se snad vybil kondenzator, muzeme reverzovat
               {
                  relay=DOWN;          // Prepni rele
                  ON(RE);
                  timer_start=T_START; // Pockej na prepnuti rele
               }
            break;
      }    

      // Zaluzie ma kratsi beh
      if ((timer_run_zaluzie==0)&&(rol[R110N]==RUN)) {rol[R110N]=STOP; OFF(OR110N);}
   }
}