#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 S105A  PIN_A0
#define R110NU PIN_A1
#define R110ND PIN_A2
#define S104A  PIN_A3
#define R104VU PIN_A4
#define R104VD PIN_A5
#define R104JU PIN_A6
#define R104JD PIN_A7

#define S103J  PIN_B0
#define R103VU PIN_B1
#define R103VD PIN_B2
#define S106A  PIN_B3
#define S107A  PIN_B4
#define S109A  PIN_B5

//#define OS101 PIN_C0 
//#define OS105B PIN_C1  
//#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 S101A PIN_F0
#define S105Z PIN_F1  
#define S102A PIN_F2
#define S110N PIN_F3
#define S108A PIN_F4
#define S201A PIN_F5
#define S110J PIN_F6

/*
#define PIN_E0  31776
#define PIN_E1  31777
#define PIN_E2  31778
#define PIN_E3  31779
#define PIN_E4  31780
#define PIN_E5  31781
#define PIN_E6  31782
#define PIN_E7  31783

#define PIN_F0  31784
#define PIN_F1  31785
#define PIN_F2  31786
#define PIN_F3  31787
#define PIN_F4  31788
#define PIN_F5  31789
#define PIN_F6  31790
#define PIN_F7  31791

#define PIN_G0  31792
#define PIN_G1  31793
#define PIN_G2  31794
#define PIN_G3  31795
#define PIN_G4  31796
#define PIN_G5  31797

#define PIN_H0  31800
#define PIN_H1  31801
#define PIN_H2  31802
#define PIN_H3  31803
#define PIN_H4  31804
#define PIN_H5  31805
#define PIN_H6  31806
#define PIN_H7  31807

#define PIN_J0  31808
#define PIN_J1  31809
#define PIN_J2  31810
#define PIN_J3  31811
#define PIN_J4  31812
#define PIN_J5  31813
#define PIN_J6  31814
#define PIN_J7  31815
*/

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

#define LED1 PIN_J7
#define LED2 PIN_J6 

#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;      // Stavy rolet
int8 tr103V, tr110N, tr104V, tr104J;   // 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(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(R##x##U);                          \
         OFF(R##x##D);                          \
         break;                                 \
      case GO_UP:                               \
         ON(R##x##U);                           \
         OFF(R##x##D);                          \
         if(tr##x==0) {r##x=STOP;}              \
         break;                                 \
      case GO_DOWN:                             \
         OFF(R##x##U);                          \
         ON(R##x##D);                           \
         if(tr##x==0) {r##x=STOP;}              \
         break;                                 \
      case REVERS_UP:                           \
         OFF(R##x##U);                          \
         OFF(R##x##D);                          \
         if(tr##x==0) {r##x=GO_UP; tr##x=GO;}   \
         break;                                 \
      case REVERS_DOWN:                         \
         OFF(R##x##U);                          \
         OFF(R##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);

   OFF(S105A);    // Vsechno zhasni a zastav
   OFF(R110NU);
   OFF(R110ND);
   OFF(S104A);
   OFF(R104VU);
   OFF(R104VD);
   OFF(R104JU);
   OFF(R104JD);
   OFF(S103J);
   OFF(R103VU);
   OFF(R103VD);
   OFF(S106A);
   OFF(S107A);
   OFF(S109A);
   OFF(S105Z);  
   OFF(S102A);
   OFF(S110N);
   OFF(S108A);
   OFF(S201A);
   OFF(S110J);

   r103V=STOP;    // Rolety jsou zastaveny
   r110N=STOP;
   r104V=STOP;
   r104J=STOP;  
   tr103V=0;
   tr110N=0;
   tr104V=0;
   tr104J=0;
   
   output_high(LED1); // Indikace restartu
   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();
   
   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(S102A);
                           break;
                        case '3':
                           output_toggle(S103J);
                           break;
                        case '4':
                           output_toggle(S104A);
                           break;
                        case '5':
                           if(buf[3]=='A') {output_toggle(S105A);}
                           if(buf[3]=='Z') {output_toggle(S105Z);}
                           break;
                        case '6':
                           output_toggle(S106A);
                           break;
                        case '7':
                           output_toggle(S107A);
                           break;
                        case '8':
                           output_toggle(S108A);
                           break;
                        case '9':
                           output_toggle(S109A);
                           break;
                        case 'a':
                           output_toggle(S110J);
                           output_toggle(S110N);
                           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);

      switch(r110N)  // Zaluzie ma specielni rizeni                                 
      {                                            
         case STOP:                                
            OFF(R110NU);                          
            OFF(R110ND);                          
            break;
         case GO_UP:                               
            ON(R110NU);                           
            OFF(R110ND);                          
            if(tr110N==0) {r110N=STOP;}              
            break;                                 
         case GO_DOWN:                             
            OFF(R110NU);                          
            ON(R110ND);                           
            if(tr110N==0) {r110N=STOP;}              
            break;                                 
         case REVERS_UP:                           
            OFF(R110NU);                          
            OFF(R110ND);                          
            if(tr110N==0) {r110N=GO_UP; tr110N=GO_ZALUZIE;}   // Nahoru pouze kratce na otevreni zaluzie
            break;                                 
         case REVERS_DOWN:                         
            OFF(R110NU);                          
            OFF(R110ND);                          
            if(tr110N==0) {r110N=GO_DOWN; tr110N=2*GO_ZALUZIE;} // Dolu jede dele, aby se najelo na koncak a zatemnilo.
            break;                             
      }                                                    
/*
switch(r110A)
{
   case GO_UP:
      printf("U");
      break;
   case GO_DOWN:
      printf("D");
      break;
   case REVERS_UP:
      printf("R");
      break;
   case REVERS_DOWN:
      printf("E");
      break;
   case STOP:
      printf("S");
      break;     
}
*/
      restart_wdt();
   }
}