/*
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

*/
#include "main.h"

#case

#define  REVERS      3     // 2*256 ms = 0,75 s
#define  GO          117   // 117*256 ms = 30 s
#define  GO_ZALUZIE  6     // cca 1,5 s
#define  RECEIVE     10    // cca 2,6 s

#define OR110NU PIN_A0 //* t1 Zaluzie koupelna dole
#define OR110ND PIN_A1 //* t2
#define OR207VU PIN_A2  // t3 Roleta klubovna
#define OR207VD PIN_A3  // t4
#define OR103VU PIN_A4  // t5 Roleta loznice
#define OR103VD PIN_A5  // t6
//#define OR104VU PIN_A4  // Roleta laborator vychod
//#define OR104VD PIN_A5
#define OR104JU PIN_A6  // t7 Roleta laborator jih
#define OR104JD PIN_A7  // t8

#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
#define OS106A  PIN_B3  // t4 Svetlo trucovna stred
#define OS107A  PIN_B4  // t5 Svetlo satna
#define OS109A  PIN_B5  // t6 Svetlo technologicka mistnost
//#define OS110J  PIN_B6   // t7 Svetlo koupelna dole sprcha
//#define O...  PIN_B7  // t8

//#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 O... PIN_F0   // t1
//#define O... PIN_F1   // t2 
//#define O... PIN_F2   // t3 
//#define O... PIN_F3   // t4 
//#define O... PIN_F4   // t5 
//#define O... PIN_F5   // t6
//#define O... PIN_F6   // t7
//#define O... PIN_F7   // t8

//#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 IR207VU input(PIN_D3)  // D Vypinac roleta klubovna nahoru
#define IR207VD input(PIN_D4)  // E Vypinac roleta klubovna dolu
#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 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 O... PIN_E4  // t5
#define OS209A  PIN_E5  // t6 Svetlo Zizala koupelna
#define OS203A  PIN_E6  // t7 Svetlo Kaklik koupelna
//#define O... PIN_E7  // t8 

int1  s201AV;
int1  s201AZ;
int1  s207AJ;
int1  s203AJ;
int1  s209AJ;
int1  r207VU;
int1  r207VD;

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

#define LED1 PIN_C0
#define LED2 PIN_C1 

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

typedef enum {GO_UP, GO_DOWN, REVERS_UP, REVERS_DOWN, STOP} state;

state r103V, r110N, r104V, r104J, r207V;      // Stavy rolet
int8 tr103V, tr110N, tr104V, tr104J, tr207V;   // Casovace rolet
int8 timer;                            // Casovac komunikace

#int_TIMER0
void  TIMER0_isr(void) 
{
   if(tr103V>0) tr103V--;
   if(tr110N>0) tr110N--;
   if(tr104V>0) tr104V--;
   if(tr104J>0) tr104J--;
   if(tr207V>0) tr207V--;
   if(timer>0) timer--;
output_toggle(LED2);
}

void up(state *status, int8 *timer) // Zmena stavu rolety smer nahoru
{
   switch (*status)
   {
      case STOP:
      case GO_DOWN:
         *status=REVERS_UP;
         *timer=REVERS;
         break;
      case REVERS_UP:
      case GO_UP:
         *status=STOP;
         *timer=0;
         break;
   }
}

void down(state *status, int8 *timer) // Zmena stavu rolety smer dolu
{
   switch (*status)
   {
      case STOP:
      case GO_UP:
         *status=REVERS_DOWN;
         *timer=REVERS;
         break;
      case REVERS_DOWN:
      case GO_DOWN:
         *status=STOP;
         *timer=0;
         break;
   }
}

#define run(x) {                                \
   switch(r##x)                                 \
   {                                            \
      case STOP:                                \
         OFF(OR##x##U);                          \
         OFF(OR##x##D);                          \
         break;                                 \
      case GO_UP:                               \
         OFF(OR##x##D);                          \
         ON(OR##x##U);                           \
         if(tr##x==0) {r##x=STOP;}              \
         break;                                 \
      case GO_DOWN:                             \
         OFF(OR##x##U);                          \
         ON(OR##x##D);                           \
         if(tr##x==0) {r##x=STOP;}              \
         break;                                 \
      case REVERS_UP:                           \
         OFF(OR##x##U);                          \
         OFF(OR##x##D);                          \
         if(tr##x==0) {r##x=GO_UP; tr##x=GO;}   \
         break;                                 \
      case REVERS_DOWN:                         \
         OFF(OR##x##U);                          \
         OFF(OR##x##D);                          \
         if(tr##x==0) {r##x=GO_DOWN; tr##x=GO;} \
         break;                                 \
   }                                            \
}      

void main()
{
   char buf[10];
   
   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_1);
   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);

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

   r103V=STOP;    // Rolety jsou zastaveny
   r110N=STOP;
   r104V=STOP;
   r104J=STOP;  
   r207V=STOP;  
   tr103V=0;
   tr110N=0;
   tr104V=0;
   tr104J=0;
   tr207V=0;
   
   output_high(LED1); // Indikace restartu (pockame na nabiti kondenzatoru ve vstupnich obvodech)
   delay_ms(100);   
   output_low(LED1);  
   delay_ms(30);
   output_high(LED1); 
   restart_wdt();
   delay_ms(100);   
   output_low(LED1);  
   delay_ms(30);
   output_high(LED1);    
   restart_wdt();
   
   s201AV=IS201AV;    // Precteme vychozi stav vypinacu
   s201AZ=IS201AZ;
   s207AJ=IS207AJ;
   s203AJ=IS203AJ;
   s209AJ=IS209AJ;
   r207VU=IR207VU;
   r207VD=IR207VD;
   
   enable_interrupts(INT_TIMER0);
   enable_interrupts(GLOBAL);
   
   CREN=0; CREN=1;               // Reinitialise USART
   
   while(TRUE)
   {

      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=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,&tr103V);} else {down(&r103V,&tr103V);}
                           break;
                        case '4':
                           if(buf[3]=='V') if((buf[4]=='U')) {up(&r104V,&tr104V);} else {down(&r104V,&tr104V);}
                           if(buf[3]=='J') if((buf[4]=='U')) {up(&r104J,&tr104J);} else {down(&r104J,&tr104J);}
                           break;
                        case 'a':
                           if((buf[4]=='U')) {up(&r110N,&tr110N);} else {down(&r110N,&tr110N);}
                           break;
                     }
                  }
               }
      
            }
         }
      }
            
      run(103V);     // Rizeni rolet za behu
//      run(104V);
      run(104J);
      run(207V);

      switch(r110N)  // Zaluzie ma specielni rizeni                                 
      {                                            
         case STOP:                                
            OFF(OR110NU);                          
            OFF(OR110ND);                          
            break;
         case GO_UP:                               
            OFF(OR110ND);                          
            ON(OR110NU);                           
            if(tr110N==0) {r110N=STOP;}              
            break;                                 
         case GO_DOWN:                             
            OFF(OR110NU);                          
            ON(OR110ND);                           
            if(tr110N==0) {r110N=STOP;}              
            break;                                 
         case REVERS_UP:                           
            OFF(OR110NU);                          
            OFF(OR110ND);                          
            if(tr110N==0) {r110N=GO_UP; tr110N=GO_ZALUZIE;}   // Nahoru pouze kratce na otevreni zaluzie
            break;                                 
         case REVERS_DOWN:                         
            OFF(OR110NU);                          
            OFF(OR110ND);                          
            if(tr110N==0) {r110N=GO_DOWN; tr110N=GO_ZALUZIE;} // Dolu take kratce pouze na zaklopeni zaluzie
            break;                             
      }                                                    

      // mistni vypinace z 2. n.p.
      if(s201AV!=IS201AV) {s201AV=IS201AV; output_toggle(OS102A); delay_ms(100); continue;}
      if(s201AZ!=IS201AZ) {s201AZ=IS201AZ; output_toggle(OS102A); delay_ms(100); continue;}
      if(s207AJ!=IS207AJ) {s207AJ=IS207AJ; output_toggle(OS207A); delay_ms(100); continue;}
      if(s203AJ!=IS203AJ) {s203AJ=IS203AJ; output_toggle(OS203A); delay_ms(100); continue;}
      if(s209AJ!=IS209AJ) {s209AJ=IS209AJ; output_toggle(OS209A); delay_ms(100); continue;}
         
     if(r207VU!=IR207VU) {r207VU=IR207VU; up(&r207V,&tr207V); delay_ms(100); continue;}
     if(r207VD!=IR207VD) {r207VD=IR207VD; down(&r207V,&tr207V); delay_ms(100); continue;}

      restart_wdt();
   }
}