//******** Mrakomer ******************************************
#define VERSION "2.1"  // Special version for the BART
#define ID "$Id: irmrak.c 420 2006-12-29 21:43:11Z kakl $"
//************************************************************

#include "irmrak.h"
#include <string.h>

#use rs232(baud=9600,parity=N,xmit=PIN_A6,rcv=PIN_A7,bits=8)

char VER[4]=VERSION;
char REV[50]=ID;

#define TRESHOLD  8  // nebo 9
                     // nad_diodou=H je + teplota
                     // pod_diodou=L je - teplota

#define MINUS  !C1OUT      // je kladny impuls z IR teplomeru
#define PLUS   C2OUT       // je zaporny impuls z IR teplomeru
#define HALL   PIN_A4      // Hallova sonda pro zjisteni natoceni dolu
// topeni je na RB3 (vystup PWM)

#define MAX_TEMP 10000

int port;   // stav brany B pro krokove motory
int j;      // pro synchronisaci fazi
unsigned int8  uhel;   // pocitadlo prodlevy mezi merenimi
unsigned int8  i;      // pro cyklus for
unsigned int16 nn;     // pocitadlo mereni
unsigned int32 timer;  // casovac pro topeni
unsigned int8  topit;  // na jaky vykon se ma topit?

unsigned int16 teplota;    // prectena teplota
int1 sign;                 // nad nulou / pod nulou

// --- Jeden krok krokoveho motoru ---
void krok(int n)
{
   while((n--)>0)
   {
      if (1==(j&1)) {port^=0b11000000;} else {port^=0b00110000;};
      output_B(port);
      delay_ms(50);
      j++;
   }
}

// --- Dojet dolu magnetem na cidlo ---
void dolu()
{
   unsigned int8 err;   // pocitadlo pro zjisteni zaseknuti otaceni

   err=0;
   while(!input(HALL))  // otoceni trubky dolu az na hall
   {
      krok(1);
      err++;
      if(40==err)       // do 40-ti kroku by se melo podarit otocit dolu
      {
         output_B(0);   // vypnuti motoru
         printf("Error movement.\n\r");
         err=0;
      }
   };
   delay_ms(700);    // cas na ustaleni trubky
   output_B(0);      // vypnuti motoru
}

// --- Najeti na vychozi polohu dole ---
void nula()
{
   int n;

   for (n=0; n<7; n++)
   {
      if (!input(HALL)) return;
      krok(1);
   }
}

// --- Precti teplotu z IR teplomeru ---
void prevod()
{
   unsigned int16 t;       // cas
   unsigned int16 tt;

   t=0;
   while(!PLUS && !MINUS)
   {
      t++;
      if(t>65000)
      {
         printf("Error thermometer.\n\r");
         teplota=0;
         sign=true;
         return;
      }
   }; // ceka se na 0

   teplota=0;
   sign=false;
   for(t=0;t<=MAX_TEMP;t++)
   {
      if(PLUS || MINUS)     // ceka se na + nebo -
      {
         if(MINUS) sign=true;
         for(tt=1;tt<=MAX_TEMP;tt++)
         {
            if(!PLUS && !MINUS) {teplota=tt; break;};  // ceka se na 0
         }
         break;
      }
   }
   teplota=teplota*19/100;  // 1 stupen celsia je asi 10us
}

// --- Prevod a vystup jedne hodnoty ---
void vystup()
{
      delay_ms(200);    // pockej na ustaleni napeti po krokovani
      printf(" ");
      prevod();         // precti teplotu z teplomeru
      if(sign)
        printf("-%Lu", teplota);
      else
        printf("%Lu", teplota);
}

//------------------------------------------------
void main()
{
   setup_oscillator(OSC_4MHZ|OSC_INTRC);     // 4 MHz interni RC oscilator

   setup_adc_ports(NO_ANALOGS|VSS_VDD);
   setup_adc(ADC_OFF);
   setup_spi(FALSE);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);  // Casovac pro PWM
   setup_timer_1(T1_DISABLED);
   setup_ccp1(CCP_OFF);
   setup_comparator(A0_VR_A1_VR);   // inicializace komparatoru
   setup_vref(VREF_HIGH|TRESHOLD);  // 32 kroku od 0.25 do 0.75 Vdd

   // nastav PWM pro topeni
   set_pwm1_duty(0);       // Spust PWM, ale zatim s trvalou 0 na vystupu
   setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_16,100,1);  // perioda

   output_B(0);               // vypnuti motoru
   set_tris_B(0b00000111);    // faze a topeni jako vystup

   delay_ms(1000);
   printf("Mrakomer V%s (C) 2006 KAKL\n\r", VER);
   printf("%s\n\r", REV);

   topit=0;          // na zacatku netopime

   while(true)
   {
      port=0b01010000;  // vychozi nastaveni fazi pro rizeni motoru
      j=0;              // smer dolu
      dolu();           // otoc trubku do vychozi pozice dolu

      while(!kbhit())
      {
         timer--;
         if (0==timer)         // casovac, aby se marakomer neupek
         {
            topit=0;
            set_pwm1_duty(0);  // zastav topeni
            printf("H %u\n\r", topit);
         };

         if (!input(HALL)) // znovuotoceni trubky dolu, kdyby ji vitr otocil
         {
            set_pwm1_duty(0);      // zastav topeni, aby byl odber do 1A
            dolu();
            set_pwm1_duty(topit);  // spust topeni
         }
      }; // pokracuj dal, kdyz prisel po RS232 znak


      uhel=getc();   // prijmi znak
      if ((uhel>='a') && (uhel<='k')) // nastaveni topeni [a..k]=(0..100%)
      {
         topit=uhel-'a';
         topit*=10;
         timer=500000;      // cca 11s

         // ochrana proti upeceni
         prevod();
         if(sign)
         {
            if ((teplota <= 5) && (topit > 60)) topit=0; // do -5°C se da topit maximalne na 60%
            printf("H %u;G -%Lu\n\r", topit, teplota); // zobraz hodnotu topeni (<H>eating)
         }
         else
         {
            if (teplota > 10) topit=0; // kdyz je vic jak +10°C, tak netopit
            if (topit > 40) topit=0; // pokud nemrzne, tak se neda topit vic jak na 40%
            printf("H %u;G %Lu\n\r", topit, teplota); // zobraz hodnotu topeni (<H>eating)
         }
         set_pwm1_duty(topit);      // spust topeni
         continue;
      };


      if ('m'==uhel) // standardni mereni ve trech polohach
      {
         prevod();     //jeden prevod na prazdno pro synchnonisaci

         j++;    // reverz, nahoru
         nula();

         printf("G");  // mereni teploty Zeme (<G>round)
         vystup();

         krok(15);
         printf(";S45");   // mereni teploty 45° nad obzorem
         vystup();
         krok(7);
         printf(";S90");   // mereni teploty v zenitu
         vystup();
         krok(7);
         printf(";S135");  // mereni teploty 45° nad obzorem na druhou stranu
         vystup();
         printf("\n\r");

         j++;     // reverz
         dolu();

         continue;
      }


      if ((uhel>='0') && (uhel<='@')) // mereni v pozadovanem uhlu [0..;]=(0..11)
      {
         uhel-='0';
      };

      if(uhel>11) continue;   // ochrana, abysme neukroutili draty

      printf("A %u;", uhel);  // zobraz pozadovany uhel (<A>ngle)

      prevod();               // jeden prevod na prazdno pro synchnonisaci

      j++;     // reverz, nahoru
      nula();

      printf("G");  // mereni teploty Zeme (<G>round)
      vystup();

      printf(";S");  // mereni teploty pozadovanym smerem do vesmiru (<S>pace)
      krok(12);      // odkrokuj do roviny
      for(i=0; i<uhel; i++) // dale odkrokuj podle pozadovaneho uhlu
      {
         krok(2);
      };
      vystup();
      printf("\n\r");

      j++;     // reverz
      dolu();
   }
}