Example project for the Rioux Chem control box

Dependencies:   mbed MODSERIAL

Dependents:   screentest

Rioux Chem Control Box

/media/uploads/emh203/ccb.jpg

This is the example project for the Rioux Chem Control Box. I have posted some youtube videos to guide you through the hardware and software:

Rioux Chem Control Box - Hardware

http://www.youtube.com/watch?v=MoZ92GRYa4s

Rioux Chem Control Box - Software - Part I

http://www.youtube.com/watch?v=_MwaTLL4dyA==

Rioux Chem Control Box - Software - Part II

http://www.youtube.com/watch?v=j_P89izfgoQ

DRIVERS/CHEM_BOX_COMMON.cpp

Committer:
wavenumber
Date:
2020-08-31
Revision:
2:73a028278c5c
Parent:
1:d64ac853223c
Child:
3:cb48919cd5e8

File content as of revision 2:73a028278c5c:

#include "mbed.h"
#include "CHEM_BOX_INTERFACE.h"
#include "MODSERIAL.h"
#include <stdio.h>
#include <stdarg.h>

//Mbed Objects

DigitalOut MBED_LED1(LED1);

DigitalOut AIO_ADC1_CS(p30);     

DigitalOut AIO_ADC2_CS(p29);  

PwmOut BUZZER_CONTROL(p26);

DigitalOut MCU_SR_CLEAR(p25);    

DigitalOut AIO_DAC1_CS(p24);    

DigitalOut AIO_DAC2_CS(p23);     

DigitalOut MFC_POWER_CONTROL(p22); 

PwmOut FAN_CONTROL(p21);       

SPI SPI1(p5,p6,p7);

DigitalOut MCU_SR_LOAD(p8); 

SPI SPI0(p11,p12,p13); 

DigitalOut SmartSwitch_SS(p14); 

BusOut TEMP_SENSE_ADDRESS(p15,p16,p17,p18);

DigitalOut TEMP_SENSE_CS(p19); 

DigitalIn LCD_SWITCH(p20); 

MODSERIAL RS232_0(p9, p10, 1024, 1024); 

MODSERIAL RS232_1(p28, p27, 1024, 1024); 

// Make TX buffer 1024bytes and RX buffer use 512bytes.
MODSERIAL PC(USBTX, USBRX, 1024, 1024); // tx, rx

//Local Variables


static uint8_t TerminalEcho = 1;

static uint8_t HeaterBits = 0;

static uint16_t SolenoidBits = 0;

static uint8_t DigitalOutputBits = 0;

Timeout BuzzTimeout;
     
static uint16_t Thermocouple_FAULT = 0;     

static uint16_t Thermocouple_SCV = 0;     

static uint16_t Thermocouple_SCG = 0;     

static uint16_t Thermocouple_OC= 0;     

static float Temperature[12];

static float InternalTemperature[12];

static uint16_t ReadRawADC(uint8_t Channel);


//Local Functions

void InitTerminal();

void WriteRAW_DAC_Value(uint8_t Channel,uint16_t Data);



void InitChemBox()
{

    AIO_ADC1_CS = 1;     
    
    AIO_ADC2_CS = 1;   
    
    BUZZER_CONTROL.period_ms(1.0);
    
    MCU_SR_CLEAR = 1;   
    
    AIO_ADC1_CS = 1;    
    
    AIO_ADC2_CS = 1;    
    
    MFC_POWER_CONTROL = 0;
    
    FAN_CONTROL.period_us(1000);    
    
    FAN_CONTROL.write(0);
        
    SPI1.format(8,0);
    
    SPI1.frequency(4000000);
    
    MCU_SR_LOAD = 0;
    
    SPI0.format(8,0);
    
    SPI0.frequency(4000000);
    
    SmartSwitch_SS = 1; 
    
    TEMP_SENSE_ADDRESS = 0;
    
    TEMP_SENSE_CS = 1;

    HeaterBits = 0;

    SolenoidBits = 0;

    DigitalOutputBits = 0;

    Thermocouple_FAULT = 0;     

    Thermocouple_SCV = 0;     
    
    Thermocouple_SCG = 0;     
    
    Thermocouple_OC= 0;     

    InitTerminal();
    
    GFX_Init();
}


void SetFanSpeed(uint8_t S)
{
  if(S>100)
    S = 100;
    
    FAN_CONTROL = (float)(S)/100.0;
   
}

void EnableFan()
{
    SetFanSpeed(100);
}

void DisableFan()
{
    SetFanSpeed(0);
}    

void BuzzOff()
{
    BUZZER_CONTROL = 0;
}

void Buzz(float Time)
{
   BUZZER_CONTROL = 0.5;
   BuzzTimeout.attach(&BuzzOff, Time);
  
}


void EnableHeater(uint8_t RelayIndex)
{
    HeaterBits |= (1<<RelayIndex);
}

void DisableHeater(uint8_t RelayIndex)
{
    HeaterBits &= ~(1<<RelayIndex);
}

void EnableSolenoidValve(uint8_t SolenoidIndex)
{
    SolenoidBits |= (1<<SolenoidIndex);
}

void DisableSolenoidValue(uint8_t SolenoidIndex)
{
    SolenoidBits &= ~(1<<SolenoidIndex);
}

void DisableAllHeatersAndSolenoids()
{
    
    SolenoidBits = 0;
    HeaterBits = 0;

    MCU_SR_CLEAR = 1;
    
    MCU_SR_CLEAR = 0;

    MCU_SR_CLEAR = 1;
    
    MCU_SR_LOAD = 1;
   
    MCU_SR_LOAD = 0;
}

void EnableMiscDigitalOutput(uint8_t DigitalOutIndex)
{
    DigitalOutputBits |= (1<<DigitalOutIndex);
}

void DisableMiscDigitalOutput(uint8_t DigitalOutIndex)
{
    DigitalOutputBits &= ~(1<<DigitalOutIndex);
}

void FlushDigitalIO()
{
    SPI1.format(8,0);
    
    SPI1.write((SolenoidBits >> 8) & 0xFF);
    SPI1.write(SolenoidBits & 0xFF);
    SPI1.write(HeaterBits & 0xFF);
    SPI1.write(DigitalOutputBits & 0xFF);
    
    MCU_SR_LOAD = 1;
    MCU_SR_LOAD = 0;
}

//Make sure to call  ReadThermocouple before you call this so internal variables are updated
uint16_t ReadThermocouple_OC() 
{
    return Thermocouple_OC;
}
//Make sure to call  ReadThermocouple before you call this so internal variables are updated
uint16_t ReadThermocouple_SCG()
{
    return Thermocouple_SCG;
}
//Make sure to call  ReadThermocouple before you call this so internal variables are updated
uint16_t ReadThermocouple_SCV()
{
    return  Thermocouple_SCV;
}
//Make sure to call  ReadThermocouple before you call this so internal variables are updated
uint16_t ReadThermocouple_FAULT()
{
    return  Thermocouple_FAULT;
}


float ReadInternalTemperature(uint8_t ThermocoupleIndex)
{
    ReadThermocouple(ThermocoupleIndex); //this will yank out the Data
    return InternalTemperature[ThermocoupleIndex];
}


   
float ReadThermocouple(uint8_t ThermocoupleIndex)
{
    uint8_t i=0;
    uint32_t    ThermocoupleData = 0;
    uint8_t TempData[4];
    
    int16_t InternalTemp = 0;
    int16_t ThermocoupleTemp = 0;
    
    //reset SPi format
    SPI1.format(8,0);
    
    TEMP_SENSE_ADDRESS = ThermocoupleIndex & 0x1f;
    
    TEMP_SENSE_CS = 0;
    
    for(i=0;i<4;i++)
        TempData[i] = SPI1.write(0);
    
    TEMP_SENSE_CS = 1;


    ThermocoupleData =   (uint32_t)(TempData[3])         | 
                        (((uint32_t)(TempData[2]))<<8)   |
                        (((uint32_t)(TempData[1]))<<16)  |
                        (((uint32_t)(TempData[0]))<<24);
                        
    
    if(ThermocoupleData & 0x01)
         Thermocouple_OC |= (1<<ThermocoupleIndex);
    else
         Thermocouple_OC &= ~(1<<ThermocoupleIndex);       

    if(ThermocoupleData & 0x02)
        Thermocouple_SCG |= (1<<ThermocoupleIndex);
    else
        Thermocouple_SCG &= ~(1<<ThermocoupleIndex);

    if(ThermocoupleData & 0x04)
        Thermocouple_SCV |= (1<<ThermocoupleIndex);
    else
        Thermocouple_SCV &= ~(1<<ThermocoupleIndex);

    if(ThermocoupleData & (1<<16))
        Thermocouple_FAULT |= (1<<ThermocoupleIndex);
    else
        Thermocouple_FAULT &= ~(1<<ThermocoupleIndex);

    if(ThermocoupleData & (1<<15))
        InternalTemp = (int16_t) ( ( (ThermocoupleData>>4) & 0xFFF) | 0xF000);  //Sign extend in this case.... we need to map a 12 bit signed number to 16-bits
    else
        InternalTemp = (int16_t)( ( (ThermocoupleData>>4) & 0xFFF));


     if(ThermocoupleData & (0x10000000))
        ThermocoupleTemp = (int16_t)(((ThermocoupleData>>18) & 0x2FFF) | 0xC000);  //Sign extend in this case.... we need to map a 14 bit signed number to 16-bits
    else
        ThermocoupleTemp = (int16_t)(((ThermocoupleData>>18) & 0x2FFF));

     Temperature[ThermocoupleIndex] = (float)ThermocoupleTemp/4.0;

     InternalTemperature[ThermocoupleIndex] = (float)InternalTemp/16.0;;

    return  Temperature[ThermocoupleIndex];
}

float ReadMFC_AnalogInput(uint8_t Channel)
{
    if(Channel > 7)
        Channel = 7;

    return ((float)(ReadRawADC(Channel)) /4095.0) * 5.0;

}

void EnableMFC_Power()
{
    MFC_POWER_CONTROL = 1;
}

void DisableMFC_Power()
{
    MFC_POWER_CONTROL = 0;
}


float ReadMISC_AnalogInput(uint8_t Channel)
{

    if(Channel > 3)
        Channel = 3;

    return ((float)(ReadRawADC(Channel + 9)) /4095.0) * 5.0;

}

float Read4to20(uint8_t Channel)
{

    if(Channel > 1)
        Channel = 1;

    return (((float)(ReadRawADC(Channel + 7)) /4095.0) * 5.0) / 82;
    
}


static uint16_t ReadRawADC(uint8_t Channel)
{
    uint8_t ControlByte[3];
    uint8_t ADC_Data[3];
    uint16_t V;
    
    SPI0.format(8,0);   //The ADC requires mode 0,0
    
    /*See Microchip manual DS21298E-page 21*/
    
    ControlByte[0] = (((Channel&0x07)>>2) & 0x01) | (3<<1);
    ControlByte[1] = Channel<<6;
    ControlByte[2] = 0;
    
    
    if(Channel<8)
        AIO_ADC1_CS = 0;
    else
        AIO_ADC2_CS = 0;
            
        //unroll the loop    
        ADC_Data[0] = SPI0.write(ControlByte[0]);
        ADC_Data[1] = SPI0.write(ControlByte[1]);
        ADC_Data[2] = SPI0.write(ControlByte[2]);
   
        AIO_ADC1_CS = 1;
        AIO_ADC2_CS = 1;
        
        
        V = ((uint16_t)(ADC_Data[1])<<8 | (uint16_t)(ADC_Data[2])) & 0xFFF;
   
        return (V);
        
}


void WriteMFC_AnalogOut(uint8_t Channel,float Value)
{

    if(Channel>7)
        Channel = 7;
        
    if(Value >5.0)
        Value = 5.0;
     
    if(Value<0.0)
        Value = 0.0;
  
    WriteRAW_DAC_Value(Channel,(uint16_t)((Value/5.0) * 4095));
 
}

void WriteMISC_AnalogOut(uint8_t Channel,float Value)
{
    if(Channel>3)
        Channel = 3;
        
    if(Value >5.0)
        Value = 5.0;
     
    if(Value<0.0)
        Value = 0.0;

        WriteRAW_DAC_Value(8+Channel,(uint16_t)((Value/5.0)*4095));
}


void WriteRAW_DAC_Value(uint8_t Channel,uint16_t Data)
{

    uint16_t DataOut;
    
    if(Channel<8)
        AIO_DAC1_CS = 0;
    else
        AIO_DAC2_CS = 0;

    SPI0.format(8,1);   //The DAC requires mode 0,1
   
    DataOut = ((uint16_t)(Channel) & 0x7)<<12  | (Data & 0xFFF);
    
    SPI0.write((DataOut>>8)&0xFF);
    SPI0.write(DataOut&0xFF);

    AIO_DAC1_CS = 1;
    AIO_DAC2_CS = 1;

}




#define MAX_TERMINAL_LINE_CHARS 128
#define MAX_TERMINAL_CMD_CHARS  64

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE 0
#endif

typedef void (*TerminalCallback)(char *);


typedef struct 
{
    const char *CommandString;
    TerminalCallback Callback;
    const char *HelpString;
        
} TerminalCallbackRecord;

//Callback function prototypes
void TerminalCmd_Help(char *arg);
void TerminalCmd_Stub(char *arg);
void TerminalCmd_EnableHeater(char *arg);
void TerminalCmd_DisableHeater(char *arg);
void TerminalCmd_EnableSolenoidValve(char *arg);
void TerminalCmd_DisableSolenoidValue(char *arg);
void TerminalCmd_DisableAllHeatersAndSolenoids(char *arg);
void TerminalCmd_EnableMiscDigitalOutput(char *arg);
void TerminalCmd_DisableMiscDigitalOutput(char *arg);
void TerminalCmd_FlushDigitalIO(char *arg);
void TerminalCmd_FanOn(char *arg);
void TerminalCmd_FanOff(char *arg);
void TerminalCmd_Buzz(char *arg);
void TerminalCmd_T(char *arg);
void TerminalCmd_MFCI(char *arg);
void TerminalCmd_MFCO(char *arg);
void TerminalCmd_4TO20(char *arg);
void TerminalCmd_AIN(char *arg);
void TerminalCmd_MFCON(char *arg);
void TerminalCmd_MFCOFF(char *arg);
void TerminalCmd_AOUT(char *arg);
void TerminalCmd_Reset(char *arg);
void TerminalCmd_ECHO_OFF(char *arg);

//Populate this array with the callback functions and their terminal command string
TerminalCallbackRecord MyTerminalCallbackRecords[] ={   {"reset",TerminalCmd_Reset,"Resets the CHEM box"},

                                                        {"help",TerminalCmd_Help,"Lists available commands"},
                                                        
                                                        {"EH",TerminalCmd_EnableHeater,"Enables a heater channel.  Argument should be between 0 and 7.   Outputs will update when a FDIO command is issued"},
                                                        
                                                        {"DH",TerminalCmd_DisableHeater,"Disables a heater channel.  Argument should be between 0 and 7. Outputs will update when a FDIO command is issued"},
                                                        
                                                        {"ESV",TerminalCmd_EnableSolenoidValve,"Enables a solenoid channel. Argument should be between 0 and 11.  Outputs will update when a FDIO command is issued"},
                                                        
                                                        {"DSV",TerminalCmd_DisableSolenoidValue,"Disables a solenoid channel. Argument should be between 0 and 11.  Outputs will update when a FFDIO command is issued"},
                                                        
                                                        {"DAHAS",TerminalCmd_DisableAllHeatersAndSolenoids,"Disables all heaters and solenoids.  Command is immediately executed."},
                                                        
                                                        {"EMDO",TerminalCmd_EnableMiscDigitalOutput,"Enables a misc. digital output.  Argument should be between 0 and 3.  Output will update when a FDIO command is issued"},
                                                        
                                                        {"DMDO",TerminalCmd_DisableMiscDigitalOutput,"Enables a misc. digital output.  Argument should be between 0 and 3.  Output will update when a FDIO command is issued"},
                                                        
                                                        {"FDIO",TerminalCmd_FlushDigitalIO,"Updates the all of the digital IO channels"},
                                                        
                                                        {"FON",TerminalCmd_FanOn,"Turns on the fans"},
                                                        
                                                        {"FOFF",TerminalCmd_FanOff,"Turns off the fans"},
                                                        
                                                        {"BUZZ",TerminalCmd_Buzz,"Buzz for a little bit.  Argument should be a floating point number representing the number of seconds to buzz"},
                                                        
                                                        {"T",TerminalCmd_T,"Read thermocouple channel"},
                                                        
                                                        {"MFCI",TerminalCmd_MFCI,"Reads in voltage from MFC channel"},
                                                        
                                                        {"MFCO",TerminalCmd_MFCO,"Sets voltage at MFC output channel.  First argument should be the channel.  Second argument should be the voltage.  I.E.  MFCO 1.45"},
                                                        
                                                        {"AOUT",TerminalCmd_AOUT,"Sets voltage at misc. output channel. First argument should be the channel.  Second argument should be the voltage.  I.E.  AOUT 3.211"},
                                                        
                                                        {"4TO20",TerminalCmd_4TO20,"Reads a 4 to 20 mA channel"},
                                                        
                                                        {"AIN",TerminalCmd_AIN,"Reads a general purpose analog in channel"},
                                                        
                                                        {"MFCON",TerminalCmd_MFCON,"Turns on the MFC power"},
                                                        
                                                        {"MFCOFF",TerminalCmd_MFCOFF,"Turns off the MFC power"},
                                                        
                                                        {"ECHO_OFF",TerminalCmd_ECHO_OFF,"Disables echoing of characters"}
                                                    };


extern "C" void mbed_reset();

void TerminalCmd_Reset(char *arg)
{
    mbed_reset();
}



void TerminalCmd_Stub(char *arg)
{
    PC.printf("stub \r\n");
}

void TerminalCmd_ECHO_OFF(char *arg)
{
    TerminalEcho = 0;
}

void TerminalCmd_MFCI(char *arg)
{
    int Channel = -1;
    float Data;
    
    if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=6)
        {
            Data =  ReadMFC_AnalogInput(Channel);
            PC.printf("MFCI:%d:%.3f",Channel,Data);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 6",Channel);
        }
    }
    else
    {
        for(Channel = 0; Channel<=6; Channel++)
        {
            Data =  ReadMFC_AnalogInput(Channel);
            PC.printf("MFCI:%d:%.3f\r\n",Channel,Data);
        }    
    }
}

void TerminalCmd_MFCON(char *arg)
{
    EnableMFC_Power();
}


void TerminalCmd_MFCOFF(char *arg)
{
    DisableMFC_Power();
}


void TerminalCmd_MFCO(char *arg)
{
    int Channel = -1;
    float Data = 0.0;
    
    if(sscanf(arg,"%d %f",&Channel,&Data) == 2)
    {
        if(Channel>=0 && Channel <=7)
        {
            WriteMFC_AnalogOut(Channel,Data);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 1",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Channel should be an integer between 0 and 7 and value should be a float between 0.0 and 5.0. i.e. MFCO 2 4.45",arg);
    }
}

void TerminalCmd_AOUT(char *arg)
{
    int Channel = -1;
    float Data = 0.0;
    
    if(sscanf(arg,"%d %f",&Channel,&Data) == 2)
    {
        if(Channel>=0 && Channel <=3)
        {
            WriteMISC_AnalogOut(Channel,Data);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 3",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Channel should be an integer between 0 and 7 and value should be a float between 0.0 and 5.0.   i.e. AOUT 1 1.25",arg);
    }
}

void TerminalCmd_4TO20(char *arg)
{
    int Channel = -1;
    float Data;
    
    if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=1)
        {
            Data =  Read4to20(Channel);
            PC.printf("4TO20:%d:%.3f",Channel,Data);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 1",Channel);
        }
    }
    else
    {
      
        for(Channel = 0;Channel<=1;Channel++)
        {
            Data =  Read4to20(Channel);
            PC.printf("4TO20:%d:%.5f\r\n",Channel,Data);
        }
      
    }


}

void TerminalCmd_AIN(char *arg)
{
    int Channel = -1;
    float Data;
    
    if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=3)
        {
            Data =  ReadMISC_AnalogInput(Channel);
            PC.printf("AIN:%d:%.3f",Channel,Data);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 3",Channel);
        }
    }
    else
    {
        for(Channel = 0;Channel<=3;Channel++)
        {
            Data =  ReadMISC_AnalogInput(Channel);
            PC.printf("AIN:%d:%.3f\r\n",Channel,Data);
        }
    }
}



void TerminalCmd_EnableHeater(char *arg)
{
    int Channel = -1;
    
    if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=7)
        {
            EnableHeater(Channel);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 7",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 7",arg);
    }
}

void TerminalCmd_DisableHeater(char *arg)
{
int Channel = -1;
    
    if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=7)
        {
            DisableHeater(Channel);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 7",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 7",arg);
    }

}

void TerminalCmd_EnableSolenoidValve(char *arg)
{

int Channel = -1;
    
    if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=11)
        {
            EnableSolenoidValve(Channel);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 11",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 11",arg);
    }
}

void TerminalCmd_DisableSolenoidValue(char *arg)
{
int Channel = -1;

   if(sscanf(arg,"%d",&Channel) == 1)
    {
        if( Channel >= 0 && Channel <= 11)
        {
            DisableSolenoidValue(Channel);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 11",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 11",arg);
    }

}
void TerminalCmd_DisableAllHeatersAndSolenoids(char *arg)
{
    
    DisableAllHeatersAndSolenoids();

}

void TerminalCmd_EnableMiscDigitalOutput(char *arg)
{
int Channel = -1;

  if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=3)
        {
            EnableMiscDigitalOutput(Channel);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 3",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 3",arg);
    }

}

void TerminalCmd_DisableMiscDigitalOutput(char *arg)
{
int Channel = -1;

  if(sscanf(arg,"%d",&Channel) == 1)
    {
        if(Channel>=0 && Channel <=3)
        {
           DisableMiscDigitalOutput(Channel);
        }
        else
        {
            PC.printf("%d is an invalid channel.   Channel should be integer between 0 and 3",Channel);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 3",arg);
    }

}

void TerminalCmd_FlushDigitalIO(char *arg)
{
    FlushDigitalIO();
}

void TerminalCmd_FanOn(char *arg)
{
     SetFanSpeed(100);   //PWMing the FANs doesn't work with the ME40100V1 models!   WE will just on or off
     MBED_LED1 = 1;
}

void TerminalCmd_FanOff(char *arg)
{
     SetFanSpeed(0);   //PWMing the FANs doesn't work with the ME40100V1 models!   WE will just on or off
      MBED_LED1 = 0;
}

void TerminalCmd_Fan(char *arg)
{
int Speed = -1;

 if(sscanf(arg,"%d",&Speed) == 1)
    {
        if(Speed>=0 && Speed<=100)
        {
           SetFanSpeed(Speed);
        }
        else
        {
            PC.printf("%d is an invalid speed.   Speed should be between 0 and 100",Speed);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be integer between 0 and 100",arg);
    }

}


void TerminalCmd_T(char *arg)
{
    float Temp = 0;
    int Channel = -1;
    
     if(sscanf(arg,"%d",&Channel) == 1)
        {
                Temp = ReadThermocouple(Channel);
                 PC.printf("TEMP:%d:%.2f\r\n",Channel,Temp);
        }
        else
        {
            for(Channel = 0; Channel<12;Channel++)
            {
                 Temp = ReadThermocouple(Channel);
                 PC.printf("TEMP:%d:%.2f\r\n",Channel,Temp);
            }
        }
}

void TerminalCmd_Buzz(char *arg)
{
 
 float T = -1.0;

 if(sscanf(arg,"%f",&T) == 1)
    {
        if(T>=0.0 && T<=5.0)
        {
           Buzz(T);
        }
        else
        {
            PC.printf("%f is an invalid time period for buzz.   Time should be between 0.0 and 5.0 seconds",T);
        }
    }
    else
    {
        PC.printf("Bad argument... %s.  Should be float between 0.0 and 5.0",arg);
    }

}




//*****************************************************************
//Plumbing.....
//*****************************************************************

#define NUM_TERMINAL_COMMANDS  (sizeof(MyTerminalCallbackRecords)/sizeof(TerminalCallbackRecord))

char TerminalLineBuf[MAX_TERMINAL_LINE_CHARS];
uint8_t TerminalPos;
char TerminalCmdBuf[MAX_TERMINAL_CMD_CHARS+1];
char TerminalArgs[MAX_TERMINAL_LINE_CHARS-MAX_TERMINAL_CMD_CHARS];
uint8_t NextCharIn;
uint8_t CmdFound;
 
void TerminalBootMsg()
{

PC.printf("\r\n\r\n"); 
PC.printf("***********************************\r\n"); 
PC.printf("CHEM Control Box                   \r\n");
PC.printf("API Version %s \r\n",API_VERSION);
PC.printf("Copyright (C) <2013>  Eli Hughes\r\n");
PC.printf("Wavenumber LLC\r\n"); 
PC.printf("***********************************\r\n\r\n>"); 

}

void InitTerminal()
{

    PC.baud(115200);
    TerminalPos = 0;
    CmdFound = 0;
    TerminalBootMsg();
}

void TerminalCmd_Help(char *arg)
{
    uint8_t i;

    PC.printf("\r\n\r\nCommand List:\r\n");
    PC.printf("----------------------\r\n");

    for(i=0;i<NUM_TERMINAL_COMMANDS;i++)
    {
         PC.printf("%s  ---->  %s\r\n\r\n",MyTerminalCallbackRecords[i].CommandString,MyTerminalCallbackRecords[i].HelpString);    
    }

    PC.printf("\r\n\r\n");
}

void TerminalCmd_Reboot(char *arg)
{
      TerminalBootMsg();
}

void ProcessTerminal()
{
     uint8_t i,j;
     uint8_t ArgsFound;
        
    if(PC.readable())
    {
       NextCharIn = PC.getc();
       
        switch(NextCharIn)
        {
            case '\r':
             
             TerminalLineBuf[TerminalPos++] = 0x0;
             
             if(TerminalEcho)
             {
                 PC.putc(NextCharIn);
             }
             
             if(TerminalPos > 1)
             {
                 //find the command
                 i=0;
                 while(TerminalLineBuf[i]>0x20 &&  TerminalLineBuf[i]<0x7f)
                 {
                      TerminalCmdBuf[i] = TerminalLineBuf[i];
                      i++;
    
                    if(i==MAX_TERMINAL_CMD_CHARS)
                        {
                         break;
                        }
                 }
                    
                TerminalCmdBuf[i] = 0;
                TerminalCmdBuf[i+1] = 0;
                
                
                ArgsFound = TRUE;
                memset(TerminalArgs,0x00,sizeof(TerminalArgs));
                //scan for num terminator or next non whitespace
                while(TerminalLineBuf[i]<=0x20 && (i<MAX_TERMINAL_LINE_CHARS))
                {
                    if(TerminalLineBuf[i] == 0x00)
                    {
                    
                        //if we find a NULL terminator before a non whitespace character they flag for no arguments
                        ArgsFound = FALSE;
                        break;
                    }   
                    i++; 
                }
                
                if(ArgsFound == TRUE)
                {
                    strcpy(TerminalArgs,&TerminalLineBuf[i]);
                    
                    //trim trailing whitespace
                    i = sizeof(TerminalArgs)-1;
                    
                    while((TerminalArgs[i]<0x21) && (i>0))
                    {
                        TerminalArgs[i]= 0x00;
                        i--;
                    }       
                }
                
                CmdFound = FALSE;
                for(j=0;j<NUM_TERMINAL_COMMANDS;j++)
                {           
                    if(strcmp(TerminalCmdBuf,MyTerminalCallbackRecords[j].CommandString) == 0)
                    {
                        PC.printf("\r\n");
                        if(MyTerminalCallbackRecords[j].Callback != NULL)
                            MyTerminalCallbackRecords[j].Callback(TerminalArgs);
                    
                        CmdFound = TRUE;
                        break;
                    }             
                }        
                if(CmdFound == FALSE)
                {
                  PC.printf("\r\n%s command not recognized.\r\n\r\n",TerminalCmdBuf);
                  TerminalCmd_Help("no arg");
                  
                }
              }    
             PC.printf("\r\n");
             TerminalPos = 0;
            
            break;
            
            case '\b':
                if(TerminalPos > 0)
                {
                    TerminalPos--;  
                    if(TerminalEcho)
                    {  
                        PC.putc(NextCharIn);
                    }
                }
            break;
            
            default:
                
                if(TerminalPos == 0 && NextCharIn == 0x020)
                {
                     //Do nothing if space bar is pressed at beginning of line    
                }
                   else if(NextCharIn >= 0x20 && NextCharIn<0x7F)
                {
                    
                    if(TerminalPos < MAX_TERMINAL_LINE_CHARS-1)
                    {
                         TerminalLineBuf[TerminalPos++] = NextCharIn;
                         if(TerminalEcho)
                         {
                            PC.putc(NextCharIn);
                         }
                    }
                }
            
            break;
        
        }
    }
 
}





//    _      _____ _____     _______ _____            _____  _    _ _____ _____  _____ 
//   | |    / ____|  __ \   / / ____|  __ \     /\   |  __ \| |  | |_   _/ ____|/ ____|
//   | |   | |    | |  | | / / |  __| |__) |   /  \  | |__) | |__| | | || |    | (___  
//   | |   | |    | |  | |/ /| | |_ |  _  /   / /\ \ |  ___/|  __  | | || |     \___ \ 
//   | |___| |____| |__| / / | |__| | | \ \  / ____ \| |    | |  | |_| || |____ ____) |
//   |______\_____|_____/_/   \_____|_|  \_\/_/    \_\_|    |_|  |_|_____\_____|_____/ 
//                                                                                     
//                                                                                     
 
void SmartSwitch_Reset();
void SmartSwitch_SetBrightness(uint8_t Brightness);
void InitSmartSwitch();
void PowerUpSmartSwitch();
void PowerDownSmartSwitch();
void SmartSwitchWriteByte(uint8_t DataOut);
void SmartSwitch_SetBackLightColor2(uint8_t RGB);
void SmartSwitch_ImageDump(uint8_t *Img);
void SmartSwitchClear();

 
 
 
#define BACK_BUFFER_SIZE_X    (64)
#define BACK_BUFFER_SIZE_Y    (32)

#define PHYSICAL_DISPLAY_XRES               (uint8_t)(64)
#define PHYSICAL_DISPLAY_YRES               (uint8_t)(32)
#define DISPLAY_X_WIDTH_BYTE                (PHYSICAL_DISPLAY_XRES>>3)
#define DISPLAY_BUFFER_TOTAL_SIZE           (DISPLAY_X_WIDTH_BYTE*PHYSICAL_DISPLAY_YRES*2)
#define GREEN_DATA_BUFFER_OFFSET            (DISPLAY_X_WIDTH_BYTE * PHYSICAL_DISPLAY_YRES)
#define PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES   (PHYSICAL_DISPLAY_XRES>>3)
#define PHYSICAL_DISPLAY_PLANE_BUFFER_SIZE  (PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES * PHYSICAL_DISPLAY_YRES)
#define PHYSICAL_DISPLAY_BUFFER_TOTAL_SIZE  (PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES * PHYSICAL_DISPLAY_YRES*2) 
 
#define SMART_SWITCH_CMD_DISPLAY_DATA           0x55
#define SMART_SWITCH_CMD_SET_BACKLIGHT_COLOR    0x40
#define SMART_SWITCH_CMD_SET_BRIGHTNESS         0x41
#define SMART_SWITCH_CMD_RESET                  0x5E
#define SMART_SWITCH_CMD_RESET_PARAMETER        0x03

#define SMART_SWITCH_BACKLIGHT_RED              (0x03<<4)
#define SMART_SWITCH_BACKLIGHT_YELLOW           (0x03<<4)|(0x03<<2)
#define SMART_SWITCH_BACKLIGHT_GREEN            (0x03<<2)
 
 #define GFX_MAX_STRING_LEN 32
 
void SmartSwitch_ImageDump(uint8_t *Img)
{
   int i;
   
   SPI1.format(8,2);
    
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_DISPLAY_DATA);
   
   for(i=0;i<256;i++)
   {
    SmartSwitchWriteByte(Img[i]);
   }
   
   SmartSwitch_SS = 1;
}

void SmartSwitchClear()
{
   int i;
   
   
   SPI1.format(8,2);
   
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_DISPLAY_DATA);
   
   for(i=0;i<256;i++)
   {
     SmartSwitchWriteByte(0x00);
   }
   
   SmartSwitch_SS = 1;
}

void SmartSwitch_Reset()
{
   
   SPI1.format(8,2);
   
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_RESET);
   SmartSwitchWriteByte(SMART_SWITCH_CMD_RESET_PARAMETER);
   SmartSwitch_SS = 1;
}

void SmartSwitch_SetBackLightColor(uint8_t Red,uint8_t Green,uint8_t Blue)
{
  
   SPI1.format(8,2);
  
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_SET_BACKLIGHT_COLOR);
   SmartSwitchWriteByte(Red<<6 | Green<<4 | Blue <<2 | 0x3);
   SmartSwitch_SS = 1;
}

void SmartSwitch_SetBackLightColor2(uint8_t RGB)
{
   SPI1.format(8,2);
   
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_SET_BACKLIGHT_COLOR);
   SmartSwitchWriteByte(RGB<<2 | 0x3);
   SmartSwitch_SS = 1;
}

void SmartSwitch_SetBrightness(uint8_t Brightness)
{
   SPI1.format(8,2);
   
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_SET_BRIGHTNESS);
   SmartSwitchWriteByte(Brightness<<5 | 0x1F);
   SmartSwitch_SS = 1;
}

void InitSmartSwitch()
{
   SmartSwitch_SS = 1;
   SmartSwitch_Reset();
}

void SmartSwitchWriteByte(uint8_t DataOut)
{

   SPI1.write(DataOut);

}


//Linking Functions to Physical Screen
//***********************************************************************************

void GFX_InitPhysicalScreen()
{
     InitSmartSwitch();
}


const uint8_t BitReverseTable[256] =
{
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
};

void GFX_DumpRenderContextToPhysicalScreen(RenderContext *Image)
{
   int x,y;
   uint8_t  NextByteOut; 
   
   SPI1.format(8,2);
   
   SmartSwitch_SS = 0;
   SmartSwitchWriteByte(SMART_SWITCH_CMD_DISPLAY_DATA);
   
   for(y=0;y<PHYSICAL_DISPLAY_YRES;y++)
   {
       for(x=0;x<PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES;x++)
       {
          //Need to rotate the display 180 degrees
          NextByteOut = Image->RenderPlane.BitPlaneSpace[(((PHYSICAL_DISPLAY_YRES - y - 1) * PHYSICAL_DISPLAY_X_WIDTH_IN_BYTES)) + x];
          SmartSwitchWriteByte(BitReverseTable[NextByteOut]);
       }
   }
   SmartSwitch_SS = 1;
}


//Device Independent Functions
//***********************************************************************************

//Reserve Space for the backbuffer

RenderContext BackBuffer;
uint8_t BackBufferRenderPlaneSpace[PHYSICAL_DISPLAY_PLANE_BUFFER_SIZE];

int16_t GFX_Drawcharacter(RenderContext *Image, uint8_t character, int16_t StartX, int16_t StartY, GFXFont *MyFont);
int16_t GFX_GetStringWidth(char * String,GFXFont * MyFont);

//FontData

#define FONT5x7_FONT_WIDTH 5
#define FONT5x7_FONT_HEIGHT 8
#define FONT5x7_FONT_ELEMENTS 128
#define FONT5x7_FONT_COLUMN_SIZE_IN_BYTE  1

uint8_t FontTable_Font5x7 [640] = {
0x00 ,0x08 ,0x0C ,0xFA ,0x81 ,0xFA ,0x0C ,0x08 ,0x00 ,0x00 ,0x00 ,0x10 ,0x30 ,0x5F ,0x81 ,0x5F ,
0x30 ,0x10 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0xBE ,0x00 ,0x00 ,0x00 ,0x00 ,0x06 ,0x00 ,0x06 ,0x00 ,0x00 ,0x28 ,
0xFE ,0x28 ,0xFE ,0x28 ,0x48 ,0xFE ,0x54 ,0xFE ,0x24 ,0x06 ,0xE6 ,0x10 ,0xCE ,0xC0 ,0x60 ,0x92 ,
0x94 ,0x78 ,0x10 ,0x06 ,0x00 ,0x00 ,0x00 ,0x00 ,0x7C ,0x82 ,0x00 ,0x00 ,0x00 ,0x82 ,0x7C ,0x00 ,
0x00 ,0x00 ,0x54 ,0x38 ,0xFE ,0x38 ,0x54 ,0x10 ,0x10 ,0x7C ,0x10 ,0x10 ,0x80 ,0x60 ,0x00 ,0x00 ,
0x00 ,0x10 ,0x10 ,0x10 ,0x10 ,0x10 ,0x80 ,0x00 ,0x00 ,0x00 ,0x00 ,0xC0 ,0x30 ,0x0C ,0x02 ,0x00 ,
0x7C ,0xA2 ,0x92 ,0x8A ,0x7C ,0x88 ,0x84 ,0xFE ,0x80 ,0x80 ,0x84 ,0xC2 ,0xA2 ,0x92 ,0x8C ,0x44 ,
0x92 ,0x92 ,0x92 ,0x6C ,0x10 ,0x18 ,0x14 ,0xFE ,0x10 ,0x4E ,0x8A ,0x8A ,0x8A ,0x72 ,0x7C ,0x92 ,
0x92 ,0x92 ,0x64 ,0x02 ,0xC2 ,0x22 ,0x12 ,0x0E ,0x6C ,0x92 ,0x92 ,0x92 ,0x6C ,0x0C ,0x92 ,0x92 ,
0x92 ,0x7C ,0x48 ,0x00 ,0x00 ,0x00 ,0x00 ,0x80 ,0x68 ,0x00 ,0x00 ,0x00 ,0x10 ,0x28 ,0x44 ,0x82 ,
0x00 ,0x28 ,0x28 ,0x28 ,0x28 ,0x00 ,0x82 ,0x44 ,0x28 ,0x10 ,0x00 ,0x04 ,0x02 ,0xA2 ,0x12 ,0x0C ,
0x3C ,0x42 ,0x9A ,0xA2 ,0x1C ,0xF8 ,0x14 ,0x12 ,0x14 ,0xF8 ,0xFE ,0x92 ,0x92 ,0x92 ,0x6C ,0x7C ,
0x82 ,0x82 ,0x82 ,0x44 ,0xFE ,0x82 ,0x82 ,0x44 ,0x38 ,0xFE ,0x92 ,0x92 ,0x82 ,0x82 ,0xFE ,0x12 ,
0x12 ,0x02 ,0x02 ,0x7C ,0x92 ,0x92 ,0x92 ,0x74 ,0xFE ,0x10 ,0x10 ,0x10 ,0xFE ,0x82 ,0x82 ,0xFE ,
0x82 ,0x82 ,0x40 ,0x80 ,0x80 ,0x80 ,0x7E ,0xFE ,0x10 ,0x28 ,0x44 ,0x82 ,0xFE ,0x80 ,0x80 ,0x80 ,
0x00 ,0xFE ,0x04 ,0x08 ,0x04 ,0xFE ,0xFE ,0x04 ,0x18 ,0x20 ,0xFE ,0x7C ,0x82 ,0x82 ,0x82 ,0x7C ,
0xFE ,0x12 ,0x12 ,0x12 ,0x0C ,0x7C ,0x82 ,0xA2 ,0xC2 ,0xFC ,0xFE ,0x12 ,0x32 ,0x52 ,0x8C ,0x4C ,
0x92 ,0x92 ,0x92 ,0x64 ,0x02 ,0x02 ,0xFE ,0x02 ,0x02 ,0x7E ,0x80 ,0x80 ,0x80 ,0x7E ,0x3E ,0x40 ,
0x80 ,0x40 ,0x3E ,0xFE ,0x40 ,0x20 ,0x40 ,0xFE ,0xC6 ,0x28 ,0x10 ,0x28 ,0xC6 ,0x02 ,0x04 ,0xF8 ,
0x04 ,0x02 ,0xC2 ,0xA2 ,0x92 ,0x8A ,0x86 ,0xFE ,0x82 ,0x82 ,0x00 ,0x00 ,0x02 ,0x0C ,0x30 ,0xC0 ,
0x00 ,0x82 ,0x82 ,0xFE ,0x00 ,0x00 ,0x04 ,0x02 ,0x04 ,0x00 ,0x00 ,0x80 ,0x80 ,0x80 ,0x80 ,0x80 ,
0x06 ,0x08 ,0x00 ,0x00 ,0x00 ,0x70 ,0x88 ,0x88 ,0x70 ,0x80 ,0xFC ,0x90 ,0x90 ,0x60 ,0x00 ,0x70 ,
0x88 ,0x88 ,0x88 ,0x00 ,0x60 ,0x90 ,0x90 ,0x7C ,0x80 ,0x70 ,0xA8 ,0xA8 ,0x90 ,0x00 ,0x10 ,0xF8 ,
0x14 ,0x04 ,0x00 ,0x98 ,0xA4 ,0xA4 ,0x78 ,0x00 ,0xFC ,0x20 ,0x10 ,0xE0 ,0x00 ,0xE8 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x40 ,0x80 ,0x80 ,0x74 ,0x00 ,0xFC ,0x20 ,0x50 ,0x88 ,0x00 ,0xFC ,0x00 ,0x00 ,0x00 ,
0x00 ,0xF0 ,0x08 ,0x30 ,0x08 ,0xF0 ,0xF8 ,0x08 ,0x08 ,0xF0 ,0x00 ,0x70 ,0x88 ,0x88 ,0x70 ,0x00 ,
0xF8 ,0x24 ,0x24 ,0x18 ,0x00 ,0x18 ,0x24 ,0x24 ,0xF8 ,0x00 ,0xF0 ,0x08 ,0x08 ,0x10 ,0x00 ,0x90 ,
0xA8 ,0xA8 ,0x48 ,0x00 ,0x08 ,0x7C ,0x88 ,0x00 ,0x00 ,0x78 ,0x80 ,0x80 ,0x78 ,0x00 ,0x38 ,0x40 ,
0x80 ,0x40 ,0x38 ,0x78 ,0x80 ,0x40 ,0x80 ,0x78 ,0x88 ,0x50 ,0x20 ,0x50 ,0x88 ,0x08 ,0x10 ,0xE0 ,
0x10 ,0x08 ,0xC8 ,0xA8 ,0x98 ,0x00 ,0x00 ,0x10 ,0x6C ,0x82 ,0x00 ,0x00 ,0xFE ,0x00 ,0x00 ,0x00 ,
0x00 ,0x82 ,0x6C ,0x10 ,0x00 ,0x00 ,0x08 ,0x04 ,0x08 ,0x10 ,0x08 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00  };

uint8_t CharacterWidthTable_Font5x7   [128] = {
0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,
0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,
0x05 ,0x01 ,0x03 ,0x05 ,0x05 ,0x05 ,0x05 ,0x01 ,0x02 ,0x02 ,0x05 ,0x05 ,0x02 ,0x05 ,0x01 ,0x04 ,
0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x01 ,0x01 ,0x04 ,0x04 ,0x04 ,0x05 ,
0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x04 ,0x05 ,0x05 ,0x05 ,
0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x05 ,0x03 ,0x04 ,0x05 ,0x03 ,0x05 ,
0x02 ,0x05 ,0x04 ,0x04 ,0x05 ,0x04 ,0x04 ,0x04 ,0x04 ,0x01 ,0x04 ,0x04 ,0x01 ,0x05 ,0x04 ,0x05 ,
0x05 ,0x05 ,0x04 ,0x04 ,0x03 ,0x04 ,0x05 ,0x05 ,0x05 ,0x05 ,0x03 ,0x03 ,0x01 ,0x05 ,0x05 ,0x05  };

#define FONT3x5_FONT_WIDTH 3
#define FONT3x5_FONT_HEIGHT 5
#define FONT3x5_ELEMENTS 128
#define FONT3x5_FONT_COLUMN_SIZE_IN_BYTE  1


uint8_t FontTable_Font3x5 [384] = {
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,
0x00 ,0x00 ,0x00 ,0x17 ,0x00 ,0x00 ,0x03 ,0x00 ,0x03 ,0x0E ,0x1F ,0x0E ,0x14 ,0x1F ,0x0A ,0x00 ,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x03 ,0x00 ,0x00 ,0x0E ,0x11 ,0x00 ,0x11 ,0x0E ,0x00 ,0x15 ,0x0E ,
0x15 ,0x04 ,0x0E ,0x04 ,0x10 ,0x08 ,0x00 ,0x04 ,0x04 ,0x04 ,0x10 ,0x00 ,0x00 ,0x18 ,0x04 ,0x03 ,
0x0E ,0x11 ,0x0E ,0x12 ,0x1F ,0x10 ,0x19 ,0x15 ,0x16 ,0x11 ,0x15 ,0x0A ,0x07 ,0x04 ,0x1F ,0x17 ,
0x15 ,0x09 ,0x1E ,0x15 ,0x18 ,0x01 ,0x1D ,0x03 ,0x1B ,0x15 ,0x1B ,0x06 ,0x15 ,0x0E ,0x0A ,0x00 ,
0x00 ,0x10 ,0x0A ,0x00 ,0x04 ,0x0A ,0x11 ,0x00 ,0x00 ,0x00 ,0x11 ,0x0A ,0x04 ,0x01 ,0x15 ,0x02 ,
0x09 ,0x15 ,0x0E ,0x1E ,0x05 ,0x1E ,0x1F ,0x15 ,0x0A ,0x0E ,0x11 ,0x0A ,0x1F ,0x11 ,0x0E ,0x1F ,
0x15 ,0x11 ,0x1F ,0x05 ,0x05 ,0x1E ,0x15 ,0x1D ,0x1F ,0x04 ,0x1F ,0x11 ,0x1F ,0x11 ,0x08 ,0x10 ,
0x0F ,0x1F ,0x06 ,0x19 ,0x1F ,0x10 ,0x10 ,0x1F ,0x02 ,0x1F ,0x1F ,0x06 ,0x1F ,0x1F ,0x11 ,0x1F ,
0x1F ,0x05 ,0x07 ,0x1F ,0x19 ,0x1F ,0x1F ,0x0D ,0x16 ,0x16 ,0x15 ,0x1D ,0x01 ,0x1F ,0x01 ,0x1F ,
0x10 ,0x1F ,0x0F ,0x10 ,0x0F ,0x1F ,0x08 ,0x1F ,0x1B ,0x04 ,0x1B ,0x01 ,0x1E ,0x01 ,0x19 ,0x15 ,
0x13 ,0x1F ,0x11 ,0x00 ,0x03 ,0x0C ,0x10 ,0x11 ,0x1F ,0x00 ,0x02 ,0x01 ,0x02 ,0x10 ,0x10 ,0x10 ,
0x01 ,0x02 ,0x00 ,0x08 ,0x14 ,0x1C ,0x1F ,0x14 ,0x08 ,0x0C ,0x12 ,0x12 ,0x08 ,0x14 ,0x1F ,0x0C ,
0x16 ,0x16 ,0x14 ,0x0E ,0x05 ,0x06 ,0x15 ,0x0F ,0x1F ,0x04 ,0x18 ,0x1D ,0x00 ,0x00 ,0x10 ,0x0D ,
0x00 ,0x1F ,0x0C ,0x12 ,0x1F ,0x00 ,0x00 ,0x1C ,0x08 ,0x1C ,0x1C ,0x02 ,0x1C ,0x0C ,0x12 ,0x0C ,
0x1E ,0x05 ,0x02 ,0x02 ,0x05 ,0x1E ,0x1C ,0x02 ,0x04 ,0x14 ,0x1A ,0x00 ,0x04 ,0x1E ,0x04 ,0x1E ,
0x10 ,0x1E ,0x0E ,0x10 ,0x0E ,0x1C ,0x08 ,0x1C ,0x12 ,0x0C ,0x12 ,0x12 ,0x0C ,0x02 ,0x12 ,0x1A ,
0x16 ,0x04 ,0x0E ,0x11 ,0x1F ,0x00 ,0x00 ,0x11 ,0x0E ,0x04 ,0x02 ,0x02 ,0x04 ,0x00 ,0x00 ,0x00  };


uint8_t CharacterWidthTable_Font3x5 [128] = {
0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,
0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,
0x03 ,0x01 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x02 ,0x03 ,0x03 ,0x03 ,0x02 ,0x03 ,0x01 ,0x03 ,
0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x02 ,0x03 ,0x03 ,0x03 ,0x03 ,
0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,
0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x02 ,0x03 ,0x02 ,0x03 ,0x03 ,
0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x03 ,0x03 ,0x01 ,0x03 ,0x03 ,0x03 ,
0x03 ,0x03 ,0x03 ,0x02 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x03 ,0x01 ,0x03 ,0x03 ,0x03  };

GFXFont Font5x7;
GFXFont Font3x5;

void GFX_Init()
{
    
    //Staticially Allocate and setup the backbuffer space;
    
    BackBuffer.RenderPlane.BitPlaneSpace = &BackBufferRenderPlaneSpace[0];
   
    BackBuffer.SizeX = BACK_BUFFER_SIZE_X;
    BackBuffer.SizeY = BACK_BUFFER_SIZE_Y;

    BackBuffer.RenderPlane.SizeX = BACK_BUFFER_SIZE_X;
    BackBuffer.RenderPlane.SizeY = BACK_BUFFER_SIZE_Y;

    
    GFX_FullDisplayBufferClear(&BackBuffer);

    //Initialize the stock fonts

    Font5x7.CharacterWidthTable = (uint8_t *)CharacterWidthTable_Font5x7;
    Font5x7.FontBuffer = (uint8_t *)FontTable_Font5x7;
    Font5x7.FontHeight = FONT5x7_FONT_HEIGHT;
    Font5x7.FontWidth = FONT5x7_FONT_WIDTH;
    Font5x7.BytesPerColumn = FONT5x7_FONT_COLUMN_SIZE_IN_BYTE;

    Font3x5.CharacterWidthTable = (uint8_t *)CharacterWidthTable_Font3x5;
    Font3x5.FontBuffer = (uint8_t *)FontTable_Font3x5;
    Font3x5.FontHeight = FONT3x5_FONT_HEIGHT;
    Font3x5.FontWidth = FONT3x5_FONT_WIDTH;
    Font3x5.BytesPerColumn = FONT3x5_FONT_COLUMN_SIZE_IN_BYTE;
    
    GFX_InitPhysicalScreen();
    
}



void GFX_FullDisplayBufferClear(RenderContext *Image)
{
    BitPlane_Clear(&Image->RenderPlane);
}


void GFX_PutPixel(RenderContext *Image, int16_t x, int16_t y)
{
    if((x<Image->SizeX) && (y<Image->SizeY) && (x>=0) && (y>=0))
    {
         BitPlane_Put(&Image->RenderPlane,Image->SizeX-x-1,Image->SizeY-y-1,TRUE);
    }
}



#ifndef _INLINE_GFX_GET_PIXEL
uint8_t GFX_GetPixel(RenderContext *Image, int16_t x, int16_t y)
{
    uint8_t PixelColor = 0;
    
    if((x<Image->SizeX) && (y<Image->SizeY) && (x>=0) && (y>=0))
    {
        
        PixelColor = BitPlane_Get(&Image->RenderPlane,x,y);
    }
    
    return PixelColor;
}
#endif


void GFX_DrawHline(RenderContext *Image, int16_t XStart, int16_t XStop, int16_t Y)
{
    int16_t LineStart;
    int16_t LineStop;
    uint16_t i;
    
    if((Y<Image->SizeY)  && (Y>=0))
    {
        if(XStart>XStop)
        {
            LineStart = XStop;    
            LineStop = XStart;
        }    
        else
        {
            LineStart = XStart;    
            LineStop = XStop;
        }
        
        if(LineStart<0)
        {
            LineStart = 0;
        }
    
        if(LineStop>Image->SizeX)
        {
            LineStop =     Image->SizeX-1;
        }
    
        if(LineStart == LineStop)
        {
            GFX_PutPixel(Image,LineStart,Y);    
        }
        else
        {
            for(i=LineStart; i<=LineStop ; i++)
            {
                GFX_PutPixel(Image,i,Y);    
            }
        }    
    }    
    
}



 void GFX_DrawVline(RenderContext *Image, int16_t YStart, int16_t YStop, int16_t X)
{
    int16_t LineStart;
    int16_t LineStop;
    int16_t i;

    if((X<Image->SizeX) && (X>=0))
    {
    
        if(YStart>YStop)
        {
            LineStart = YStop;    
            LineStop = YStart;
        }    
        else
        {
            LineStart = YStart;    
            LineStop = YStop;
        }
        
        if(LineStart<0)
        {
            LineStart = 0;
        }
    

        if(LineStop>Image->SizeY)
        {
            LineStop =     Image->SizeY-1;
        }
    
        for(i=LineStart; i<=LineStop ; i++)
        {
            GFX_PutPixel(Image,X,i);    
        }    
    }    
}


void GFX_DrawLine(RenderContext * Image, int16_t X1,int16_t Y1, int16_t X2,int16_t Y2)
{
    //A simple Implementation of Bresenham's line Algorithm
    int16_t StartX,StopX,StartY,StopY;
    int16_t dX,dY;
    int16_t Y_Numerator;
    int16_t X_Numerator;
    int16_t Y;
    int16_t X;
    int16_t i;
    uint8_t YDir = 0;
    //First Make sure that it is left to right
    //If not them flop them
    if(X2>X1)
    {
        StartX = X1;
        StopX = X2;    
        StartY = Y1;
        StopY = Y2;    
    }    
    else
    {
        StartX = X2;
        StopX = X1;    
        StartY = Y2;
        StopY = Y1;    
    }
    GFX_PutPixel(Image, StopX,StopY);
    if(StopY>=StartY)
    {
        dY = StopY - StartY;
        YDir = 0;
    }
    else
    {
        dY = StartY - StopY;
        YDir = 1;
    }
    dX = StopX - StartX;
    //Now, if the slope is less greater than one,  we need to swap all X/Y operations
    if(dY<=dX)
    {
        //Slope is less than one, proceed at normal and step along the x axis
        Y=StartY;   //start the whole part of the Y value at the starting pixeel.
        X=StartX;
        //We need to start the numerator of the fraction half way through the fraction so evertyhing rounds at
        //fraction midpoint
        Y_Numerator = dX>>1;   //The fraction demonimator is assumeed to be dX
                                // out fixed point Y value is  Y + (Y_Numerator / dX)
                                //Every time we step the X coordinate by one, we need to step
                                //out Y coordinate by dY/dX.  We do this by just adding dY to our
                                //numerator.  When the numerator gets bigger than the
                                //denomiator, the increment the whole part by one and decrement the numerator
                                //by the denominator
        for(i=0;i<dX;i++)
        {
            GFX_PutPixel(Image,X,Y);
            X++;
            //Now do all the fractional stuff
            Y_Numerator += dY;
            if(Y_Numerator >= dX)
            {    
                Y_Numerator-=dX;
                if(StopY > StartY)
                {
                    Y++;
                }
                else
                {
                    Y--;    
                }
            }
        }
    }
    else
    {
        //Same as before by step along the y axis.    
        Y=StartY;   
        X=StartX;
        X_Numerator = dY>>1;   
        for(i=0;i<dY;i++)
        {
            GFX_PutPixel(Image,X,Y);
            //Now do all the fractional stuff
            if(YDir)
            {
                Y--;
            }
            else
            {
                Y++;
            }
            X_Numerator += dX;
            if(X_Numerator >= dY)
            {    
                X_Numerator-=dY;
                if(StopX > StartX)
                {
                    X++;
                }
                else
                {
                    X--;    
                }
            }
        }
    }
}

void GFX_DrawBox(RenderContext *Image, GFXDisplayBox *Box)
{
    GFX_DrawHline(Image,Box->P1.X,Box->P2.X,Box->P1.Y);
    GFX_DrawHline(Image,Box->P1.X,Box->P2.X,Box->P2.Y);
    GFX_DrawVline(Image,Box->P1.Y,Box->P2.Y,Box->P1.X);
    GFX_DrawVline(Image,Box->P1.Y,Box->P2.Y,Box->P2.X);
}

int16_t GFX_DrawCharacter(RenderContext * Image,uint8_t Character,int16_t StartX, int16_t StartY, GFXFont * MyFont)
{
    uint8_t i,j,Mask;
    uint16_t CharStartIndex,ColumnStartIndex,ByteOffset;

    CharStartIndex = (Character * (MyFont->BytesPerColumn) * (MyFont->FontWidth));

    for(j=0;j<MyFont->CharacterWidthTable[Character];j++)
        {
            //Draw the current slice
            ColumnStartIndex = j* (MyFont->BytesPerColumn);

            for(i=0;i<MyFont->FontHeight;i++)
            {
                ByteOffset = i>>3;
                Mask = 0x01 << (i&0x07);
            
                if( (MyFont->FontBuffer[CharStartIndex + ColumnStartIndex + ByteOffset]) & Mask)
                {
                    GFX_PutPixel(Image, StartX, StartY + i);
                }        
            }
          StartX++;
        }
    return StartX;
}


int16_t GFX_GetStringWidth(char * String,GFXFont * MyFont)
{
    uint8_t Ptr = 0;
    uint8_t NextChar;
    int16_t StringSize = 0;
    
    NextChar = String[Ptr];
    Ptr++;
    
    while((NextChar!=0) && (Ptr <GFX_MAX_STRING_LEN))
    {
        StringSize += MyFont->CharacterWidthTable[NextChar] + 1;
        NextChar = String[Ptr];
        Ptr++;
    }
    
    return StringSize;
}

void GFX_DrawCenteredString(RenderContext * Image,char * String,int16_t StartX, int16_t StartY, GFXFont * MyFont)
{
    StartX -= (GFX_GetStringWidth(String,MyFont)>>1);
    GFX_DrawString(Image,String,StartX,StartY,MyFont);
}

void GFX_DrawString(RenderContext * Image,char * String,int16_t StartX, int16_t StartY, GFXFont * MyFont)
{

uint8_t Ptr = 0;
uint8_t NextChar;

NextChar = String[Ptr];

    while((NextChar!=0) && (Ptr <GFX_MAX_STRING_LEN))
    {
        StartX = GFX_DrawCharacter(Image,NextChar,StartX,StartY,MyFont);
        Ptr++;
        NextChar = String[Ptr];
        StartX++;
    }

}

char GFXStringBuf[64];

void  GFX_printf(RenderContext * Image,int16_t StartX, int16_t StartY, GFXFont * MyFont, const char *FormatString,...)
{
     va_list argptr; 
     va_start(argptr,FormatString); 
     vsprintf((char *)GFXStringBuf,FormatString,argptr);
     va_end(argptr);   
     
     GFX_DrawString(Image,GFXStringBuf,StartX,StartY,MyFont);
}

#ifndef INLINE_BITPLANE_PUT
void BitPlane_Put(BitPlane  * BP, uint16_t X,uint16_t Y, uint8_t Value)
{
    uint16_t Offset;
    uint8_t Mask;
    
    Offset = (Y * ((BP->SizeX)>>3)) + (X>>3);
    Mask = 0x01 << (X & 0x07);

    if(Value)
    {
        BP->BitPlaneSpace[Offset] |= Mask;
    }
    else
    {
        BP->BitPlaneSpace[Offset] &= ~Mask;
    }
}
#endif

#ifndef INLINE_BITPLANE_GET
uint8_t BitPlane_Get(BitPlane  * BP, uint16_t X,uint16_t Y)
{
    uint16_t Offset;
    uint8_t Mask;
 
    Offset = (Y * ((BP->SizeX)>>3)) + (X>>3);
    Mask = 0x01 << (X & 0x07);

    if((BP->BitPlaneSpace[Offset])&Mask)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}
#endif

void BitPlane_Clear(BitPlane  * BP) 
{
    uint16_t PlaneSpaceSize;
    uint16_t i;

    PlaneSpaceSize = ((BP->SizeX)>>3) * BP->SizeY;

    for (i=0;i<PlaneSpaceSize;i++) {
        BP->BitPlaneSpace[i] = 0;
    }
}