/** ###################################################################
**     Filename  : Generator.C
**     Project   : Generator
**     Processor : MC9S08GT16ACFB
**     Version   : Driver 01.11
**     Compiler  : CodeWarrior HCS08 C Compiler
**     Date/Time : 18.3.2010, 21:33
**     Abstract  :
**         Main module.
**         This module contains user's application code.
**     Settings  :
**     Contents  :
**         No public methods
**
** ###################################################################*/
/* MODULE Generator */


/* Including needed modules to compile this module/procedure */
#include "Cpu.h"
#include "Events.h"
#include "Potvrzreni_in.h"
#include "Potvrzeni_out.h"
#include "Vystupni_port.h"
#include "Frekvence_filtr.h"
#include "DAC_ILE.h"
#include "EI2C2.h"
#include "Inhr3.h"
#include "Inhr4.h"
/* Include shared modules, which are used for whole project */
#include "PE_Types.h"
#include "PE_Error.h"
#include "PE_Const.h"
#include "IO_Map.h"
#define lowbyte(v)   ((unsigned char) (v))
#define highbyte(v)  ((unsigned char) (((unsigned int) (v)) >> 8))
/* User includes (#include below this line is not maintained by Processor Expert) */

                                ////////////////////////////////////////
                                //   deklarace globálních proměnných  //
                                ////////////////////////////////////////
                                
  float index_vzorku = 0;  //aktuální index vzorku, který se bude generovat v rozsahu 0 až 199
  float FSW1 = 131.072;    //proměnná FSW1, která se bude přičítat do generátoru adresy  (vložena testovací proměnná)       
  float cas1 = 0.095;      //doba, po kterou se nebude generovat signál příjde v sekundách  (vložena testovací proměnná)
  
  unsigned char prubeh[201] = {0,255,255,255,255,255,255,254,254,254,254,254,253,253,253,252,252,252,251,251,250,
                               250,249,249,248,248,247,247,246,245,245,244,243,243,242,241,241,240,239,238,238,
                               237,236,235,235,234,233,232,232,231,230,229,228,228,227,226,225,225,224,223,222,
                               222,221,220,219,219,218,217,217,216,215,215,214,213,213,212,212,211,211,210,210,
                               209,209,208,208,208,207,207,207,206,206,206,206,206,205,205,205,205,205,205,205,
                               205,205,205,205,205,205,206,206,206,206,206,207,207,207,208,208,208,209,209,210,
                               210,211,211,212,212,213,213,214,215,215,216,217,217,218,219,219,220,221,222,222,
                               223,224,225,225,226,227,228,228,229,230,231,232,232,233,234,235,235,236,237,238,
                               238,239,240,241,241,242,243,243,244,245,245,246,247,247,248,248,249,249,250,250,
                               251,251,252,252,252,253,253,253,254,254,254,254,254,255,255,255,255,255,255,255};
  unsigned char opakovani[201];                     //počet opakování jednoho vzorku ve výstupním signálu 
  unsigned char indexy [201];                       //indexy vzorků, které se generují za jednu periodu zvlnění signálu 
  unsigned char i;                                  //pomocný čítač
  unsigned int j;                                   //pomocný čítač 
  const unsigned long velikost_generatoru = 65536;  //2^16 - velikost 16-bitového generátoru long - 32 bitů potřebuju velikost číslo 65536 nenacpu do int
  unsigned int pocet_vzorku = 2000;                 //počet vzorků uložených v paměti
  float generator_adresy;                           //aktuální hodnota generátoru adresy - rovnou přečtení FSW1
  unsigned char counter=0;                          //pomocná proměnná      
  unsigned char modulo;                             //pomocná proměnná
  unsigned char pocet_period = 10;                  //pomocná proměnná = počet period zvlnění signálu
  unsigned char preddelicka;                        //proměnná pro nastavená Č/Č2 - bude počítat čas, po který se nebude generovat signál
  unsigned int celkove =0;                          //celkový počet neopakujících se vygenerovaných vzorků 
  unsigned char vzorek=0;                           //index aktuálního vzorku, který se bude gegerovat
  unsigned int  modulo_reg1;                        //proměnná pro nastavení modulo registrů Č/Č 1    
  float koeficienty1 []= {
   3.55893603855866e-06,-0.000468799405491670,0.0216171014818673,-0.375328468437791,0.434583974362179,45.2955578230740};//nejvyšší mocnina ^5 - první koeficient, pro interval <0.5;50> ms
  float koeficienty2 [] = {
  -2.88778306445705e-13,8.54430468755167e-10,-9.62919743306513e-07,0.000513369504514874,-0.129686717181200,13.4056066079768};//pro interval (50;950> ms
  float delka_impulzu = 3;                          //šířka impulzu pro nastavení mezní frekvence filtru 
  float fmez;                                       //mezní frekvence, na kterou se nastaví analogový filtr
  int zpozdeni;                                     //časová hodnota zoždění mezi prvky
  float del1 = 2;                                   //hodnota, kterou se budou vzorky dělit, pro zmenšení výsledného proudu
  long temp;
  extern char pocet_prijmu;
  extern long buffer;                           
  char k;                                                  //pomocné proměnné
 
                //////////////////////////////////////////////////////////////////////////////
                //   definice unie, která slouží pro překopírování hodnoty z long do float  //
                //////////////////////////////////////////////////////////////////////////////
 
 typedef union long_2_float {             //definice struktury UNION - slouží pro překopírování bitů z float do unsigned long (kdybych to udělal normálně překopíruje se zaokrouhlená hodnota)
    unsigned long uint;                  //32 bitové slovo  ve formátu unsigned long
    float         fp;                    //hodnota uložená v FP formátu na stejném místě paměti
}long_2_float;



                      /////////////////////////////////////////////////////////////////
                      //   funkce, která bitově překopíruje hodnotu z long do float  //
                      /////////////////////////////////////////////////////////////////
                
float sluc_float(unsigned long lng){
  float val;
  long_2_float lng32;                 //přiřazení jména
  lng32.uint=lng;                     //vložení vstupní proměnné do unie
  val = lng32.fp;                     //překopírování výstpuní proměnné z unie (ve formátu floating point)
  return val;}


                             //////////////////////////////////////////////////////
                             // podprogram vypočítávající mezní frekvenci filtru //
                             //////////////////////////////////////////////////////

float mezni_frekvence (float delka_impulzu){
  float frekvence;
  float nasobek = delka_impulzu;
  if (delka_impulzu>=0.5 & delka_impulzu<=50){          //polynom s koeficienty1 
    frekvence = koeficienty1[5];                        //přičtení nulté mocniny
    for (i=0;i<=4;i++){
      frekvence += (delka_impulzu * koeficienty1[4-i]);
      delka_impulzu = delka_impulzu * nasobek;          //v cyklu se vypočte funkční hodnota polynomu
    }
    if (frekvence>45)frekvence = 45;                    //maximální mezní frekvence filtru je 45 kHz (polynom je pouze aproximace, může vyjít více, než 45)
  return frekvence;                                     //funkce vrací hodnotu mezní frekvence
  } 
  else{
    frekvence = koeficienty2[5];
    for (i=0;i<=4;i++){
      frekvence += delka_impulzu * koeficienty2[4-i];
      delka_impulzu = delka_impulzu * nasobek;          //v cyklu se vypočte funkční hodnota polynomu
    }
  return frekvence;}                                    //funkce vrací hodnotu mezní frekvence
}
                                  
                                 //////////////////////////////////////////////
                                 // podprogram "zaokrouhlující" index_vzorku //
                                 ////////////////////////////////////////////// 
  
   unsigned char ceil1 (float hodnota)  
{                
                float desetinna_cast;     
                unsigned int cela_cast;
                cela_cast=(unsigned int)hodnota;      //celá část načteného indexu vzorku(převedení na int (rozsah int stačí) odstraní desetinnou část)*/
                desetinna_cast = hodnota - cela_cast; //desetinná část načteného indexu vzorku*/
          if (desetinna_cast !=0)                     //pokud je desetinná část různá od nuly (pokud je nula -> vstupní číslo bylo celé a není co zaokrouhlovat)
                hodnota = (unsigned int) hodnota+1;   //potřebuju zaokrouhlovat všechno nahoru (princip DDS) -> odsraním desetinnou část a pak přičtu 1          
                return hodnota;                       //funkce vrátí číslo zaokrouhlené nahoru
}   

                                 //////////////////////////////////////////
                                 // funkce inicializující I2C periférii  //
                                 ////////////////////////////////////////// 

                             
void I2C_init (void)
{
IICF_MULT = 0b00;  //nastavení MULT na 1
IICF_ICR =  0x0b;  //nastavení clock rate -> baud rate = 250 kbps a SDA hold time = 0,9 us
IICC_IICEN = 1;    //povolení IIC
IICC_IICIE = 1;    //povolení přerušení
IICC_MST = 0;      //slave mode
IICA = 0b11110010; //slave adresa
}

  
void main(void)
{
  /* Write your local variable definition here */

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  PE_low_level_init();
  /*** End of Processor Expert internal initialization.                    ***/
  
  //zakomentovaný úsek kódu -> příjem parametrů terapie po sběrnici I2C
   
  /*EI2C2_Enable();
  EI2C2_EnableEvent();
  I2C_init();               //inicializace I2C sběrnice 
  
  
  while(pocet_prijmu!=4);   //čekání na příchod první proměnné. Po přijetí se zavolá obsluha přerušení  EI2C2_OnRxChar
  //po dokončení cyklu byla 4x přijata data osmibitová data -> byl dokončen příjem první proměnné a ta je uložena v buffer
  FSW1 = sluc_float(buffer);  //převod do formátu float pomocí unie
  buffer = 0;                 //nulování proměnné buffer
  while(pocet_prijmu!=8);   //čekání na příchod druhé proměnné. Po přijetí se zavolá obsluha přerušení  EI2C2_OnRxChar
  del1 = sluc_float(buffer);
  buffer = 0;
  while(pocet_prijmu!=12);  //čekání na příchod třetí proměnné. Po přijetí se zavolá obsluha přerušení  EI2C2_OnRxChar
  cas1 = sluc_float(buffer);
                       //byl dokončen příjem řídicích proměnných po sběrnici I2C
                       
   */
  for (k=0;k<=201;k++)
  prubeh [k] = prubeh[k] /del1; //cyklus, ve které se vydělí všechny vzorky signálu pro snížení magnetické indukce v aplikátorech.
  cas1 = cas1/0.0001;                                       //převod sekund na stovky mikrosekund
  zpozdeni = (int)cas1;
  delka_impulzu = 1000/((FSW1*100000)/velikost_generatoru); //výpočet délky impulzu (v ms)
  fmez = 1/(mezni_frekvence(delka_impulzu)*100000);         //převod na periodu v s

  generator_adresy = FSW1;
  
    while (generator_adresy<=(float)(velikost_generatoru)/10) {                               //cyklus, který se bude vykonávat dokud nepřeteče generátor dělený hodnotou 10 - bude se generovat jedna perioda zvlnění (period je 10) 
                  index_vzorku = generator_adresy/((float)velikost_generatoru/pocet_vzorku);  //výpočet indexu vzorku = generátor/(2^16/2000) - float v závorce - aby se nezaokrouhloval výsledek
                  index_vzorku = ceil1(index_vzorku);                                    //zaokrouhlení indexu vzorku pokaždé nahoru
               
              if (index_vzorku==indexy[counter])opakovani[counter]++;                                               //podmínka pokud je nový index, na který ukazuje generátor stejný jako index v předchozím taktu 
                                                                        //na příslušné pozici v proměnné counter se inkrementuje hodnota - proměnná opakování říká kolikrát se za sebou opakuje jeden index (není započítaný první výskyt indexu)
                else{
                   counter++;                                                                 //pokud jsou indexy různé inkrementuj counter - byl vygenerován vzorek různý od předchozího 
                   indexy [counter]=index_vzorku;                                             //pokud byl předchozí index jiný na následující pozici v proměnné indexy se zapíše aktuální index vzorku
                    }
                  generator_adresy +=FSW1;                                                    //přičtení FSW ke generátoru adresy pro vygenerování dalšího vzorku
                                
    }
  
    for (i=0;i<=counter;i++)         //cyklus, který nahradí indexy konkrétními vzorky -> rychlejší vyčítání jednotlivých vzorků
    indexy[i]=prubeh[indexy[i]];
    indexy[0]=indexy[counter];      //na index nula se zapíše poslední generovaný vzorek - kvůli modulárnímu dělení při vyčítání
    
    
           //////////////////////////////////////////////////////////////////////////////////////////////                                                                                    
           //je dokončený výpočet vektoru generovaných vzorků, vektoru počtů opakování pro každý vzorek//
           //                mikrokontrolér je připraven ke generování impulzů                         //
           //////////////////////////////////////////////////////////////////////////////////////////////
           
           
                       
                       //generující mikrokontrolér potvrdí dokončení výpočtu řídícímu MCU a čekání na start generování
   
   modulo=counter;                   //counter nyní udává počet různých vzorků za jednu periodu zvlnění     
   celkove = pocet_period*modulo;    //výpočet celkového počtu různých vzorků za dobu trvání signálu
   Frekvence_filtr_SetPeriodReal(fmez);
   Frekvence_filtr_Enable();

   Potvrzeni_out_PutVal(1);       //potvrzení pro řídící MCU, že byl dokončen výpočet vzorků - ještě kouknou na nastavení na výstup         
   while (!Potvrzreni_in_GetVal());  //čekání na startovací pokyn od řídícího MCU - jednička na pinu 5 potru C - podle potřeby možno zaměnit za jiný
   DAC_ILE_SetVal();//nastavení DAC do režimu flow - through  - jednička na ILE - zbytek je uzemněný 

   
   
   
   while(1){                      //nekonečná smyčka
   
   
   /////////////////////////////////////////////////////////////////////////////////////////////////////
   //   Část, která vyčítá vzorky z paměti - vyčte se jedna perioda zvlnění a pak se kód 10x zopakuje.//
   //      Poté se na výstup pošle nula a spustí se Č/Č2, který odměří čas, kdy je na výstupu nula    // 
   /////////////////////////////////////////////////////////////////////////////////////////////////////   
   TPM1SC_CLKSA = 1;
   
   for (j=1;j<=celkove;){                                      //opakování 10x - počet period
           vzorek=j%modulo;                                    //pořadové číslo vzorku modulární dělení čítače počtem různých vzorků v periodě - generuje se jedna perioda dokola - potřbuju pořád vzorky pro první periodu
            PTAD = indexy[vzorek];                             //poslání vzorku na výstupní port
                   if (!opakovani[vzorek]==0){                 //pokud se vzorek alespoň jednou opakuje (v poli opakování na příslušné pozici není nula)
                       modulo_reg1=100*opakovani[vzorek]-45;   //nastavení modulo registru pro Č/Č1 - předělička=1, 100* - vzorky se generují s periodou 10us - 45 doba kterou trvá vygenerování dalšího vzorku po přetečení Č/Č2 .
                       TPM1MODL = lowbyte (modulo_reg1);
                       TPM1MODH = highbyte (modulo_reg1);
                       TPM1SC_TOF=0;                           //nulování ukazatele přetečení Č/Č1
                       TPM1CNTL = 0;                           //nulování počítacího registru Č/Č1
                       while(!TPM1SC_TOF);                     //stůj dokud nepřeteče čítač
                       asm nop;asm nop;                        //pomocné zpoždění, aby byl modulo registr dělitelný 5 (pokud není modulo regist dělitelný 5 přetéká až později např. v modulo registru je 99 a má přetéct při 100 - v dalším kroku simulátoru už je tam ale např. 104 a objeví se příznak přetečení - nevím, co se děje během těch pěti hodinových cyklů. Simulátor to krokuje moc hrubě - proto jsem to udělal takhle aby to v simulátoru sedělo)
                   }
                   else {
                   asm nop;asm nop;asm nop;asm nop;asm nop;asm nop;asm nop;asm nop;asm nop; // pomocné zpoždění pokud se vzorek neopakuje
                   }
                  j++;                                                                       //inkrementace counter - další různý index
        } 
          PTAD = 0;           //vyslání nuly na výsup po vygenerování jednoho impulzu
           
          Cpu_Delay100US(zpozdeni); //volání funkce, která realizuje potřebné zpoždění

   
  } 



  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;){}
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

/* END Generator */
/*
** ###################################################################
**
**     This file was created by Processor Expert 3.07 [04.34]
**     for the Freescale HCS08 series of microcontrollers.
**
** ###################################################################
*/
