//*****************************************************************************
//
// UARTCmds.c - Funkce pro zpracovani prikazu prijatych po UART
//
//*****************************************************************************

#include <common.h>
#include <uart.h>
#include <UARTCmds.h>
#include <EEPROMdriver.h>
#include "main.h"

// Promenne**********************
struct UARTData UARTComm;

//Definice funkci**************************************************************
//Stavovy automat pro prijem prikazu po UART----------------------------------
void RecieveSM(unsigned char RecByte)
{
  static unsigned char UART_Data_Count;
  
  switch(UARTComm.State)                  //Stavovy automat pro prijem ramce UART
    {
    case UART_STATE_IDLE:                 //Klidovy stav-------------------------
      {
        if(RecByte==UART_PREAM)           //Pokud je prijata spravna preambule
        {
          UARTComm.Preamble=RecByte;      //je ulozena do struktury
          UARTComm.State=UART_STATE_PREAM; //Nasledujici stav - prijem prikazu
          UARTComm.CompCRC=0;             //Smazani dosavadniho vypoctu CRC
        }
      break;
      }
    case UART_STATE_PREAM:                //Prijata preambule--------------------
      {
         if(RecByte<CMD_COUNT)              //Pokud je prikaz v rozsahu podporovanych prikazu
         {
            UARTComm.Cmd=RecByte;           //ulozi se prikaz do struktury
            UARTComm.CompCRC=RecByte;       //vypocet CRC
            UARTComm.State=UART_STATE_CMD;  //a prechazim do dalsiho stavu / prijem poctu datovych bytu
         }
         else if(RecByte==UART_PREAM)       //pokud neni spravne cislo prikazu, ale je shodny byte jako preambule
         {
           UARTComm.State=UART_STATE_PREAM;   //zustavam ve stavu, kdy je prijata preambule / muze byt zacatek ramce
         }
         else                               //pokud neni prijat ani spravny prikaz, ani preambule
         {
           UARTComm.State=UART_STATE_IDLE;  //provede se inicializace
           SensorWIM.CardState|=0x02;       //priznak chybneho/nepodporovaneho prikazu 
         }
      break;
      }
    case UART_STATE_CMD:                  //Prijat prikaz------------------------
      {
        if(RecByte<UART_MAX_COUNT)            //Pokud je pocet dat. bytu v podporovanem rozsahu
         {
          UARTComm.CompCRC^=RecByte;          //vypocet CRC
          UARTComm.Count=RecByte;             //ulozi se pocet dat.bytu do struktury
          if(UARTComm.Count>0){               //pokud budou nejake datove byty
            UARTComm.State=UART_STATE_COUNT;  //prechazim do dalsiho stavu / prijem datovych bytu
            UART_Data_Count=RecByte;          //ulozeni poctu datovych bytu pro jejich spravny prijem
          }
          else                                //pokud nejsou datove byty
            UARTComm.State=UART_STATE_DATA;   //preskakuji az na prijem CRC
         }
         else
         {
           UARTComm.State=UART_STATE_IDLE;    //pokud neni pocet ze spravneho rozsahu, inicializace
           SensorWIM.CardState|=0x04;         //Priznak chyby / prijat vetsi pocet dat.bytu, nez muze byt
         }
      break;
      }
    case UART_STATE_COUNT:                //Prijat poctu datovych bytu-----------
      {
        UARTComm.CompCRC^=RecByte;            //vypocet CRC
        UARTComm.Data[UARTComm.Count-UART_Data_Count--]=RecByte;  //ulozeni jednotlivych datovych bytu
        if(UART_Data_Count==0)                //pokud byl prijat posledni datovy byte
          UARTComm.State=UART_STATE_DATA;     //prechazim na prijem CRC
      break;
      }
    case UART_STATE_DATA:                 //Prijaty datove byty------------------
      {
        if(RecByte==UARTComm.CompCRC)       //Pokud je prijat stejny kontrolni soucet jako je vypocteny
        {
          UARTComm.CRC=RecByte;             //ulozeni prijateho kontrolniho souctu
          UARTComm.State=UART_STATE_CRC;    //prechazim do dalsiho stavu / prijem zakoncovaciho znaku
        }
        else
        {
          UARTComm.State=UART_STATE_IDLE;    //pokud neni shodny kontrolni soucet, inicializace
          SensorWIM.CardState|=0x01;         //Priznak chyby / nesouhlasi kontrolni soucet
        }
      break;
      }
    case UART_STATE_CRC:                  //Prijat kontrolni soucet--------------
      {
        if(RecByte=='\n')                     //pokud je prijat spravny zakoncovaci znak
        {        
          request.flag.uart_message_received=1; //Nastaveni priznaku prijateho ramce
          UARTComm.State=UART_STATE_PROCCESS;   //Nastaveni stavu, ze se zpracovava prikaz
        }
        else
        {
          UARTComm.State=UART_STATE_IDLE;    //pokud neni spravny zakoncovaci znak, inicializace
          SensorWIM.CardState|=0x08;          //Priznak chyby / jina chyba 
        }
      break;
      }
    case UART_STATE_PROCCESS:             //Provadeni prikazu----------------------
      {
                                            //Nove prijate znaky se neuvazuji..
      break;
      }
    default:                              //Pokud jiny stav, vse zahazuji a znova---
      {
        UARTComm.State=UART_STATE_IDLE;
        SensorWIM.CardState|=0x08;          //Priznak chyby / jina chyba 
      }
    }
}

//zpracovani prijate zpravy--------------------------------------------------
void UARTProcessCmd(void)
{
  
    switch(UARTComm.Cmd)                        //rozliseni pozadovaneho prikazu
    {
      case UART_CMD_RD_STATE:                   //prikaz 0 - stav prevodnikove karty
        {
          UARTCmd_00();                         
          break;
        }
      case UART_CMD_OPT:                        //prikaz 1 - cteni hodnoty z AD prevodniku ze zvoleneho kanalu
        {
          UARTCmd_01();
          break;
        }
      case UART_CMD_TEMP:                       //prikaz 2 - cteni teploty na DPS
        {
          UARTCmd_02();
          break;
        }
      case UART_CMD_WR_EEPROM:                  //prikaz 3 - zapis dat do EEPROM
        {
          UARTCmd_03();
          break;
        }
      case UART_CMD_RD_EEPROM:                  //prikaz 4 - cteni z EEPROM
        {
          UARTCmd_04();
          break;
        }
      default:                                  //Nepodporovany prikaz
        {
           //Nedelam nic / spatne cislo prikazu / nemelo by nastat
          UARTComm.State=UART_STATE_IDLE;
        }
    }
  
    if(UARTComm.State!= UART_STATE_IDLE)        //pokud nenastala chyba pri vykonavani prikazu
    {
      UARTComm.State=UART_STATE_TX_PREAM;       //nastaveni stavoveho automatu na vysilani prvni casti / preambule
       SendReply();                             //odeslani odpovedi
    }
}

//Odeslani odpovedi na prikaz---------------------------------------------------
void SendReply(void)                                    
{
  unsigned char ByteToSend;
  static volatile unsigned char SendCount;
  
   while(UARTComm.State!=UART_STATE_IDLE)                   //Dokud neni odeslan cely ramec
   {
     switch(UARTComm.State)                                 //zjisteni aktualni pozice v ramci
     {
       case UART_STATE_TX_PREAM:                            //odesilani preambule
         {
            ByteToSend=UARTComm.Preamble;
            UARTComm.State=UART_STATE_TX_CMD;
            break;
         }
        case UART_STATE_TX_CMD:                             //odesilani identifikatoru prikazu
         {
            ByteToSend=UARTComm.Cmd;
            UARTComm.State=UART_STATE_TX_COUNT; 
            UARTComm.CompCRC=ByteToSend;
            break;
         } 
        case UART_STATE_TX_COUNT:                           //odeslani poctu datovych bytu
         {
            ByteToSend=UARTComm.Count;
            SendCount=UARTComm.Count;
            UARTComm.State= (UARTComm.Count>0 ? UART_STATE_TX_DATA : UART_STATE_TX_CRC);  //pokud nejsou data, odeslani CRC, jinak data
            UARTComm.CompCRC^=ByteToSend;
            break;
         }
       case UART_STATE_TX_DATA:                             //odesilani jednotlivych datovych bytu
         {
            ByteToSend=UARTComm.Data[UARTComm.Count-SendCount];
            UARTComm.CompCRC^=ByteToSend;
            if(--SendCount==0)                              //pokud jiz nejsou dalsi datove byty k odeslani
              UARTComm.State=UART_STATE_TX_CRC;             
            break;
         }
       case UART_STATE_TX_CRC:                              //odeslani vypocteneho CRC
         {
            ByteToSend=UARTComm.CompCRC;
            UARTComm.State=UART_STATE_TX_END;
            break;
         }
       case UART_STATE_TX_END:                              //odeslani zakoncovaciho znaku
         {
            ByteToSend='\n';
            UARTComm.State=UART_STATE_TX_DONE;
            break;
         }
        default:                                            //pokud nastane chyba, nastaveni vychoziho stavu
          {
            UARTComm.State=UART_STATE_IDLE;
          }
     }
     if(UARTComm.State!=UART_STATE_IDLE)                    //pokud nenastala chyba, odeslu danou cast ramce
     {
        UARTCharPutNonBlocking(UART0_BASE,ByteToSend);
        if(UARTComm.State==UART_STATE_TX_DONE)              //jesli byla odeslana posledni cast ramce, inicializace stav.automatu
          UARTComm.State=UART_STATE_IDLE;
     }
   }
}

//Prikaz 0 - cteni stavu karty--------------------------------------------------
void UARTCmd_00(void)
{
    UARTComm.Count=1;                                                           //Jeden datovy byte
    UARTComm.Data[0]=SensorWIM.CardState;                                       //Jen pro demonstraci vracim 0 / stav OK
    SensorWIM.CardState=0x00;                                                   //jakmile probehne dotaz na stav karty, smazou se stare stavy
}

//Prikaz 1 - ziskani hodnoty z AD prevodniku------------------------------------
void UARTCmd_01(void)
{
  
  unsigned char *pChar=(unsigned char *)&SensorWIM.ADCValue[UARTComm.Data[0]];  //ukazatel na aktualni ADCvalue na zvolenem kanalu
  
  UARTComm.Count=2;                                                             //odesilaji se 2datove byty ADCValue
  UARTComm.Data[0]=*pChar++;
  UARTComm.Data[1]=*pChar; 
  
}

//Prikaz 2 - ziskani hodnoty teploty merene na karte----------------------------
void UARTCmd_02(void)
{
  unsigned char *pChar=(unsigned char *)&SensorWIM.Temperature;                 //ukazatel na aktualni teplotu
  
  UARTComm.Count=4;                                                             //v odpovedi budou 4 byty / float teplota
  UARTComm.Data[0]=*pChar++;
  UARTComm.Data[1]=*pChar++; 
  UARTComm.Data[2]=*pChar++;
  UARTComm.Data[3]=*pChar; 
}

//Prikaz 3 - zapis konfigurace karty do EEPROM----------------------------------
void UARTCmd_03(void)
{
  if((UARTComm.Data[1]>0)&&(UARTComm.Data[1]<UART_MAX_COUNT))                 //testovani poctu datovych bytu
  {
    EEPROMWrite(UARTComm.Data[0], &UARTComm.Data[2], UARTComm.Data[1]);       //zapsani pozadovanych dat do EEPROM
    UARTComm.Count=0;                                                         //v odpovedi nejsou zadne data
  }
  else                                                                        //pokud neni pocet dat.bytu v rozsahu
  {
    UARTComm.State=UART_STATE_IDLE;                                           //neprovadi se zapis a zadna odpoved
  }
}

//Prikaz 4 - cteni konfigurace karty z EEPROM-----------------------------------
void UARTCmd_04(void)
{
  if((UARTComm.Data[1]>0)&&(UARTComm.Data[1]<UART_MAX_COUNT))                     //testovani poctu datovych bytu
  {
    UARTComm.Count=UARTComm.Data[1];                                            //ulozeni poctu odesilanych bytu
    EEPROMRead(UARTComm.Data[0], UARTComm.Data, UARTComm.Data[1]);              //cteni pozadovanych dat z EEPROM
  }
  else                                                                          //pokud neni pocet dat.bytu v rozsahu
  {
    UARTComm.State=UART_STATE_IDLE;                                             //neprovadi se cteni a zadna odpoved
  }
 
}