Control Code with I/O and ADC working

Dependencies:   MODSERIAL mbed

Revision:
20:cdeed4dad690
Parent:
19:0946665b37c7
Child:
21:f87464a7e7c6
--- a/main.cpp	Thu Jun 28 21:30:44 2018 +0000
+++ b/main.cpp	Mon Jul 16 03:53:59 2018 +0000
@@ -1,34 +1,44 @@
 // MBED SCRIPT FOR CONTROLLING THE TEMPERATURE CONTROLLED TEST FIXTURE (TCTF)
 // DATE: SEPTEMBER 2017
 
-#define FW_VERSION      "V.010"
 #include "mbed.h"
 #include "MODSERIAL.h"
 #include "MCP23008.h"
 #include "LTC2487.h"
 #include <string>
 
+
 //DEFINITIVE VARIABLES
-#define DEBUG                0
-#define DEBUG1               0
-#define DEBUG2               0
-#define DEBUG3               0
-#define DEBUG5               0
-#define UID_PRINT            0
-#define TEMP_PRINT           1
-#define LOOP_TIME            0  
-#define CHN_COUNT            8
+#define DEBUG_LOOP_TIME      0x00000001
+#define RXDATA_PRINT         0x00000002
+#define UID_PRINT            0x00000004
+#define ERROR_PRINT          0x00000008
+#define ADC_VAL_PRINT        0x00000010
+#define HEATER_CHILLER_PRINT 0x00000020
+#define HEATER_ON_TIME_PRINT 0x00000040
+#define LED_PRINT            0x00000080
+#define TEMP_PRINT           0x00000100
+#define I2C_PRINT            0x00000200
+
+#define IO_I2C_LINE          1
+#define ADC_I2C_LINE         2
+
+
+#define CHAN_COUNT           8
 #define MIN_TEMP             10
 #define MAX_TEMP             65
-#define TEMP_MARGIN          20
+#define MEGA_MAX_TEMP        75
+#define TEMP_MARGIN          10
 #define HYST_LOW             0.3
 #define HYST_HIGH            1
 #define SAMPLES              5
 #define I2C_Freq             2000
 #define VALVE                1
 #define HEATER               2
-#define STATUS_GOOD          3
-#define STATUS_BAD           0
+#define GREEN_STATUS_ON      3
+#define RED_STATUS_ON        0
+#define ERROR_STATUS_ON      1
+#define STATUS_OFF           4
 #define sizeLUT              34
 #define BACK_THERM           0
 #define FRONT_THERM          1
@@ -38,6 +48,17 @@
 #define ROOM_TEMP            22
 #define MAX_HEATER_ON_TIME   25
 #define MAX_CHILL_TIME       10 //10sec
+#define MIN_ERROR_CNT_1      4    //ALL SAFETY RELATEDD CHECKS
+#define MIN_ERROR_CNT_2      600  //PEFORMANCE TIME (HAVE TO GIVE FIXTURE TIME TO SETTLE)
+#define MIN_ERROR_CNT_3      60
+#define NUM_EMAIL_SEND       2
+#define STATUS_COOLING       1
+#define STATUS_HEATING       2
+#define STATUS_INACTIVE      3
+#define STATUS_STANDBY       4
+
+#define READ_TEMP_TASK_TIME  .300f //300ms to read one A/D value
+#define I2C_READ_WAIT_TIME   0.08f
 
 // Defines for use with Serial communication
 #pragma pack (1)
@@ -49,18 +70,52 @@
 #define SET_TEMPERATURE         0xB0
 #define SELECT_CHANNEL          0xB1
 #define READ_UID                0xB2
+#define READ_FW_VERSION         0xB3
+#define DEBUG_CONTROL           0xB4
 #define RESPONSE_DATA           0xD0
 #define TEMP_DATA               0xD1
 #define UID_DATA                0xD2
+#define FW_VERSION_DATA         0xD3
 #define ERROR_DATA              0xDF
 
 
+const char FW_Version[8] =  "V0.01C";
 unsigned int chanSel_SendTemp = 0;
 unsigned int chanSel_SetTemp = 0;
 // Default to chan 0
 int currChan = 0;
 bool newTempSet = false;
+bool readFrontThermistor = true;
+bool newTempData = false;
+bool newTempDataAvailable = false;
+unsigned int UID_print_count = 0;
+unsigned int debug_control = 0x2;
 
+//***********************************************
+// Timers
+//***********************************************
+Ticker frontTempDoneTicker;
+Ticker backTempDoneTicker;
+Ticker readThermistorTicker;
+Ticker frontTempInProgTicker;
+Ticker backTempInProgTicker;
+
+//***********************************************
+// LEDs
+//***********************************************
+DigitalOut rLed(LED1);
+DigitalOut gLed(LED2);
+
+//***********************************************
+// Functions Declarations
+//***********************************************
+void sendUID ();
+void sendFWVersion();
+void read_front_temp();
+void read_back_temp();
+void update_front_temp_data();
+void update_back_temp_data();
+void temperatureDataReady();
 
 //***********************************************
 // Serial Rx Packet Format
@@ -93,6 +148,7 @@
     unsigned char cmd_type;
     unsigned char len;
     unsigned char Delim;
+    uint32_t channel;
     float data;
     unsigned char EOF_flag;
 } RESPONSE_CMD;
@@ -102,7 +158,7 @@
     unsigned char cmd_type;
     unsigned char len;
     unsigned char Delim;
-    float chTemp[CHN_COUNT];
+    float chTemp[CHAN_COUNT];
     unsigned char EOF_flag;
 } RESPONSE_TEMP_CMD;
 
@@ -114,6 +170,22 @@
 } READ_UID_CMD;
 
 typedef struct {
+    HOST_CMD_HEADER cmd_header;
+    unsigned char chanIDSel;
+    unsigned char chanDelim;
+    uint32_t commandData;
+} GUI_STANDARD_CMD;
+
+typedef struct {
+    unsigned char SOF_flag;
+    unsigned char cmd_type;
+    unsigned char len;
+    unsigned char Delim;
+    unsigned char FW_Version[8];
+    unsigned char EOF_flag;
+} FW_VERSION_RESPONSE;
+
+typedef struct {
     unsigned char SOF_flag;
     unsigned char cmd_type;
     unsigned char len;
@@ -128,59 +200,21 @@
 struct CHNL_DATA{
    bool status;
    float setTemp;
-   bool error;
-   int heater_init_time;
+   int error;
+   int state;
+   int errorEmailSent;
+   int i2cRxed;
 };
 
 CHNL_DATA chnlStatus[] = {
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
-    {0, NULL, 0, 0},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1},
+    {0, NULL, 0, 0, 0, 1}
 };
 
 
@@ -198,47 +232,7 @@
     {0x63, 0x50},
     {0x22, 0x11},
     {0x52, 0x61},
-    {0x42, 0x71},
-    {0x72, 0x41},
-    {0x62, 0x51},
-    {0x21, 0x12},
-    {0x51, 0x62},
-    {0x41, 0x72},
-    {0x71, 0x42},
-    {0x61, 0x52},
-    {0x20, 0x13},
-    {0x50, 0x63},
-    {0x40, 0x73},
-    {0x70, 0x43},
-    {0x60, 0x53},
-    {0x26, 0x14},
-    {0x56, 0x64},
-    {0x46, 0x74},
-    {0x76, 0x44},
-    {0x66, 0x54},
-    {0x2C, 0x1F},
-    {0x5C, 0x6F},
-    {0x4C, 0x7F},
-    {0x7C, 0x4F},
-    {0x6C, 0x5F},
-    {0x2D, 0x1E},
-    {0x5D, 0x6E},
-    {0x4D, 0x7E},
-    {0x7D, 0x4E},
-    {0x6D, 0x5E},
-    {0x2E, 0x1D},
-    {0x5E, 0x6D},
-    {0x4E, 0x7D},
-    {0x7E, 0x4D},
-    {0x6E, 0x5D},
-    {0x2F, 0x1C},
-    {0x5F, 0x6C},
-    {0x4F, 0x7C},
-    {0x7F, 0x4C},
-    {0x6F, 0x5C},
-    {0x20, 0x1B},
-    {0x50, 0x6B},
-    {0x40, 0x7B},
+    {0x42, 0x71}
 };
 
 //THERMISTOR LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
@@ -284,13 +278,15 @@
     {2284,125}
 };
 
+
+
 //TCTF CHANNEL TEMPERATURE
 typedef struct{
    float currTempFront;
    float currTempBack;
 }CHNL_TEMP;
 
-CHNL_TEMP channelTempData[CHN_COUNT];
+CHNL_TEMP channelTempData[CHAN_COUNT];
 
 //SERIAL COMMUNICATION SETUP
 MODSERIAL pc(USBTX, USBRX);
@@ -309,7 +305,7 @@
 volatile bool dataTxReady = false;
 char rxBuf[50];
 int chnlSel;
-
+bool standbyLED[CHAN_COUNT] = {false,false,false,false,false,false,false,false};
 
 /* Function: turnOffChannel
    **************************************************************
@@ -332,11 +328,6 @@
    Returns: N/A
 */
 
-DigitalOut rLed(LED1);
-DigitalOut gLed(LED2);
-
-void sendUID ();
-
 //***********************************************
 // Rx Interrupt from serial Host interface
 //***********************************************
@@ -344,6 +335,7 @@
 {
     gLed = 0;
     dataReceived = true;
+    //wait(.5);
     gLed = 1;
 }
 
@@ -353,7 +345,9 @@
 //***************************************************************
 void txInterrupt(MODSERIAL_IRQ_INFO *info)
 {
+    gLed = 1;
     dataTxReady = true;
+    gLed = 1;
 }
 
 
@@ -363,19 +357,20 @@
    Receives: chn: The channel we want to put into the channel
    Returns: N/A
 */
-
-void parseRXData()
+void processRxUARTData()
 {
     HOST_CMD_HEADER *pRxPktHdr;
     string data = "";
-    unsigned char *ptemp;
-    int i;
 
     pRxPktHdr = (HOST_CMD_HEADER *)rxBuf;
 
-#ifdef DEBUG
-    pc.printf("DBG: fl=%02x, len=%02x\n", pRxPktHdr->SOF_flag, pRxPktHdr->len);
-#endif
+    if (debug_control & RXDATA_PRINT) {
+        pc.printf("DBG: SOF=%02x, Len=%02x, CMD=%02x\r\n", pRxPktHdr->SOF_flag, pRxPktHdr->len, pRxPktHdr->cmd_type);
+        pc.printf("DBG: ");
+        for (int i=0; i <5; i++)
+            pc.printf("%02x ", rxBuf[i]);
+        pc.printf("\n");
+    }
 
     // Exit if the packet does not contain correct header
     // Maybe send NAK?
@@ -388,10 +383,11 @@
             // Process set temp for specified channel
             {
                 SET_TEMPERATURE_CMD *pRxPkt = (SET_TEMPERATURE_CMD *)(rxBuf);
-#ifdef DEBUG
-                pc.printf("DBG: SETTEMP: ch = %02x, tempSet = %f, chanStat = %02x\n",
-                            pRxPkt->chanID, pRxPkt->setTemp, pRxPkt->chanStat);
-#endif
+
+                if (debug_control & RXDATA_PRINT)
+                    pc.printf("DBG: SETTEMP: ch = %02x, tempSet = %f, chanStat = %02x\r\n",
+                                pRxPkt->chanID, pRxPkt->setTemp, pRxPkt->chanStat);
+
                 if ((pRxPkt->tempDelim != DELIMETER) || (pRxPkt->chanStatDelim != DELIMETER)) {
                     // Send NAK back
                     pc.printf("DBG: Error\n");
@@ -399,9 +395,11 @@
                 else {
                     chanSel_SetTemp = pRxPkt->chanID;
                     chnlStatus[pRxPkt->chanID].status = pRxPkt->chanStat;
+                    chnlStatus[pRxPkt->chanID].state = STATUS_INACTIVE;
                     chnlStatus[pRxPkt->chanID].setTemp = pRxPkt->setTemp;
                     chnlStatus[pRxPkt->chanID].error = 0;
-                    chnlStatus[pRxPkt->chanID].heater_init_time = 0;
+                    chnlStatus[pRxPkt->chanID].errorEmailSent = 0;
+                    chnlStatus[pRxPkt->chanID].i2cRxed = 0;
                     newTempSet = true;
                 }
             }
@@ -413,22 +411,44 @@
                 SELECT_CHANNEL_CMD *pRxPkt = (SELECT_CHANNEL_CMD *)(rxBuf);
 
                 chanSel_SendTemp = pRxPkt->chanIDSel;
-#ifdef DEBUG
-                pc.printf("DBG: CHAN_SEL: chan=%02x, chanStat = %02x\n", pRxPkt->chanIDSel, pRxPkt->chanStat);
-#endif
+
+                // Send back FW version for each select channel
+                sendFWVersion();
+                if (debug_control & RXDATA_PRINT)
+                    pc.printf("DBG: CHAN_SEL: chan=%02x, chanStat = %02x\r\n", pRxPkt->chanIDSel, pRxPkt->chanStat);
+
             }
             break;
 
         case READ_UID:
             {
                 READ_UID_CMD *pRxPkt = (READ_UID_CMD *)(rxBuf);
-#ifdef DEBUG
-                pc.printf("DBG: Read UID: chan%02x\n", pRxPkt->chanIDSel);
-#endif
+                if (debug_control & RXDATA_PRINT)
+                    pc.printf("DBG: Read UID: chan%02x\n", pRxPkt->chanIDSel);
+
                 sendUID();
             }
             break;
 
+        case READ_FW_VERSION:
+            {
+                sendFWVersion();
+                if (debug_control & RXDATA_PRINT)
+                    pc.printf("DBG: Read SW Version\r\n");
+
+            }
+            break;
+
+        case DEBUG_CONTROL:
+            {
+                GUI_STANDARD_CMD *pRxPkt = (GUI_STANDARD_CMD *)rxBuf;
+                debug_control = pRxPkt->commandData;
+                if (debug_control & RXDATA_PRINT)
+                    pc.printf ("DBG: Rx'd DEBUG CMD: %04x\r\n", pRxPkt->commandData);
+            }
+            break;
+
+
         default:
             // Error
             break;
@@ -439,7 +459,7 @@
    **************************************************************
    Description: Convert A/D count to temperature value
    Receives: ADC_val: the count from the A/D reading
-   Returns: the temp. of the A/D reading 
+   Returns: the temp. of the A/D reading
 */
 
 float get_temp(float ADC_val){
@@ -464,42 +484,96 @@
     float m = a/b;
     float y = (m*(ADC_val-thermLUT[i].adc))+thermLUT[i].temp;
 
-    if(DEBUG3) pc.printf("DBG: ADC VAL: %f TEMP: %f \r\n", ADC_val, y);
+    if (debug_control & ADC_VAL_PRINT)
+        pc.printf("DBG: ADC VAL: %f TEMP: %f \r\n", ADC_val, y);
 
     return y;
 }
 
-/* Function: get_temp_DATA
+/* Function: get_front_temp_DATA
    **************************************************************
-   Description: Read A/D data from LTC2487 and set array with front and back temp.
+   Description: Read A/D data from LTC2487 and set array with front temp.
+                Save values in CHNL_TEMP data struct
+   Receives: N/A
+   Returns: int If the write recieved an ACK
+*/
+void read_front_temp_data()
+{
+    readThermistorTicker.detach();
+    //Write to all 8 channels selecting the front port to read
+    for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
+        chnlStatus[chnl].i2cRxed = 0;
+        ltc2487.setAddress(addrLUT[chnl].adc);
+        //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
+        chnlStatus[chnl].i2cRxed = !ltc2487.writePort(FRONT_THERM);
+    }
+    //wait until next clock cycle on LTC
+    //wait(I2C_READ_WAIT_TIME);
+    frontTempInProgTicker.attach(&update_front_temp_data, I2C_READ_WAIT_TIME);
+}
+
+void update_front_temp_data()
+{
+    frontTempInProgTicker.detach();
+    for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
+        ltc2487.setAddress(addrLUT[chnl].adc);
+        channelTempData[chnl].currTempFront = get_temp(ltc2487.read());
+    }
+    //wait until next clock cycle on LTC
+    //wait(0.08);
+    frontTempDoneTicker.attach(&read_back_temp, I2C_READ_WAIT_TIME);
+}
+
+/* Function: get_back_temp_DATA
+   **************************************************************
+   Description: Read A/D data from LTC2487 and set array with back temp.
+                Save values in CHNL_TEMP data struct
    Receives: N/A
    Returns: N/A
 */
 
-void get_temp_data(){
+void read_back_temp()
+{
+    frontTempDoneTicker.detach();
     //Write to all 8 channels selecting the front port to read
-    for(int chnl = 0; chnl < CHN_COUNT; chnl++){
-        ltc2487.setAddress(addrLUT[chnl].adc);
-        ltc2487.writePort(FRONT_THERM);
-    }
-    //wait until next clock cycle on LTC
-    wait(0.08);
-    for(int chnl = 0; chnl < CHN_COUNT; chnl++){
+    for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
+        chnlStatus[chnl].i2cRxed = 0;
         ltc2487.setAddress(addrLUT[chnl].adc);
-        channelTempData[chnl].currTempFront = get_temp(ltc2487.read());
+        //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
+        chnlStatus[chnl].i2cRxed = !ltc2487.writePort(BACK_THERM);
     }
+
     //wait until next clock cycle on LTC
-    wait(0.08);
-    for(int chnl = 0; chnl < CHN_COUNT; chnl++){
-        ltc2487.setAddress(addrLUT[chnl].adc);
-        ltc2487.writePort(BACK_THERM);
-    }
-    //wait until next clock cycle on LTC
-    wait(0.08);
-    for(int chnl = 0; chnl < CHN_COUNT; chnl++){
+    //wait(I2C_READ_WAIT_TIME);
+    backTempInProgTicker.attach(&update_back_temp_data, I2C_READ_WAIT_TIME);
+}
+
+void update_back_temp_data()
+{
+    backTempInProgTicker.detach();
+    for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
         ltc2487.setAddress(addrLUT[chnl].adc);
         channelTempData[chnl].currTempBack = get_temp(ltc2487.read());
     }
+    //wait until next clock cycle on LTC
+    //wait(0.08);
+    backTempDoneTicker.attach(&temperatureDataReady, I2C_READ_WAIT_TIME);
+
+}
+
+/* Function: temperatureDataReady
+   **************************************************************
+   Description: Flag that temperature data is ready to be
+                processed
+                Restart task timer
+   Receives: N/A
+   Returns: N/A
+*/
+void temperatureDataReady()
+{
+    backTempDoneTicker.detach();
+    newTempDataAvailable = true;
+    readThermistorTicker.attach(&read_front_temp_data, READ_TEMP_TASK_TIME);
 }
 
 /* Function: get_heater_current
@@ -508,8 +582,7 @@
    Receives: chn: the channel of the fixture to read current from
    Returns: the current into the heater control MOSFET
 */
-
-float get_heater_current(int chn, int port){
+void get_heater_current(int chn, int port){
     ltc2487.setAddress(addrLUT[chn].adc);
     ltc2487.writePort(HEAT_FET_AMP);
     wait(0.08);
@@ -524,7 +597,7 @@
    Returns: the current into the valve control MOSFET
 */
 
-float get_valve_current(int chn, int port){
+void get_valve_current(int chn, int port){
     ltc2487.setAddress(addrLUT[chn].adc);
     ltc2487.writePort(VALVE_FET_AMP);
     wait(0.08);
@@ -593,14 +666,34 @@
 */
 
 void status_led(int chn, int status){
-    io_control.setAddress(addrLUT[chn].io);
-    if(status){
+    if(status == GREEN_STATUS_ON){
+        //green LED
+        if(debug_control & LED_PRINT) pc.printf("GREEN LED %d \r\n", chn);
+        io_control.setAddress(addrLUT[chn].io);
+        io_control.init();
         io_control.writeOutput(0,0,1,0);
     }
-    else{
+    if(status == RED_STATUS_ON){
+        //red LED
+        if(debug_control & LED_PRINT) pc.printf("RED LED %d \r\n", chn);
+        io_control.setAddress(addrLUT[chn].io);
+        io_control.init();
+        io_control.writeOutput(0,0,0,1);
+    }
+    if(status == ERROR_STATUS_ON){
         //turn valve on too
+        if(debug_control & LED_PRINT) pc.printf("RED AND BLUE LED %d \r\n", chn);
+        io_control.setAddress(addrLUT[chn].io);
+        io_control.init();
         io_control.writeOutput(1,0,0,1);
     }
+    if(status == STATUS_OFF){
+        //turn valve on too
+            if(debug_control & LED_PRINT) pc.printf("ALL OFF %d \r\n", chn);
+        io_control.setAddress(addrLUT[chn].io);
+        io_control.init();
+        io_control.writeOutput(0,0,0,0);
+    }
 }
 
 /* Function: test_mcp23008
@@ -632,7 +725,7 @@
 */
 
 void test_ltc2487(){
-    for(int chnl = 0; chnl < CHN_COUNT; chnl++){
+    for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
         float frontTemp = channelTempData[chnl].currTempFront;
         float backTemp = channelTempData[chnl].currTempBack;
         pc.printf("TEMPERATURE READING [%i]:: BACK: %f FRONT: %f \r\n", chnl, backTemp, frontTemp);
@@ -642,7 +735,8 @@
 //***************************************************************
 // Build packet with temperature readings to send to GUI
 //***************************************************************
-void sendTempReadings(){
+void processTxUARTData()
+{
     RESPONSE_TEMP_CMD response;
     unsigned char *ptr = (unsigned char *)&response;
     int i;
@@ -659,6 +753,9 @@
     response.chTemp[5] = channelTempData[5].currTempBack;
     response.chTemp[6] = channelTempData[6].currTempBack;
     response.chTemp[7] = channelTempData[7].currTempBack;
+
+    // Send Errors Count/Info
+
     /*float *dst = (float *)&response.chTemp[0];
     float *src = (float *)&channelTempData[0];
     memcpy(dst, src, sizeof(channelTempData));*/
@@ -695,6 +792,35 @@
 }
 
 //***************************************************************
+// Build packet with SW Version
+//***************************************************************
+void sendFWVersion()
+{
+    FW_VERSION_RESPONSE response;
+    unsigned char *ptr = (unsigned char *)&response;
+    int i;
+    rLed = 1;
+
+    for (i=0; i < 20; i++)
+        rLed = 0;
+
+    rLed = 1;
+
+    response.SOF_flag = TX_SOF;
+    response.cmd_type = FW_VERSION_DATA;
+    response.len = 13;
+    response.Delim = DELIMETER;
+    memcpy(response.FW_Version, FW_Version, 8);
+    response.FW_Version[7] = '\0';
+    response.EOF_flag = TX_EOF;
+
+    // Send response to GUI
+    for (i=0; i < response.len; i++, ptr++)
+        pc.printf("%02x", *ptr);
+    pc.printf("\n");
+}
+
+//***************************************************************
 // Build packet with errors to send to GUI
 //***************************************************************
 void sendError (int chan, float error)
@@ -703,17 +829,101 @@
     unsigned char *ptr = (unsigned char *)&response;
     int i;
 
+    if(chnlStatus[chan].errorEmailSent >= NUM_EMAIL_SEND)
+        return;
+
     response.SOF_flag = TX_SOF;
     response.cmd_type = ERROR_DATA;
-    response.len = 9;
+    response.len = 13;
     response.Delim = DELIMETER;
+    response.channel = chan;
     response.data = (float)error;
+
     response.EOF_flag = TX_EOF;
 
     // Send response to GUI
     for (i=0; i < response.len; i++, ptr++)
         pc.printf("%02x", *ptr);
     pc.printf("\n");
+
+    chnlStatus[chan].errorEmailSent++;
+}
+
+/* Function: toggleI2C
+   **************************************************************
+   Description: Toggle the I2C line in an attempt to unfreeze it
+   Receives: N/A
+   Returns: N/A
+*/
+
+void toggleI2C(){
+    DigitalOut ioSDAIn(PTC9);
+    DigitalOut adcSDAIn(PTC11);
+    DigitalOut ioSCLIn(PTC8);
+    DigitalOut adcSCLIn(PTC10);
+
+    ioSDAIn = 1;
+    adcSDAIn = 1;
+    ioSCLIn = 1;
+    adcSCLIn = 1;
+    wait(0.5);
+    ioSDAIn = 0;
+    adcSDAIn = 0;
+    ioSCLIn = 0;
+    adcSCLIn = 0;
+    wait(0.5);
+    ioSDAIn = 1;
+    adcSDAIn = 1;
+    ioSCLIn = 1;
+    adcSCLIn = 1;
+    wait(0.5);
+    ioSDAIn = 0;
+    adcSDAIn = 0;
+    ioSCLIn = 0;
+    adcSCLIn = 0;
+    wait(0.5);
+
+    MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
+    LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
+
+}
+
+/* Function: softwareReset
+   **************************************************************
+   Description: soft Reset
+   Recieves: N/A
+   Returns: N/A
+*/
+
+void softwareReset(void){
+    SCB->AIRCR = (0x5FA<<SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk;
+    for(;;){}
+}
+
+/* Function: read I2C Line
+   **************************************************************
+   Description: Read the I2C line to check if pulled high
+   Receives: N/A
+   Returns: N/A
+*/
+
+int readI2CLine(int line)
+{
+    if(line == IO_I2C_LINE){
+        DigitalIn ioSDAIn(PTC9);
+        int ioSDA = ioSDAIn.read();
+        if(I2C_PRINT) pc.printf("DBG: TEMPERATURE SDA LINE: %d \r\n", ioSDA);
+        MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
+        return ioSDA;
+    }
+    if(line == ADC_I2C_LINE){
+        DigitalIn adcSDAIn(PTC11);
+        int adcSDA = adcSDAIn.read();
+        if(I2C_PRINT) pc.printf("DBG: IO SDA LINE: %d \r\n", adcSDA);
+        LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
+        return adcSDA;
+    }
+    return 0;
 }
 
 /* Function: error_check
@@ -722,213 +932,260 @@
    Recieves: frontTemp: temp. of front thermistor
              backTemp: temp. of back thermistor
              currTimeMin: currentTime in minutes
+             ioSDA: voltage on the SDA line
+             adcSDA: voltage on the SDA line
    Returns: N/A
 */
 
-void error_check(int chnl, float currentTempFront, float currentTempBack, int currTimeMin, int ioSDA, int adcSDA){
-    if((currentTempFront >= MAX_TEMP) && (currentTempBack >= MAX_TEMP)){
-        status_led(chnl, STATUS_BAD);
-        sendError(chnl, 1);
-        chnlStatus[chnl].error = 1;
-        if(DEBUG3) pc.printf("DBG: [%d] ERROR 1 \r\n", chnl);
+int error_check(int chnl, float currentTempFront, float currentTempBack, int currTimeMin, int ioSDA, int adcSDA){
+    //check if the thermistors are disconnected
+    if((currentTempFront == 0) || (currentTempBack == 0)){
+        if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){
+            sendError(chnl, 2);
+            status_led(chnl, RED_STATUS_ON);
+        }
+        else{
+            chnlStatus[chnl].error++;
+        }
+        if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 2 \r\n", chnl);
+        return 1;
+    }
+    //check if the channels are disconnected
+    if(currentTempBack == currentTempFront){
+        if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){
+        sendError(chnl, 8);
+            status_led(chnl, RED_STATUS_ON);
+    }
+        else{
+            chnlStatus[chnl].error++;
+        }
+        if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 2A \r\n", chnl);
+        return 1;
     }
-    if(((currentTempFront == 0) || (currentTempBack == 0))){
-        status_led(chnl, STATUS_BAD);
-        sendError(chnl, 2);
-        chnlStatus[chnl].error = 1;
-        if(DEBUG3) pc.printf("DBG: [%d] ERROR 2 \r\n", chnl);
+
+    //check if there is a temperature difference |b| front and back
+    if((abs(currentTempBack - currentTempFront) >= TEMP_MARGIN)){
+        if(chnlStatus[chnl].error >= MIN_ERROR_CNT_2){
+            sendError(chnl, 3);
+            status_led(chnl, RED_STATUS_ON);
+        }
+        else{
+            chnlStatus[chnl].error++;
+        }
+        if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 3 \r\n", chnl);
+        return 1;
     }
-    if((abs(currentTempBack - currentTempFront) >= TEMP_MARGIN)){
-        status_led(chnl, STATUS_BAD);
-        sendError(chnl, 3);
-        chnlStatus[chnl].error = 1;
-        if(DEBUG3) pc.printf("DBG: [%d] ERROR 3 \r\n", chnl);
+    //check if channels are over the MAX temperature
+    if((currentTempFront >= MAX_TEMP) || (currentTempBack >= MAX_TEMP)){
+        //if fixture over 65C for more than ~60s
+        if(chnlStatus[chnl].error >= MIN_ERROR_CNT_3){
+            sendError(chnl, 1);
+            status_led(chnl, RED_STATUS_ON);
+            if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 1 SOFTWARE RESET %d \r\n", chnl, chnlStatus[chnl].error);
+            softwareReset();
+        }
+        //if fixture over 65C for more than ~1s
+        else if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){
+             sendError(chnl, 1);
+             status_led(chnl, RED_STATUS_ON);
+             if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 1.9 SOFTWARE RESET %d \r\n", chnl, chnlStatus[chnl].error);
+             chnlStatus[chnl].error++;
+        }
+        else{
+            chnlStatus[chnl].error++;
+        }
+        if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 1 \r\n", chnl);
+        return 1;
     }
+    //check if the valves are stuck open
     if(((currentTempFront <= MIN_TEMP) && (currentTempBack <= MIN_TEMP))){
-        status_led(chnl, STATUS_BAD);
-        sendError(chnl, 4);
-        chnlStatus[chnl].error = 1;
-        if(DEBUG3) pc.printf("DBG: [%d] ERROR 4 \r\n", chnl);
+        if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){
+            sendError(chnl, 4);
+            status_led(chnl, RED_STATUS_ON );
+        }
+        else{
+            chnlStatus[chnl].error++;
+        }
+        if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 4 \r\n", chnl);
+        return 1;
     }
-    if(chnlStatus[chnl].heater_init_time != 0){
-        int init_time = chnlStatus[chnl].heater_init_time;
-        int on_time_heater = currTimeMin - init_time;
-        //account for 0 crossover
-        if(init_time > currTimeMin){
-            on_time_heater = (60 - init_time)+currTimeMin;
-        }
 
-        if(on_time_heater > MAX_HEATER_ON_TIME){
-            status_led(chnl, STATUS_BAD);
-            sendError(chnl, 5);
-            chnlStatus[chnl].error = 1;
-            chnlStatus[chnl].heater_init_time = 0;
-            if(DEBUG3) pc.printf("DBG: [%d] ERROR 5 \r\n", chnl);
-        }
-    }
     //check that the SDA lines aren't stuck low
     if((ioSDA != 1) || (adcSDA != 1)){
-            status_led(chnl, STATUS_BAD);
-            sendError(chnl, 6);
-            chnlStatus[chnl].error = 1;
-            chnlStatus[chnl].heater_init_time = 0;
-            if(DEBUG3) pc.printf("DBG: [%d] ERROR 6 \r\n", chnl);
-    }        
-    if(chnlStatus[chnl].error == 1){
-        status_led(chnl, STATUS_BAD);
-        chnlStatus[chnl].error = 1;
+            if(chnlStatus[chnl].error >= MIN_ERROR_CNT_1){
+                sendError(chnl, 6);
+                status_led(chnl, RED_STATUS_ON );
+                softwareReset();
+            }
+            else{
+                toggleI2C();
+                chnlStatus[chnl].error++;
+            }
+            if(debug_control & ERROR_PRINT) pc.printf("DBG: [%d] ERROR 6 \r\n", chnl);
+            return 1;
     }
-    
+    //no errors
+    return 0;
 }
 
 
+/* Function: systemLogic
+   **************************************************************
+   Description: Checks for any system errors
+   Receives: Channel to modify
+   Returns: N/A
+*/
+
+void systemLogic(){
+    int chan;
+    float currTemp;
+
+    for (chan=0; chan < CHAN_COUNT; chan++)
+    {
+        if(chnlStatus[chan].status == 1){
+            //Current Temperature
+            currTemp = channelTempData[chan].currTempBack;
+
+            if(currTemp > ((chnlStatus[chan].setTemp)+HYST_HIGH)){
+                //TURN COOLING ON
+                chnlStatus[chan].state = STATUS_COOLING;
+            }
+            else if(currTemp < ((chnlStatus[chan].setTemp)-HYST_LOW)){
+                //TURN HEATER ON
+                chnlStatus[chan].state = STATUS_HEATING;
+            }
+            else{
+                //FIXTURE INACTIVE
+                chnlStatus[chan].state = STATUS_INACTIVE;
+            }
+        }
+        else{
+            //FIXTURE STANDBY
+            chnlStatus[chan].state = STATUS_STANDBY;
+        }
+    }
+
+}
+
+/* Function: systemControl
+   **************************************************************
+   Description: Checks for any system errors
+   Receives: chn: Channel to modify
+   Returns: N/A
+*/
+
+void systemControl()
+{
+    int chan;
+
+    for (chan=0; chan < CHAN_COUNT; chan++){
+        if(chnlStatus[chan].status == 1){
+            if(chnlStatus[chan].state == STATUS_COOLING){
+                //TURN COOLING ON
+                turn_valve_on(chan);
+            }
+            else if(chnlStatus[chan].state == STATUS_HEATING){
+                //TURN HEATER ON
+                turn_heater_off(chan);
+                turn_heater_on(chan);
+            }
+            else{
+                //FIXTURE INACTIVE
+                status_led(chan, GREEN_STATUS_ON );
+            }
+        }
+        else
+        {
+            //FIXTURE INACTIVE
+            if(standbyLED[chan]){
+                status_led(chan, GREEN_STATUS_ON);
+                standbyLED[chan] = !standbyLED[chan];
+            }
+            else{
+                status_led(chan, STATUS_OFF);
+                standbyLED[chan] = !standbyLED[chan];
+            }
+        }
+    }
+}
+
+void systemDiagnostic()
+{
+}
+
 /*************************************************************/
-/*                       MAIN FUNCTION                       */
+/*                       NEW MAIN FUNCTION                   */
 /*************************************************************/
 
-int main() {
-    //variables for controlling board
-    Timer t;
-    Timer t_cool;
-    int time_min = 0;
-    int init_heat_time = 0;
-    uint32_t UIDMH, UIDML, UIDL;
-
+int main(){
+    /* INITIALIZATION CODE */
     // Setup serial port
     // Look for RX_EOF
+    uint32_t UIDMH, UIDML, UIDL;
+    int UID_print_count = 0;
+
+
+    //*********************************
+    // Initial thermistors readings
+    // Kick off temperature reding
+    // state machine
+    //*********************************
+    readThermistorTicker.attach(&read_front_temp_data, .0001);
+
     pc.baud(9600);
     pc.autoDetectChar(RX_EOF);
     pc.attach(&rxInterrupt, MODSERIAL::RxAutoDetect);
 
-    myled = 1;
-    rLed = 1;
-    gLed = 0;
-
-    t.start();
-
-    sendUID();
-
     UIDMH = (uint32_t)SIM->UIDMH;
     UIDML = (uint32_t)SIM->UIDML;
     UIDL = (uint32_t)SIM->UIDL;
 
-    //print UID once
-    if(UID_PRINT) pc.printf("DBG: <%f>[UID: %04X%08X%08X] PSTARTED\n", t.read(), UIDMH, UIDML, UIDL);
+    //print UID three times on start-up to ID Mbed board
+    if(UID_print_count++ < 3)
+        pc.printf("DBG: [UID: %04X%08X%08X]\n", UIDMH, UIDML, UIDL);
+
 
     while(1) {
-        //test_mcp23008(0);
-
-        //SETUP TIMER USED TO TRACK HOW LONG THE HEATER IS ON
-        float time_sec = t.read();
+        //*********************************
+        // Process Rx UART data from GUI
+        //*********************************
+        if (dataReceived)
+        {
+            dataReceived = false;
+            if (debug_control & RXDATA_PRINT)
+                pc.printf("DBG: %d bytes Rx'd\n", pc.rxBufferGetCount());
 
-        if(time_sec >= 60){
-            time_min++;
-            //time_sec = 0;
-            t.reset();
+            pc.move(rxBuf, 50);
+            processRxUARTData();
+            pc.rxBufferFlush();
         }
 
-        if(time_min >= 60){
-           time_min = 0;
-        }
-        
-        //GET TEMPERATURE DATA
-        get_temp_data();
-
-        //SEND TEMPERATURE DATA FOR LOGGING
-        sendTempReadings();
-        
-        time_sec = t.read();
-        if(LOOP_TIME) pc.printf("DBG: TIME: %f s\n", time_sec);
-
-        //CONTROL LOOP: LOOPS THROUGH EVERY CHANNEL AND CONTROLS THE FIXTURE IN RESPONSE
-        for(int chnl = 0; chnl < CHN_COUNT; chnl++){
+        //*********************************
+        // Logic Loop
+        //*********************************
+        // System Logic/Control
+        if (newTempDataAvailable)
+            systemLogic();
 
-            //check if we received data/need to update TCTF data
-            if(dataReceived){
-                dataReceived = false;
-#ifdef DEBUG
-                pc.printf("DBG: %d bytes Rx'd\n", pc.rxBufferGetCount());
-#endif
-                pc.move(rxBuf, 50);
-                parseRXData();
-                pc.rxBufferFlush();
-            }
-
-            //update channel temperature data
-            float currentTempFront = channelTempData[chnl].currTempFront;
-            float currentTempBack = channelTempData[chnl].currTempBack;
-            
-            //float currentTempBack = get_temp(chnl, BACK_THERM);
-            float currentTemp = currentTempBack;
-            
-            //check if I2C dataline is pulled high
-            DigitalIn isoSDAIn(PTC9);
-            DigitalIn adcSDAIn(PTC11);
-            int isoSDA = isoSDAIn.read();
-            int adcSDA = adcSDAIn.read();
-            pc.printf("DBG: TEMPERATURE SDA LINE: %d \r\n", isoSDA);
-            pc.printf("DBG: IO SDA LINE: %d \r\n", adcSDA);
-            MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
-            LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
-
-            //Error check on fixture
-            error_check(chnl, currentTempFront, currentTempBack, time_min, isoSDA, adcSDA);
+        //*********************************
+        // System Diagnostic & Error Check
+        //*********************************
+        systemDiagnostic();
 
-            if(TEMP_PRINT) pc.printf("DBG: TEMPERATURE: [%d] Temp: F: %f B: %f\r\n", chnl, currentTempFront, currentTempBack);
-            
-            //CONTROL LOOP:
-            if(chnlStatus[chnl].status == 1){
-                if(DEBUG) pc.printf("DBG: [%d] Temp: F: %f B: %f\r\n", chnl, currentTempFront, currentTempBack);
-                //main loop for channels
-                if(chnlStatus[chnl].error == 0){
-                    if(currentTemp > ((chnlStatus[chnl].setTemp)+HYST_HIGH)){
-                        if(DEBUG) pc.printf("DBG: [%d] Chiller ON \r\n", chnl);
-                        //reset heater on time
-                        chnlStatus[chnl].heater_init_time = 0;
-                        //Turn chiller on
-                        turn_valve_on(chnl);
-                    }
-                    else if (currentTemp < ((chnlStatus[chnl].setTemp)-HYST_LOW)){
-                        if(DEBUG) pc.printf("DBG: [%d] Heater ON \r\n", chnl);
-                        //establish starting time for heater
-                        if(chnlStatus[chnl].heater_init_time == 0){ //check if it is the first time that heater has turned on
-                            //make sure time isn't zero, otherwise keeping looping until we are not at 0
-                            if(time_min != 0){
-                                chnlStatus[chnl].heater_init_time = time_min;
-                            }
-                        }
-                        if(DEBUG2) pc.printf("DBG: TIME ON: %d %d %f %d %d\r\n", chnlStatus[chnl].heater_init_time, time_min, time_sec, init_heat_time, (chnlStatus[chnl].heater_init_time == NULL));
-                        //Turn heater on
-                        turn_heater_on(chnl);
-                    }
-                    else{
-                        if(DEBUG) pc.printf("DBG: [%d] All OFF \r\n", chnl);
-                        //reset heater on time
-                        chnlStatus[chnl].heater_init_time = 0;
-                        //turn off chiller
-                        turn_valve_off(chnl);
-                        //turn off heater
-                        turn_heater_off(chnl);
-                        //turn on green LED status light
-                        status_led(chnl, 1);
-                    }
-                }
-            }
-            else{
-                if(chnlStatus[chnl].error == 0){
-                //turn off chiller
-                turn_valve_off(chnl);
-                //turn off heater
-                turn_heater_off(chnl);
-                //turn on green LED status light
-                status_led(chnl, 1);
-                }
-                else{
-                    status_led(chnl, STATUS_BAD);
-                }
-                //reset heater on time
-                chnlStatus[chnl].heater_init_time = 0;
-            }
+        //*********************************
+        // Process Tx UART data
+        // Send Temperature Data/Error to GUI
+        //*********************************
+        if (newTempDataAvailable)
+        {
+            processTxUARTData();
+
+            //*********************************
+            //Actuate Loop
+            //*********************************
+            systemControl();
+            newTempDataAvailable = false;
         }
     }
-}
\ No newline at end of file
+
+}