EasyCAT source codes

#ifndef ABT_EasyCAT_H
#define ABT_EasyCAT_H

#include <Arduino.h> 
#include <SPI.h> 


//---- AB&T EasyCAT library V_1.4 -----------------------------------------------------------------	
//
// AB&T Tecnologie Informatiche - Ivrea Italy
// http://www.bausano.net
// https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm
//
// This library has been tested with Arduino IDE 1.6.8
// https://www.arduino.cc



//****** configuration parameters *****************************************************************

 #define SPI_fast_transfer                 // enable fast SPI transfert (default)
 #define SPI_fast_SS                       // enable fast SPI chip select management (default)
 

//*************************************************************************************************


//---- LAN9252 registers --------------------------------------------------------------------------

                                            //---- access to EtherCAT registers -------------------

#define ECAT_CSR_DATA           0x0300      // EtherCAT CSR Interface Data Register
#define ECAT_CSR_CMD            0x0304      // EtherCAT CSR Interface Command Register


                                            //---- access to EtherCAT process RAM ----------------- 

#define ECAT_PRAM_RD_ADDR_LEN   0x0308      // EtherCAT Process RAM Read Address and Length Register
#define ECAT_PRAM_RD_CMD        0x030C      // EtherCAT Process RAM Read Command Register
#define ECAT_PRAM_WR_ADDR_LEN   0x0310      // EtherCAT Process RAM Write Address and Length Register 
#define ECAT_PRAM_WR_CMD        0x0314      // EtherCAT Process RAM Write Command Register

#define ECAT_PRAM_RD_DATA       0x0000      // EtherCAT Process RAM Read Data FIFO
#define ECAT_PRAM_WR_DATA       0x0020      // EtherCAT Process RAM Write Data FIFO

                                            //---- EtherCAT registers -----------------------------
                                            
#define AL_STATUS               0x0130      // AL status
#define WDOG_STATUS             0x0440      // watch dog status


                                            //---- LAN9252 registers ------------------------------    

#define HW_CFG                  0x0074      // hardware configuration register
#define BYTE_TEST               0x0064      // byte order test register
#define RESET_CTL               0x01F8      // reset register       
#define ID_REV                  0x0050      // chip ID and revision


//---- LAN9252 flags ------------------------------------------------------------------------------

#define ECAT_CSR_BUSY     0x80
#define PRAM_READ_BUSY    0x80
#define PRAM_READ_AVAIL   0x01
#define PRAM_WRITE_AVAIL  0x01
#define READY             0x08000000

#define DIGITAL_RST       0x00000001
#define ETHERCAT_RST      0x00000040


//---- EtherCAT flags -----------------------------------------------------------------------------

                                                      // EtherCAT state machine 
                                                      
#define ESM_INIT                0x01                  // init
#define ESM_PREOP               0x02                  // pre-operational
#define ESM_BOOT                0x03                  // bootstrap
#define ESM_SAFEOP              0x04                  // safe-operational
#define ESM_OP                  0x08                  // operational


//--- ESC commands --------------------------------------------------------------------------------

#define ESC_WRITE 		   0x80
#define ESC_READ 		     0xC0


//---- SPI ----------------------------------------------------------------------------------------

#define COMM_SPI_READ    0x03
#define COMM_SPI_WRITE   0x02

#define DUMMY_BYTE       0xFF



#if defined(ARDUINO_ARCH_AVR)  
  #define SpiSpeed         8000000
  
#elif defined (ARDUINO_ARCH_SAM)
  #define SpiSpeed        14000000 
  
#elif defined (ARDUINO_ARCH_SAMD)
  #define SpiSpeed        12000000   
  
#else  
  #define SpiSpeed        8000000    
#endif


  
  
//---- typedef ------------------------------------------------------------------------------------

typedef union
{
    unsigned short  Word;
    unsigned char   Byte[2];
} UWORD;

typedef union
{
    unsigned long   Long;
    unsigned short  Word[2];
    unsigned char   Byte[4];
} ULONG;

typedef union
{
  unsigned char Byte [32];
  unsigned long Long [8];      
} PROCBUFFER;


//-------------------------------------------------------------------------------------------------
 
class EasyCAT 
{
  public:
    EasyCAT(unsigned char SPI_CHIP_SELECT); // constructor
    EasyCAT();                              // default constructor

    
    unsigned char MainTask();               // EtherCAT main task
                                            // must be called cyclically by the application 
    
    bool Init();                            // EasyCAT board initialization 
    
    PROCBUFFER BufferOut;                   // output process data buffer 
    PROCBUFFER BufferIn;                    // input process data buffer
    
    
  private:
    void          SPIWriteRegisterDirect   (unsigned short Address, unsigned long DataOut);
    unsigned long SPIReadRegisterDirect    (unsigned short Address, unsigned char Len);
    
    void          SPIWriteRegisterIndirect (unsigned long  DataOut, unsigned short Address);
    unsigned long SPIReadRegisterIndirect  (unsigned short Address, unsigned char Len); 
    
    void          SPIReadProcRamFifo();    
    void          SPIWriteProcRamFifo();  
    
    unsigned char SCS; 

    #if defined(ARDUINO_ARCH_SAM)    
      Pio* pPort_SCS; 
      uint32_t Bit_SCS;      
    #endif

    #if defined(ARDUINO_ARCH_SAMD)    
      EPortType Port_SCS;
      uint32_t Bit_SCS;       
    #endif    
    
    #if defined(ARDUINO_ARCH_AVR)    
      unsigned char Mask_SCS;
      unsigned char Port_SCS;
      volatile uint8_t* pPort_SCS;       
    #endif        
    
 
 
 //----- fast SPI chip select management ----------------------------------------------------------
 
    #if defined SPI_fast_SS 

      #if defined(ARDUINO_ARCH_AVR)                   // -- AVR architecture (Uno - Mega) ---------
        #define SCS_Low_macro      *pPort_SCS &= ~(Mask_SCS);
        #define SCS_High_macro     *pPort_SCS |=  (Mask_SCS); 
          
      //#elif defined(ARDUINO_ARCH_SAMD)                //--- SAMD architecture (Zero) --------------
      //  #define SCS_Low_macro      PORT->Group[Port_SCS].OUTCLR.reg = (1<<Bit_SCS);
      //  #define SCS_High_macro     PORT->Group[Port_SCS].OUTSET.reg = (1<<Bit_SCS);
        
      #elif defined(ARDUINO_ARCH_SAM)                 //---- SAM architecture (Due) ---------------
      	#define SCS_Low_macro      pPort_SCS->PIO_CODR = Bit_SCS;
        #define SCS_High_macro     pPort_SCS->PIO_SODR = Bit_SCS;

      #else                                    //-- standard management for others architectures -- 
        #define SCS_Low_macro      digitalWrite(SCS, LOW);
        #define SCS_High_macro     digitalWrite(SCS, HIGH);        

      #endif    
  
  
 //----- standard SPI chip select management ------------------------------------------------------

    #else     
      #define SCS_Low_macro     digitalWrite(SCS, LOW);
      #define SCS_High_macro    digitalWrite(SCS, HIGH);  
    #endif  
     
//-------------------------------------------------------------------------------------------------    
    
    
    
    
//----- fast SPI transfert ------------------------------------------------------------------------
    
  #if defined SPI_fast_transfer      

    #if defined(ARDUINO_ARCH_AVR)                     // -- AVR architecture (Uno - Mega) ---------

      inline static void SPI_TransferTx(unsigned char Data) {                             \
                                                            SPDR = Data;                  \
                                                            asm volatile("nop");        
                                                            while (!(SPSR & _BV(SPIF))) ; \
                                                            };               
          
      inline static void SPI_TransferTxLast(unsigned char Data) {                         \
                                                            SPDR = Data;                  \
                                                            asm volatile("nop");                                                                        
                                                            while (!(SPSR & _BV(SPIF))) ; \
                                                            };         
       
      inline static unsigned char SPI_TransferRx(unsigned char Data) {                      \
                                                              SPDR = Data;                  \
                                                              asm volatile("nop");          
                                                              while (!(SPSR & _BV(SPIF))) ; \
                                                              return SPDR; };    
      
    #elif defined(ARDUINO_ARCH_SAMD)                    //--- SAMD architecture (Zero) --------------
     
      inline static void SPI_TransferTx (unsigned char Data){                                     \
                                                    while(SERCOM4->SPI.INTFLAG.bit.DRE == 0){};   \
                                                    SERCOM4->SPI.DATA.bit.DATA = Data;}; 
                                                     
      inline static void SPI_TransferTxLast(unsigned char Data){                                  \
                                                    while(SERCOM4->SPI.INTFLAG.bit.DRE == 0){};   \
                                                    SERCOM4->SPI.DATA.bit.DATA = Data;            \
                                                    while(SERCOM4->SPI.INTFLAG.bit.TXC == 0){};};                                                      
                                                                  
      inline static unsigned char SPI_TransferRx (unsigned char Data){                                \
                                                    unsigned char Dummy = SERCOM4->SPI.DATA.bit.DATA; \
                                                    while(SERCOM4->SPI.INTFLAG.bit.DRE == 0){};       \
                                                    SERCOM4->SPI.DATA.bit.DATA = Data;                \
                                                    while(SERCOM4->SPI.INTFLAG.bit.RXC == 0){};       \
                                                    return SERCOM4->SPI.DATA.bit.DATA;};              \
                                                                                                     
    #elif defined(ARDUINO_ARCH_SAM)                   //---- SAM architecture (Due) ---------------   
                                                      // TODO! currently standard transfert is used  
       
        inline static void SPI_TransferTx          (unsigned char Data) {SPI.transfer(Data); };    
        inline static void SPI_TransferTxLast      (unsigned char Data) {SPI.transfer(Data); }; 
        inline static unsigned char SPI_TransferRx (unsigned char Data) {return SPI.transfer(Data); };        
       
       
    #else                                             //-- standard transfert for others architectures
    
      inline static void SPI_TransferTx            (unsigned char Data) {SPI.transfer(Data); };    
      inline static void SPI_TransferTxLast        (unsigned char Data) {SPI.transfer(Data); }; 
      inline static unsigned char SPI_TransferRx   (unsigned char Data) {return SPI.transfer(Data); }; 
 
    #endif        
      
//---- standard SPI transfert ---------------------------------------------------------------------  

  #else                              
      inline static void SPI_TransferTx          (unsigned char Data) {SPI.transfer(Data); };    
      inline static void SPI_TransferTxLast      (unsigned char Data) {SPI.transfer(Data); }; 
      inline static unsigned char SPI_TransferRx (unsigned char Data) {return SPI.transfer(Data); };         
  #endif       
 
//---------------------------------------------------------------------------------------- 
   
};
 
 
  #endif
#include "EasyCAT.h"                         
#include <SPI.h> 

  
//---- AB&T EasyCAT library V_1.4 -----------------------------------------------------------------	
//
// AB&T Tecnologie Informatiche - Ivrea Italy
// http://www.bausano.net
// https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm
//
// This library has been tested with Arduino IDE 1.6.8
// https://www.arduino.cc

//--- V_1.4 ---
//
// The MainTask function now return the state of the 
// Ethercat State machine and of the Wachdog
//
// Now the SPI chip select is initialized High inside the constructor


//--- V_1.3 --- 
// Replaced delay(100) in Init() function with a wait loop 
//
//
//--- V_1.2 --- 
// SPI chip select is configured by the application, setting a constructor parameter.
// If no chip select is declared in the constructor, pin 9 will be used as default.  
// Code cleaning.
// Comments in english.
// TODO: fast SPI transfert for DUE board
//
//
//--- V_1.1 --- 
// First official release.
// SPI chip select is configured editing the library ".h" file.


    
//---- constructor --------------------------------------------------------------------------------

EasyCAT::EasyCAT(unsigned char SPI_CHIP_SELECT) //------- SPI_CHIP_SELECT options -----------------
                                                //
                                                // for EasyCAT board REV_A we can choose between:
                                                // 8, 9, 10
                                                //  
                                                // for EasyCAT board REV_B we have three additional options:
                                                // A5, 6, 7 

{                                       
  SCS = (unsigned char)SPI_CHIP_SELECT;         //  initialize chip select  
  digitalWrite (SCS, HIGH);                     //    
}
 
 
EasyCAT::EasyCAT()                              //------- default constructor ---------------------- 
{                                               //                               
  SCS = 9;                                      // if no chip select is declared, default is pin 9 
  digitalWrite (SCS, HIGH);                     // initialize chip select     
}                                               //

  
//---- EasyCAT board initialization ---------------------------------------------------------------

bool EasyCAT::Init()
{
  ULONG TempLong;

  SPI.begin();

  
  #if defined(ARDUINO_ARCH_SAMD)                          // calculate the microcontroller port and
    Bit_SCS = g_APinDescription[SCS].ulPin;               // pin for fast SPI chip select management     
    Port_SCS = g_APinDescription[SCS].ulPort;             //                                           
  #endif                                                  //  
                                                          //  
  #if defined(ARDUINO_ARCH_SAM)                           //    
    Bit_SCS = g_APinDescription[SCS].ulPin;               //    
    pPort_SCS = g_APinDescription[SCS].pPort;             //  
  #endif                                                  //
                                                          //
  #if defined(ARDUINO_ARCH_AVR)                           //
    Mask_SCS = (digitalPinToBitMask(SCS));                //  
    Port_SCS = digitalPinToPort(SCS);                     //
    pPort_SCS = portOutputRegister(Port_SCS);             //     
  #endif                                                  //
    
  digitalWrite(SCS, HIGH);
  pinMode(SCS, OUTPUT);   
  
  SPI.beginTransaction(SPISettings(SpiSpeed, MSBFIRST, SPI_MODE0)); // set SPI parameters
 
  SPIWriteRegisterDirect (RESET_CTL, (DIGITAL_RST & ETHERCAT_RST)); // LAN9252 reset
  
  //delay (100);                                                      // wait 100mS 
  for (unsigned int i=0; i<50000; i++)
  {
	digitalWrite(SCS, HIGH);
  }
  
  TempLong.Long = SPIReadRegisterDirect (BYTE_TEST, 4);             // read test register  
  
  if (TempLong.Long == 0x87654321)                                  // if the test register is ok 
  {                                                                 // check also the READY flag
    TempLong.Long = SPIReadRegisterDirect (HW_CFG, 4);              //    
     if (TempLong.Long & READY)                                     //
     {                                                              //
        SPI.endTransaction();                                       // if both are ok
        return true;                                                // initalization completed    
     }
   }
     
  SPI.endTransaction();                                             // 
  SPI.end();                                                        // otherwise                                                                      //
  return false;                                                     // initialization failed           
};  


//---- EtherCAT task ------------------------------------------------------------------------------

unsigned char EasyCAT::MainTask()                           // must be called cyclically by the application

{
  bool WatchDog = 0;
  bool Operational = 0; 
  unsigned char i;
  ULONG TempLong; 
  unsigned char Status;  
                                                            // set SPI parameters
  SPI.beginTransaction(SPISettings(SpiSpeed, MSBFIRST, SPI_MODE0)); 
 
  
  TempLong.Long = SPIReadRegisterIndirect (WDOG_STATUS, 1); // read watchdog status
  if ((TempLong.Byte[0] & 0x01) == 0x01)                    //
    WatchDog = 0;                                           // set/reset the corrisponding flag
  else                                                      //
    WatchDog = 1;                                           //
    
  TempLong.Long = SPIReadRegisterIndirect (AL_STATUS, 1);   // read the EtherCAT State Machine status
  Status = TempLong.Byte[0] & 0x0F;                         //
  if (Status == ESM_OP)                                     // to see if we are in operational state
    Operational = 1;                                        //
  else                                                      // set/reset the corrisponding flag
    Operational = 0;                                        //    


                                                            //--- process data transfert ----------
                                                            //                                                        
  if (WatchDog | !Operational)                              // if watchdog is active or we are 
  {                                                         // not in operational state, reset 
    for (i=0; i<4; i++)                                     // the output buffer
    BufferOut.Long[i] = 0;                                  //

/*                                                          // debug
    if (!Operational)                                       //
      Serial.println("Not operational");                    //
    if (WatchDog)                                           //    
      Serial.println("WatchDog");                           //  
*/                                                          //
   
  }
  
  else                                                      
  {                                                         
    SPIReadProcRamFifo();                                   // otherwise transfer process data from 
  }                                                         // the EtherCAT core to the output buffer  

  SPIWriteProcRamFifo();                                    // we always transfer process data from
                                                            // the input buffer to the EtherCAT core  
                                                            
  SPI.endTransaction();                                     //

  if (WatchDog)                                             // return the status of the State Machine      
  {                                                         // and of the watchdog
    Status |= 0x80;                                         //
  }                                                         //
  return Status;                                            //  
  
}

    
//---- read a directly addressable registers  -----------------------------------------------------

unsigned long EasyCAT::SPIReadRegisterDirect (unsigned short Address, unsigned char Len)

                                                   // Address = register to read
                                                   // Len = number of bytes to read (1,2,3,4)
                                                   //
                                                   // a long is returned but only the requested bytes
                                                   // are meaningful, starting from LsByte                                                 
{
  ULONG Result; 
  UWORD Addr;
  Addr.Word = Address; 
  unsigned char i; 
  
  SCS_Low_macro                                             // SPI chip select enable

  SPI_TransferTx(COMM_SPI_READ);                            // SPI read command
  SPI_TransferTx(Addr.Byte[1]);                             // address of the register
  SPI_TransferTxLast(Addr.Byte[0]);                         // to read, MsByte first
 
  for (i=0; i<Len; i++)                                     // read the requested number of bytes
  {                                                         // LsByte first 
    Result.Byte[i] = SPI_TransferRx(DUMMY_BYTE);            //
  }                                                         //    
  
  SCS_High_macro                                            // SPI chip select disable 
 
  return Result.Long;                                       // return the result
}


//---- write a directly addressable registers  ----------------------------------------------------

void EasyCAT::SPIWriteRegisterDirect (unsigned short Address, unsigned long DataOut)

                                                   // Address = register to write
                                                   // DataOut = data to write
{ 
  ULONG Data; 
  UWORD Addr;
  Addr.Word = Address;
  Data.Long = DataOut;    

  SCS_Low_macro                                             // SPI chip select enable  
  
  SPI_TransferTx(COMM_SPI_WRITE);                           // SPI write command
  SPI_TransferTx(Addr.Byte[1]);                             // address of the register
  SPI_TransferTx(Addr.Byte[0]);                             // to write MsByte first

  SPI_TransferTx(Data.Byte[0]);                             // data to write 
  SPI_TransferTx(Data.Byte[1]);                             // LsByte first
  SPI_TransferTx(Data.Byte[2]);                             //
  SPI_TransferTxLast(Data.Byte[3]);                         //
 
  SCS_High_macro                                            // SPI chip select enable   
}


//---- read an undirectly addressable registers  --------------------------------------------------

unsigned long EasyCAT::SPIReadRegisterIndirect (unsigned short Address, unsigned char Len)

                                                   // Address = register to read
                                                   // Len = number of bytes to read (1,2,3,4)
                                                   //
                                                   // a long is returned but only the requested bytes
                                                   // are meaningful, starting from LsByte                                                  
{
  ULONG TempLong;
  UWORD Addr;
  Addr.Word = Address;
                                                            // compose the command
                                                            //
  TempLong.Byte[0] = Addr.Byte[0];                          // address of the register
  TempLong.Byte[1] = Addr.Byte[1];                          // to read, LsByte first
  TempLong.Byte[2] = Len;                                   // number of bytes to read
  TempLong.Byte[3] = ESC_READ;                              // ESC read 

  SPIWriteRegisterDirect (ECAT_CSR_CMD, TempLong.Long);     // write the command

  do
  {                                                         // wait for command execution
    TempLong.Long = SPIReadRegisterDirect(ECAT_CSR_CMD,4);  //
  }                                                         //
  while(TempLong.Byte[3] & ECAT_CSR_BUSY);                  //
                                                             
                                                              
  TempLong.Long = SPIReadRegisterDirect(ECAT_CSR_DATA,Len); // read the requested register
  return TempLong.Long;                                     //
}


//---- write an undirectly addressable registers  -------------------------------------------------

void  EasyCAT::SPIWriteRegisterIndirect (unsigned long DataOut, unsigned short Address)

                                                   // Address = register to write
                                                   // DataOut = data to write                                                    
{
  ULONG TempLong;
  UWORD Addr;
  Addr.Word = Address;


  SPIWriteRegisterDirect (ECAT_CSR_DATA, DataOut);            // write the data

                                                              // compose the command
                                                              //                                
  TempLong.Byte[0] = Addr.Byte[0];                            // address of the register  
  TempLong.Byte[1] = Addr.Byte[1];                            // to write, LsByte first
  TempLong.Byte[2] = 4;                                       // we write always 4 bytes
  TempLong.Byte[3] = ESC_WRITE;                               // ESC write

  SPIWriteRegisterDirect (ECAT_CSR_CMD, TempLong.Long);       // write the command

  do                                                          // wait for command execution
  {                                                           //
    TempLong.Long = SPIReadRegisterDirect (ECAT_CSR_CMD, 4);  //  
  }                                                           //  
  while (TempLong.Byte[3] & ECAT_CSR_BUSY);                   //
  
}


//---- read from process ram fifo ----------------------------------------------------------------

void EasyCAT::SPIReadProcRamFifo()    // read 32 bytes from the output process ram, through the fifo
                                      //        
                                      // these are the bytes received from the EtherCAT master and
                                      // that will be use by our application to write the outputs
{
  ULONG TempLong;
  unsigned char i;
  
  SPIWriteRegisterDirect (ECAT_PRAM_RD_ADDR_LEN, 0x00201000);   // we always read 32 bytes   0x0020----
                                                                // output process ram offset 0x----1000
                                                                
  SPIWriteRegisterDirect (ECAT_PRAM_RD_CMD, 0x80000000);        // start command                                                                  
                                                                                                                               
  do                                                            // wait for data to be transferred      
  {                                                             // from the output process ram 
    TempLong.Long = SPIReadRegisterDirect (ECAT_PRAM_RD_CMD,4); // to the read fifo 
  }                                                             //    
  while (!(TempLong.Byte[0] & PRAM_READ_AVAIL) || (TempLong.Byte[1] != 8));     
  
 
  SCS_Low_macro                                                 // SPI chip select enable  
  
  SPI_TransferTx(COMM_SPI_READ);                                // SPI read command
  SPI_TransferTx(0x00);                                         // address of the read  
  SPI_TransferTxLast(0x00);                                     // fifo MsByte first
  

  for (i=0; i<32; i++)                                          // 32 bytes read loop 
  {                                                             // 
    BufferOut.Byte[i] = SPI_TransferRx(DUMMY_BYTE);             //
  }                                                             //
    
  SCS_High_macro                                                // SPI chip select disable    
}


//---- write to the process ram fifo --------------------------------------------------------------

void EasyCAT::SPIWriteProcRamFifo()    // write 32 bytes to the input process ram, through the fifo
                                       //    
                                       // these are the bytes that we have read from the inputs of our                   
                                       // application and that will be sent to the EtherCAT master
{
  ULONG TempLong;
  unsigned char i;

  SPIWriteRegisterDirect (ECAT_PRAM_WR_ADDR_LEN, 0x00201200);   // we always write 32 bytes 0x0020----
                                                                // input process ram offset 0x----1200

  SPIWriteRegisterDirect (ECAT_PRAM_WR_CMD, 0x80000000);        // start command  

  do                                                            // check fifo has available space     
  {                                                             // for data to be written
    TempLong.Long = SPIReadRegisterDirect (ECAT_PRAM_WR_CMD,4); //  
  }                                                             //    
  while (!(TempLong.Byte[0] & PRAM_WRITE_AVAIL) || (TempLong.Byte[1] < 8) );             
  
  
  SCS_Low_macro                                                 // enable SPI chip select
  
  SPI_TransferTx(COMM_SPI_WRITE);                               // SPI write command
  SPI_TransferTx(0x00);                                         // address of the write fifo 
  SPI_TransferTx(0x20);                                         // MsByte first 

  for (i=0; i<31; i++)                                          // 32 bytes write loop
  {                                                             //
    SPI_TransferTx (BufferIn.Byte[i]);                          // 
  }                                                             //
                                                                //  
  SPI_TransferTxLast (BufferIn.Byte[31]);                       //
  
  SCS_High_macro                                                // disable SPI chip select      
}
//---- AB&T EasyCAT shield application example ------------------------------------------------------------------  
//
//
// AB&T Tecnologie Informatiche - Ivrea Italy
// http://www.bausano.net
// https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm
//





#include "EasyCAT.h"                // EasyCAT library to interface the LAN9252
#include <SPI.h>                    // SPI library

 
EasyCAT EASYCAT;                    // EasyCAT istantiation

                                    // The constructor allow us to choose the pin used for the EasyCAT SPI chip select 
                                    // Without any parameter pin 9 will be used 
                                                                      
                                    // for EasyCAT board REV_A we can choose between:
                                    // 8, 9, 10 
                                    //  
                                    // for EasyCAT board REV_B we can choose between:
                                    // 8, 9, 10, A5, 6, 7                                    

                                    // example:                                  
//EasyCAT EASYCAT(8);               // pin 8 will be used as SPI chip select


                                    // The chip select chosen by the firmware must match the setting on the board

                                    // On board REV_A the chip select is set soldering
                                    // a 0 ohm resistor in the appropriate position

                                    // On board REV_B the chip select is set
                                    // througt a bank of jumpers                                    



//---- pins declaration ------------------------------------------------------------------------------

const int Ana0 = A0;                // analog input 0
const int Ana1 = A1;                // analog input 1

const int BitOut0 = A2;             // digital output bit 0
const int BitOut1 = A3;             // digital output bit 1
const int BitOut2 = A4;             // digital output bit 2
const int BitOut3 = A5;             // digital output bit 3

const int BitIn0 = 3;               // digital input  bit 0
const int BitIn1 = 5;               // digital input  bit 1
const int BitIn2 = 6;               // digital input  bit 2
const int BitIn3 = 7;               // digital input  bit 3



//---- global variables ---------------------------------------------------------------------------


UWORD ContaUp;                      // used for sawthoot test generation
UWORD ContaDown;                    //

unsigned long Millis = 0;
unsigned long PreviousSaw = 0;
unsigned long PreviousCycle = 0;

//---- setup ---------------------------------------------------------------------------------------
 
void setup()
{
  Serial.begin(9600);                                             // serial line initialization
                                                                  //(used only for debug)
           
  Serial.print ("\nEasyCAT - Generic EtherCAT slave\n");          // print the banner

  pinMode(BitOut0, OUTPUT);                                       // digital output pins setting
  pinMode(BitOut1, OUTPUT);                                       // 
  pinMode(BitOut2, OUTPUT);                                       //
  pinMode(BitOut3, OUTPUT);                                       //

  pinMode(BitIn0, INPUT_PULLUP);                                  // digital input pins setting
  pinMode(BitIn1, INPUT_PULLUP);                                  // 
  pinMode(BitIn2, INPUT_PULLUP);                                  //
  pinMode(BitIn3, INPUT_PULLUP);                                  //

  ContaUp.Word = 0x0000;                                          //
  ContaDown.Word = 0x0000;                                        //
 
                                                                  //---- initialize the EasyCAT board -----
                                                                  
  if (EASYCAT.Init() == true)                                     // initialization
  {                                                               // succesfully completed
    Serial.print ("initialized");                                 //
  }                                                               //
  
  else                                                            // initialization failed   
  {                                                               // the EasyCAT board was not recognized
    Serial.print ("initialization failed");                       //     
                                                                  // The most common reason is that the SPI 
                                                                  // chip select choosen on the board doesn't 
                                                                  // match the one choosen by the firmware
                                                                  
    pinMode(13, OUTPUT);                                          // stay in loop for ever
                                                                  // with the Arduino led blinking
    while(1)                                                      //
    {                                                             //   
      digitalWrite (13, LOW);                                     // 
      delay(500);                                                 //   
      digitalWrite (13, HIGH);                                    //  
      delay(500);                                                 // 
    }                                                             // 
  }    
}


//---- main loop ----------------------------------------------------------------------------------------
 
void loop()                                             // In the main loop we must call ciclically the 
{                                                       // EasyCAT task and our application
                                                        //
                                                        // This allows the bidirectional exachange of the data
                                                        // between the EtherCAT master and our application
                                                        //
                                                        // The EasyCAT cycle and the Master cycle are asynchronous
                                                        //     
  
  delay(2);                                             // This delay allows us to set the EasyCAT cycle time  
                                                        // according to the needs of our application
                                                        //
                                                        // For user interface applications a cycle time of 100mS,
                                                        // or even more, is appropriate, but, for data processing 
                                                        // applications, a faster cycle time may be required
                                                        //
                                                        // In this case we can also completely eliminate this
                                                        // delay in order to obtain the fastest possible response
                                                        

                                                        // Instead we can also use millis() to set the cycle time  
                                                        //  
                                                        // example:
//Millis = millis();                                    //
//if (Millis - PreviousCycle >= 50)                     // each 50 mS   
  {                                                     // 
                                                        //
// PreviousCycle = Millis;                              //


    EASYCAT.MainTask();                                 // execute the EasyCAT task
                                                                  
    Application();                                      // execute the user application
  }    
}


//---- user application ------------------------------------------------------------------------------

void Application ()                                        

{
  UWORD Analog0;
  UWORD Analog1;
                                                      // --- analog inputs management ---
    
  Analog0.Word = analogRead(Ana0);                    // read analog input 0
  Analog0.Word >>= 2;                                 // normalize it on 8 bits
  EASYCAT.BufferIn.Byte[0] = Analog0.Byte[0];         // and put the result into
                                                      // input Byte 0 

  Analog1.Word = analogRead(Ana1);                    // read analog input 1
  Analog1.Word >>= 2;                                 // normalize it on 8 bits 
  EASYCAT.BufferIn.Byte[1] = Analog1.Byte[0];         // and put the result into
                                                      // input Byte 1   

                                                      // --- four output bits management ----
                                                      //                          
  if (EASYCAT.BufferOut.Byte[0] & (1<<0))             // the four output bits are mapped to the 
    digitalWrite (BitOut0, HIGH);                     // lower nibble of output Byte 0
  else                                                // 
    digitalWrite (BitOut0, LOW);                      // we read each bit and write it
                                                      // to the corrisponding pin
  if (EASYCAT.BufferOut.Byte[0] & (1<<1))             // 
    digitalWrite (BitOut1, HIGH);                     //
  else                                                //
    digitalWrite (BitOut1, LOW);                      // 
                                                      //
  if (EASYCAT.BufferOut.Byte[0] & (1<<2))             //   
    digitalWrite (BitOut2, HIGH);                     //
  else                                                //
    digitalWrite (BitOut2, LOW);                      // 
                                                      //  
  if (EASYCAT.BufferOut.Byte[0] & (1<<3))             // 
    digitalWrite (BitOut3, HIGH);                     //
  else                                                //
    digitalWrite (BitOut3, LOW);                      // 

                                                      //--- four input bits management ---
                                                      //  
  if (digitalRead(BitIn0))                            // the four input pins are mapped to the
    EASYCAT.BufferIn.Byte[6] |= (1<<0);               // lower nibble of input Byte 6
  else                                                //
    EASYCAT.BufferIn.Byte[6] &= ~(1<<0);              // we read each pin and write it 
                                                      // to the corresponding bit
  if (digitalRead(BitIn1))                            //
    EASYCAT.BufferIn.Byte[6] |= (1<<1);               //  
  else                                                //
    EASYCAT.BufferIn.Byte[6] &= ~(1<<1);              //
                                                      //
  if (digitalRead(BitIn2))                            //
    EASYCAT.BufferIn.Byte[6] |= (1<<2);               //   
  else                                                //
    EASYCAT.BufferIn.Byte[6] &= ~(1<<2);              //  
                                                      //  
  if (digitalRead(BitIn3))                            //
    EASYCAT.BufferIn.Byte[6] |= (1<<3);               // 
  else                                                //
    EASYCAT.BufferIn.Byte[6] &= ~(1<<3);              //

                                                      // --- test sawtooth generation --- 
                                                     //
  Millis = millis();                                  // each 100 mS
  if (Millis - PreviousSaw >= 100)                    // 
  {                                                   // 
    PreviousSaw = Millis;                             //
                                                      //
    ContaUp.Word++;                                   // we increment the variable ContaUp  
    ContaDown.Word--;                                 // and decrement ContaDown
  }                                                   //

                                                   // we use these variables to create sawtooth,
                                                      // with different slopes and periods, for
                                                      // test pourpose, in input Bytes 2,3,4,5,30,31
                                                      
  EASYCAT.BufferIn.Byte[2] = ContaUp.Byte[0];         // slow rising slope
  EASYCAT.BufferIn.Byte[3] = ContaUp.Byte[1];         // extremly slow rising slope
  
  EASYCAT.BufferIn.Byte[4] = ContaDown.Byte[0];       // slow falling slope
  EASYCAT.BufferIn.Byte[5] = ContaDown.Byte[1];       // extremly slow falling slope
    
  EASYCAT.BufferIn.Byte[30] = ContaUp.Byte[0] << 2;   // medium speed rising slope
  EASYCAT.BufferIn.Byte[31] = ContaDown.Byte[0] << 2; // medium speed falling slope    
}
//---- AB&T EasyCAT shield simple HMI application example ------------------------------------------------------------------  
//
//
// AB&T Tecnologie Informatiche - Ivrea Italy
// http://www.bausano.net/en/
// https://www.ethercat.org/en/products/791FFAA126AD43859920EA64384AD4FD.htm
//


// This application demonstrates a simple EtherCAT HMI (human machine interface) built by:
//
// an EasycatShield                                            http://www.bausano.net/en/hardware/ethercat-e-arduino/easycat.html
// an Arduino UNO                                              https://www.arduino.cc/en/Main/ArduinoBoardUno
// an Adafruit 2.8" TFT capacitive touch shield for Arduino    https://www.adafruit.com/product/1947

// Many thanks to the Arduino Team and to Adafruit for their cool products  :-)


//--------------------------------------------------------------------------------------------------------------------



#include "EasyCAT.h"                                      // EasyCAT library (we need version 1.4 or higher)

#include <Adafruit_GFX.h>                                 // Core graphics library

#include <SPI.h>                                          // this is needed for display
#include <Adafruit_ILI9341.h>                             //

#include <Wire.h>                                         // this is needed for FT6206
#include <Adafruit_FT6206.h>                              //

#include <Fonts/FreeMonoBold24pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
                                                
Adafruit_FT6206 ctp = Adafruit_FT6206();                  // The FT6206 uses hardware I2C (SCL/SDA)

#define TFT_CS 10                                         // The display also uses hardware SPI, plus #9 & #10
#define TFT_DC 9                                          //
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);  //


#define	BLACK   0x0000                    // assign human-readable names to some common 16-bit color values
#define	BLUE    0x001F                    //
#define	RED     0xF800                    //    
#define	GREEN   0x07E0                    //  
#define CYAN    0x07FF                    //
#define MAGENTA 0xF81F                    //
#define YELLOW  0xFFE0                    //
#define WHITE   0xFFFF                    //
                                          //
#define ORANGE  0xFC00                    //



EasyCAT EASYCAT(8);         // Instantiate the EasyCAT library choosing pin 8
                            // as SPI chip select not to interfere with the LCD  
                            //
                            // !!! Remember to set pin 8 also on the EasyCAT board, using the jumper,   
                            // if you have rev B, or the 0 ohm resistor, if you have rev A !!! 


//---- global variables ---------------------------------------------------------------------------

unsigned long Millis, PreviousMillis;

int Analog_X =0, Analog_X_prev = 1;
int Analog_Y =0, Analog_Y_prev = 1;

bool FirstRound = true;
bool Blink = true;
bool Running = false;
unsigned char N_Cycles = 0;

unsigned char Conta;

unsigned char EcatState;

unsigned char LedStatus = 0;
unsigned char TouchStatus_prev = 0;






//---- setup ---------------------------------------------------------------------------------------
 
void setup()
{ 
  Serial.begin(9600);                                         // Initialize the debug serial line                       
          
  Serial.print ("\nEasyCAT HMI\n");                           // Print the banner
  Serial.print ("\nAB&T www.bausano.net\n");                  //
  Serial.print ("\nMade in ITALY\n");                         //      

  
  tft.begin();                                                // Initialize the LCD                            
    
  if (! ctp.begin(40))                                        // Initialize the touch screen
  {                                                           // pass in 'sensitivity' coefficient
    Serial.println("Couldn't start FT6206 touchscreen controller");
    while (1);
  }
  Serial.println("Capacitive touchscreen started");
    
 
  tft.fillScreen(BLACK);                                      // Clear the LCD
  tft.setRotation(1);                                         // Set the orientation to horizontal
   
  tft.setFont(&FreeMonoBold24pt7b);                           // Set large font
  tft.setTextSize(1);                                         // Set text size 
 
  tft.setTextColor(GREEN);                                    // Print the first part of the banner on the LCD  
  tft.setCursor(105, 60);                                     //
  tft.print ("AB&T");                                         //

  tft.setFont(&FreeMonoBold12pt7b);                           // Set small font
      
  tft.setCursor(60, 130);                                     // Print the second part of the banner on the LCD     
  tft.print ("www.bausano.net");                              //
  tft.setCursor(70, 190);                                     //
  tft.print ("Made in ITALY");                                //
  
  delay (3000);                                               // Wait a while  
  tft.fillScreen(BLACK);                                      // clear the screen


  EASYCAT.Init();                                             // Initialize the EasyCAT board

  if (EASYCAT.Init() == true)                                 //---- Initialization succeded -----------  
  {                                                           //  
    Serial.print ("inizialized");                             //  
                                                              //
    tft.setFont(&FreeMonoBold24pt7b);                         // Print the "OK" banner on the LCD
                                                              //
    tft.setTextColor(ORANGE);                                 //  
    tft.setCursor(60, 50);                                    //
    tft.print ("EasyCAT");                                    //  
                                                              //
    tft.setFont(&FreeMonoBold12pt7b);                         //
                                                              //
    tft.setCursor(78, 110);                                   //
    tft.print ("inizialized!");                               //
    PrintSmile (160, 180, GREEN);                             //     
  }           
  
  else                                                        //---- Initialization failed -------------         
  {                                                           //
    Serial.print ("inizialization failed");                   //
                                                              //  
    tft.setFont(&FreeMonoBold24pt7b);                         // Print the "KO" banner on the LCD
                                                              //
    tft.setTextColor(ORANGE);                                 // The EasyCAT board is not recognized   
    tft.setCursor(63, 50);                                    // The most common reason is that the SPI 
    tft.print ("EasyCAT");                                    // chip select choosen on the board doesn't  
                                                              // match the one choosen by the firmware
    tft.setFont(&FreeMonoBold12pt7b);                         //
                                                              //
    tft.setCursor(78, 110);                                   //
    tft.print ("init failed!");                               //
    PrintSad (160, 180, GREEN);                               //  

    pinMode(13, OUTPUT);                                      //  
                                                                
    while(1)                                                  // Stay in loop for ever, blinking the Arduino led 
    {                                                         // 
      digitalWrite (13, LOW);                                 //
      delay(500);                                             //
      digitalWrite (13, HIGH);                                //  
      delay(500);                                             // 
    }                                                         // 
  }            

  delay (3000);                                               // Wait a while  
  tft.fillScreen(BLACK);                                      // Clear the screen

                                                              // ---- Print on the LCD the fixed texts and drawing of the HMI ---
  tft.setTextColor(YELLOW);                                   //
  tft.setFont(&FreeMonoBold24pt7b);                           //
                                                             
  tft.setCursor(85, 30);                                      // Analog input "X"      
  tft.print("X=");                                            //
  tft.drawRect(60, 40, 257, 15, YELLOW);                      //     
                                                              
  tft.setCursor(85, 110);                                     // Analog input "Y"
  tft.print("Y=");                                            //
  tft.drawRect(60, 123,  257, 15, YELLOW);                    //
  
  tft.setFont(&FreeMonoBold12pt7b);                           // Leds  
                                                              //
  tft.setCursor(8, 235);                                      // 
  tft.print("led1  led2  led3  led4");                        //
                                                              //
  tft.drawCircle(35, 185, 18, GREEN);                         //
  tft.drawCircle(120, 185, 18, GREEN);                        //
  tft.drawCircle(205, 185, 18, GREEN);                        //
  tft.drawCircle(290, 185, 18, GREEN);                        //  
}


//---- main loop ----------------------------------------------------------------------------------------
 

void loop()                                             // In the main loop we must call ciclically the 
{                                                       // EasyCAT task and our application
                                                        //
                                                        // This allows the bidirectional exachange of the data
                                                        // between the EtherCAT master and our application
                                                        //
                                                        // The EasyCAT cycle and the Master cycle are asynchronous
                                                        //

  Millis = millis();                                    // For this application we choose a cycle time of 150 mS
  if (Millis - PreviousMillis >= 150)                   // that is suitable for an HMI 
  {                                                     // 
    PreviousMillis = Millis;                            //
       
    EcatState = EASYCAT.MainTask();                     // EasyCAT task 
                                                        // (It is mandatory to use EasyCAT library version 1.4 or higher)
   
    Application();                                      // User application    
  }                              
}


//---- user application ----------------------------------------------------------------------------------------------------------

void Application ()                                        

{       

  
//                             -------------------------------- output data management ---------------------------------------------
  
                                                                        // We read the analog values from the EtherCAT output buffer,
                                                                        // i.e. from the data that come from the Master,
                                                                        // and visualize them on the LCD
                                                                              
  Analog_X =  EASYCAT.BufferOut.Byte[0] | (EASYCAT.BufferOut.Byte[1] << 8);   // Analog_X is mapped to output Bytes 0 and 1
  Analog_Y =  EASYCAT.BufferOut.Byte[2] | (EASYCAT.BufferOut.Byte[3] << 8);   // Analog_Y is mapped to output Bytes 2 and 3

  Analog_X = Analog_X >> 3;                                             // normalize the values on 12 bit i.e. from 0 t0 4095        
  Analog_Y  = Analog_Y >> 3;                                            //

  if ((Analog_X != Analog_X_prev) || (FirstRound == true))              // If the Analog_X is changed from the previous reading, or this  
  {                                                                     // is the first time we pass here, refresh the visualization
                                                                        //
    PrintValueRight (Analog_X, Analog_X_prev, 305, 30, ORANGE);         // Print the value on the LCD, in numerical form, right justified 
    PrintValueBar (Analog_X, Analog_X_prev, 61, 41, ORANGE);            // Print the value on the LCD, as a bar 
                                                                        //  
    Analog_X_prev = Analog_X;                                           // Remember the value for the next cycle    
  }  


  if ((Analog_Y != Analog_Y_prev) || (FirstRound == true))              // The same for Analog_Y ...
  {                                                                     //  
    PrintValueRight (Analog_Y, Analog_Y_prev, 305, 110, ORANGE);        //
    PrintValueBar (Analog_Y, Analog_Y_prev, 61, 124, ORANGE);            // 
                                                                        //
    Analog_Y_prev = Analog_Y;                                           //
  }  

  FirstRound = false;                                                   // Remember that we already passed here 


//                             -------------------------------- input data management ----------------------------------------------

                                                                        // We read the data from the touch, process them, and write
                                                                        // the result to the EtherCAT input buffer, i.e. to the data
                                                                        // that will be sent to the Master.
                                                                        
  ProcessTouch(&LedStatus);                                             // Read and process the data from the touch
                                                                        // and visualize the led status on the LCD  

  EASYCAT.BufferIn.Byte[0] = LedStatus;                                 // The status of the leds is mapped to Byte input 0
  
  EASYCAT.BufferIn.Byte[31] = Conta++;                                  // We also increase Conta every cycle and put it in 
                                                                        // input Byte 31, just for test pourpose   



//                             ------------------------------------- HALT/RUN visualization ---------------------------------------

  if (EcatState == 0x08)                                                // If the EasyCAT is in Operational State
  {                                                                     //
    if (!Running)                                                       // and the communication is running
    {                                                                   //
      PrintRun();                                                       // we print a green "RUN" on the LCD
      Running = true;                                                   //
    }                                                                   //
  }

  else                                                                  // Otherwise we print a blinking red "HALT" 
  {                                                                     //     
    Running = false;                                                    //
                                                                        //  
    if (N_Cycles++ > 4)                                                 //
    {                                                                   //
      N_Cycles = 0;                                                     //  
      if (Blink)                                                        //
      {                                                                 //
        PrintHalt();                                                    //  
        Blink = false;                                                  //
      }                                                                 //  
      else                                                              //  
      {                                                                 //
        tft.fillRect(27, 5, 15, 79, BLACK);                             //
        Blink = true;                                                   //
      }                                                                 //
    }    
  }
}   


//----- print a value between 0 and 4095, right justified  ------------------------------------------------------------

void PrintValueRight (unsigned int Value, unsigned int Value_prev, unsigned int x, unsigned int y, unsigned int Color)
{ 
  
  #define Width 32                                                  // space between characters, in pixel
  
  unsigned char i;
  unsigned char Length, Length_prev;
  unsigned char N_Clear, N_Print;
  char AsciiString [8];
  char AsciiString_prev [8];

                                                                    // We use the current and the previous value
                                                                    // to clear and redraw only the needed characters,
                                                                    // to avoid flickering
                                                            
  itoa (Value, AsciiString, 10  );                                  // Convert the current value and the previous value
  itoa (Value_prev, AsciiString_prev, 10  );                        // into ASCII strings
    
  Length = strlen(AsciiString);                                     // Calculate the strings length
  Length_prev = strlen(AsciiString_prev);                           //
    
  if (Length != Length_prev)                                        // If the string length is changed
  {                                                                 // we clear and redraw everything
    N_Clear = 5;                                                    //
    N_Print = Length;                                               //
  }                                                                 //

  else                                                              // Else we compute how many characters
  {                                                                 // to clear and redraw  
    for (i=0; i<Length; i++)                                        //
    {                                                               //
      if(AsciiString[i] != AsciiString_prev[i])                     //    
        break;                                                      //
    }                                                               //  
    N_Clear = Length - i;                                           //
    N_Print = N_Clear;                                              //
  }                                                                 //  

  tft.setFont(&FreeMonoBold24pt7b);                                 // Set large font

  tft.fillRect(x-(N_Clear*Width), y-30, N_Clear*Width, 32, BLACK);  // Clear the area

  x -= Width;                                                       // Set the X for the first character on the right
                    
  for (i=0; i<N_Print; i++)                                         // Print the string, from right to left 
  {                                                                 //
    tft.drawChar(x, y, AsciiString[Length-1-i], Color, 0, 1);       //
    x -= Width;                                                     //
  }                                                                 // 
}


//----- print a value between 0 and 4095, as a bar  ------------------------------------------------------------

void PrintValueBar (unsigned int Value, unsigned int Value_prev, unsigned int x, unsigned int y, unsigned int Color)
{ 
  
  #define Tickness 13                                               // Bar tickness, in pixel

  unsigned char Value_8, Value_8_prev;
                                                                    // We use the current and the previous value
                                                                    // to clear and redraw only the needed pixel,
                                                                    // to avoid flickering
                                                                    
  Value_8 = Value >> 4;                                             // We normalize the current and the previous      
  Value_8_prev = Value_prev >> 4;                                   // value to 8 bits, i.e. from 0 to 255
  
    Serial.println(Value_8); 
    Serial.println(Value_8_prev); 


  if (Value_8 > Value_8_prev)
  {
   tft.fillRect(x + Value_8_prev, y, (Value_8 - Value_8_prev), Tickness, Color);  
  }  

  if (Value_8 < Value_8_prev)
  {
    tft.fillRect(x + Value_8, y, (Value_8_prev - Value_8), Tickness, BLACK);   
  }

    Serial.println();
  
}



//--------- print "Smile" emotion -------------------------------------------------------------------------

void PrintSmile(unsigned int x, unsigned int y, unsigned int Color)

{ 
    tft.drawCircle(x, y-6, 21, Color);   
    tft.drawCircle(x, y-6, 20, Color); 
    tft.drawCircle(x, y-6, 19, Color);  
 
    tft.fillRect(x-30, y-30, 60, 38, BLACK);    
  
    tft.drawCircle(x, y, 30, Color);                          
    tft.drawCircle(x, y, 29, Color);  
    tft.drawCircle(x, y, 28, Color);      

    tft.fillCircle(x - 10, y- 8, 3, Color);
    tft.fillCircle(x + 10, y- 8, 3, Color);     
}  


//--------- print "Sad" emotion--------------------------------------------------------------------------------

void PrintSad(unsigned int x, unsigned int y, unsigned int Color)

{ 
    tft.drawCircle(x, y+29, 21, Color);   
    tft.drawCircle(x, y+29, 20, Color); 
    tft.drawCircle(x, y+29, 19, Color);  
 
    tft.fillRect(x-30, y+16, 60, 35, BLACK);    
  
    tft.drawCircle(x, y, 30, Color);                          
    tft.drawCircle(x, y, 29, Color);  
    tft.drawCircle(x, y, 28, Color);      

    tft.fillCircle(x - 10, y- 8, 3, Color);
    tft.fillCircle(x + 10, y- 8, 3, Color);     
}  


//--------- print a vertical green "RUN" ----------------------------------------------------------------------

void PrintRun (void)

{
  tft.fillRect(27, 5, 15, 79, BLACK);   
  tft.setFont(&FreeMonoBold12pt7b);
  tft.setTextColor(GREEN);  
  tft.setCursor(27, 18);                                         
  tft.print("R"); 
  tft.setCursor(27, 39);                                         
  tft.print("U"); 
  tft.setCursor(27, 61);                                         
  tft.print("N"); 
}


//--------- print a vertical red "HALT" ----------------------------------------------------------------------

void PrintHalt (void)
{
  tft.fillRect(27, 5, 15, 79, BLACK);     
  tft.setFont(&FreeMonoBold12pt7b);  
  tft.setTextColor(RED);  
  tft.setCursor(27, 18);                                         
  tft.print("H"); 
  tft.setCursor(28,39);                                         
  tft.print("A"); 
  tft.setCursor(28, 61);                                         
  tft.print("L"); 
  tft.setCursor(28, 83);                                         
  tft.print("T");     
}


//--- process data from the Touch and draw led status on the LCD ------------------------------------------- 

void ProcessTouch(unsigned char* LedStatus)

{
  unsigned char LedToggle;
  unsigned char TouchStatus = 0x00;
                                                                         
  if (ctp.touched())                                                    // If the touch has been tapped, we process the data
  {
    TS_Point p = ctp.getPoint();                                        // Retrive the tapped point
    
   // Serial.print("X = "); Serial.print(p.x);                          // Print out raw data from the touch controller
   // Serial.print("\tY = "); Serial.println(p.y);                      // for debug pourpose  

    if (p.x > (160))                                                    // If the tapped point belong the led area at the 
                                                                        // bottom of the screen, find out wich led is and
                                                                        // set the corrisponding flag in TouchStatus                                                                       
    {                                                                                 
      if (p.y > (260))                                                  // led 1
      {                                                                 //
        TouchStatus |= 0x01;                                            //
//      Serial.println("1");                                            //        
      }                                                                 //

      if ((p.y < (225)) && (p.y > 170))                                 // led 2
      {                                                                 //
        TouchStatus |= 0x02;                                            //
//      Serial.println("2");                                            //        
      }                                                                 //

       if ((p.y < (140)) && (p.y > 85))                                 // led 3
      {                                                                 //
        TouchStatus |= 0x04;                                            //
//      Serial.println("3");                                            //        
      }                                                                 //
           
      if (p.y < (60))                                                   // led 4   
      {                                                                 //  
        TouchStatus |= 0x08;                                            //
//      Serial.println("4");                                            //        
      }                                                                 //

      LedToggle = ~TouchStatus_prev & TouchStatus;                      // If there is a rising edge in some bit of TouchStatus
      *LedStatus = *LedStatus ^ LedToggle;                              // we toggle the corrisponding bit in LedStatus 

      DrawLed(*LedStatus);                                              // Draw the leds on the LCD
    }  
  }

  TouchStatus_prev = TouchStatus;                                       // Remember if one led has been tapped    
}


//---- draw the leds on the LCD -----------------------------------------------------------------------------------------

void DrawLed (unsigned char LedStatus)

{
      if (LedStatus & 0x01)                                             // Draw the leds according to LedStatus
        tft.fillCircle(35, 185, 16, GREEN);                             //
      else                                                              //
        tft.fillCircle(35, 185, 16, BLACK);                             //
                                                                        //
      if (LedStatus & 0x02)                                             //  
        tft.fillCircle(120, 185, 16, GREEN);                            //
      else                                                              //
        tft.fillCircle(120, 185, 16, BLACK);                            //  
                                                                        //
      if (LedStatus & 0x04)                                             //
        tft.fillCircle(205, 185, 16, GREEN);                            //
      else                                                              //
        tft.fillCircle(205, 185, 16, BLACK);                            //
                                                                        //
      if (LedStatus & 0x08)                                             //
        tft.fillCircle(290, 185, 16, GREEN);                            //
      else                                                              //  
        tft.fillCircle(290, 185, 16, BLACK);                            // 
}