Working on rewriting how we acquire data from LTC chip and sending all temp data over serial for python logging

Dependencies:   MODSERIAL mbed

Fork of TCTF_Control_Main by Rivian Irvine Team

main.cpp

Committer:
jrodenburg
Date:
2018-06-15
Revision:
18:029a1283a878
Parent:
17:5098d8fbb298
Child:
19:fec49ef9944b

File content as of revision 18:029a1283a878:

// 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 CHN_COUNT            8
#define MIN_TEMP             10
#define MAX_TEMP             65
#define TEMP_MARGIN          20
#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 sizeLUT              34
#define BACK_THERM           0
#define FRONT_THERM          1
#define HEAT_FET_AMP         2
#define VALVE_FET_AMP        3
#define FET_ON_CURRENT       1.12
#define ROOM_TEMP            22
#define MAX_HEATER_ON_TIME   25
#define MAX_CHILL_TIME       10 //10sec

// Defines for use with Serial communication
#pragma pack (1)
#define RX_SOF                  0x7B
#define RX_EOF                  0x7D
#define TX_SOF                  0x7B
#define TX_EOF                  0x7D
#define DELIMETER               0x2E
#define SET_TEMPERATURE         0xB0
#define SELECT_CHANNEL          0xB1
#define READ_UID                0xB2
#define RESPONSE_DATA           0xD0
#define TEMP_DATA               0xD1
#define UID_DATA                0xD2
#define ERROR_DATA              0xDF


unsigned int chanSel_SendTemp = 0;
unsigned int chanSel_SetTemp = 0;
// Default to chan 0
int currChan = 0;
bool newTempSet = false;


//***********************************************
// Serial Rx Packet Format
//***********************************************
typedef struct {
    unsigned char SOF_flag;
    unsigned char cmd_type;
    unsigned char len;
    unsigned char Delim;
} HOST_CMD_HEADER;

typedef struct {
    HOST_CMD_HEADER cmd_header;
    unsigned char chanID;
    unsigned char tempDelim;
    float setTemp;
    unsigned char chanStatDelim;
    unsigned char chanStat;
} SET_TEMPERATURE_CMD;

typedef struct {
    HOST_CMD_HEADER cmd_header;
    unsigned char chanIDSel;
    unsigned char chanDelim;
    unsigned char chanStat;
} SELECT_CHANNEL_CMD;

typedef struct {
    unsigned char SOF_flag;
    unsigned char cmd_type;
    unsigned char len;
    unsigned char Delim;
    float data;
    unsigned char EOF_flag;
} RESPONSE_CMD;

typedef struct {
    unsigned char SOF_flag;
    unsigned char cmd_type;
    unsigned char len;
    unsigned char Delim;
    float chTemp[CHN_COUNT];
    unsigned char EOF_flag;
} RESPONSE_TEMP_CMD;

typedef struct {
    HOST_CMD_HEADER cmd_header;
    unsigned char chanIDSel;
    unsigned char chanDelim;
    unsigned char chanStat;
} READ_UID_CMD;

typedef struct {
    unsigned char SOF_flag;
    unsigned char cmd_type;
    unsigned char len;
    unsigned char Delim;
    uint32_t UIDMH;
    uint32_t UIDML;
    uint32_t UIDL;
    unsigned char EOF_flag;
} UID_RESPONSE;

//TCTF CHANNEL DATA
struct CHNL_DATA{
   bool status;
   float setTemp;
   bool error;
   int heater_init_time;
};

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},
};


//I2C AADRESS LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
struct I2C_ADDR_LUT{
   int adc;
   int io;
};

I2C_ADDR_LUT addrLUT[] = {
    {0x23, 0x10},
    {0x53, 0x60},
    {0x43, 0x70},
    {0x73, 0x40},
    {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},
};

//THERMISTOR LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
struct THERM_LUT{
   int adc;
   int temp;
};

THERM_LUT thermLUT[] = {
    {113779,-40},
    {109152,-35},
    {103830,-30},
    {97855,-25},
    {91319,-20},
    {84352,-15},
    {77124,-10},
    {69820,-5},
    {62621,0},
    {55693,5},
    {49169,10},
    {43144,15},
    {37669,20},
    {32768,25},
    {28429,30},
    {24622,35},
    {21309,40},
    {18439,45},
    {15962,50},
    {13831,55},
    {12002,60},
    {10428,65},
    {9080,70},
    {7919,75},
    {6923,80},
    {6063,85},
    {5323,90},
    {4685,95},
    {4130,100},
    {3653,105},
    {3234,110},
    {2876,115},
    {2563,120},
    {2284,125}
};

//TCTF CHANNEL TEMPERATURE
typedef struct{
   float currTempFront;
   float currTempBack;
}CHNL_TEMP;

CHNL_TEMP channelTempData[CHN_COUNT];

//SERIAL COMMUNICATION SETUP
MODSERIAL pc(USBTX, USBRX);

//DEFINE PINS
DigitalOut myled(LED2);

//I2C FOR MCP23008 (I/O Control)
MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl

//I2C FOR LTC2487 (ADC Control)
LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl

//GLOBAL VARIABLES
volatile bool dataReceived = false; //used to check if data has been received
volatile bool dataTxReady = false;
char rxBuf[50];
int chnlSel;


/* Function: turnOffChannel
   **************************************************************
   Description: Turns off a channel
   Recieves: chnl: channel to turn off
   Returns: N/A
*/

void turnOffChannel(int chnl){
    io_control.setAddress(addrLUT[chnl].io);
    io_control.init();
    io_control.writeOutput(0,0,0,0);
}


/* Function: rxInterrupt
   **************************************************************
   Description: serial rx interupt handler
   Receives: N/A
   Returns: N/A
*/

DigitalOut rLed(LED1);
DigitalOut gLed(LED2);

void sendUID ();

//***********************************************
// Rx Interrupt from serial Host interface
//***********************************************
void rxInterrupt(MODSERIAL_IRQ_INFO *info)
{
    gLed = 0;
    dataReceived = true;
    gLed = 1;
}


//***************************************************************
// Tx Interrupt from serial Host interface
//***************************************************************
void txInterrupt(MODSERIAL_IRQ_INFO *info)
{
    dataTxReady = true;
}


/* Function: parseRXData
   **************************************************************
   Description: The parse received data into
   Receives: chn: The channel we want to put into the channel
   Returns: N/A
*/

void parseRXData()
{
    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

    // Exit if the packet does not contain correct header
    // Maybe send NAK?
    if ((pRxPktHdr->SOF_flag != RX_SOF) || (pRxPktHdr->Delim != DELIMETER))
        return;

    switch (pRxPktHdr->cmd_type)
    {
        case SET_TEMPERATURE:
            // 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 ((pRxPkt->tempDelim != DELIMETER) || (pRxPkt->chanStatDelim != DELIMETER)) {
                    // Send NAK back
                    pc.printf("DBG: Error\n");
                }
                else {
                    chanSel_SetTemp = pRxPkt->chanID;
                    chnlStatus[pRxPkt->chanID].status = pRxPkt->chanStat;
                    chnlStatus[pRxPkt->chanID].setTemp = pRxPkt->setTemp;
                    chnlStatus[pRxPkt->chanID].error = 0;
                    chnlStatus[pRxPkt->chanID].heater_init_time = 0;
                    newTempSet = true;
                }
            }
            break;

        case SELECT_CHANNEL:
            // Select channel to send temp data to
            {
                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
            }
            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
                sendUID();
            }
            break;

        default:
            // Error
            break;
    }
}

/* Function: get_temp
   **************************************************************
   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 
*/

float get_temp(float ADC_val){
    myled = 1;
    //ltc2487.setAddress(addrLUT[chn].adc);

    //float ADC_val = ltc2487.readOutput(port); //(65536*1.334)/2.5

    int i = 0;

    while((i < sizeLUT) && (thermLUT[i].adc > ADC_val)){
        i++;
    }  //find the temp. above therm temp

    //Point slope formula extrapolation:
    // m = (y1-y0)/(x1-x0)+ y0 , y = temp. value, x = adc value
    // y1 = thermLUT[i-1].temp   y0 = thermLUT[i].temp
    // x1 = thermLUT[i-1].adc    x0 =thermLUT[i].adc
    float a = float(thermLUT[i-1].temp - thermLUT[i].temp); //slope of temp between points where therm temp is between (Tmax - Tmin)
    float b = float(thermLUT[i-1].adc - thermLUT[i].adc);   //slope of adc between points where therm adc is between (Amax - Amin)

    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);

    return y;
}

/* Function: get_temp_DATA
   **************************************************************
   Description: Read A/D data from LTC2487 and set array with front and back temp.
   Receives: N/A
   Returns: N/A
*/

void get_temp_data(){
    //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++){
        ltc2487.setAddress(addrLUT[chnl].adc);
        channelTempData[chnl].currTempFront = get_temp(ltc2487.read());
    }
    //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++){
        ltc2487.setAddress(addrLUT[chnl].adc);
        channelTempData[chnl].currTempBack = get_temp(ltc2487.read());
    }
}

/* Function: get_heater_current
   **************************************************************
   Description: Retrieve current into heater control MOSFET
   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){
    ltc2487.setAddress(addrLUT[chn].adc);
    ltc2487.writePort(HEAT_FET_AMP);
    wait(0.08);
    ltc2487.read();
    wait(0.08);
}

/* Function: get_valve_current
   **************************************************************
   Description: Retrieve current into valve control MOSFET
   Receives: chn: the channel of the fixture to read current from
   Returns: the current into the valve control MOSFET
*/

float get_valve_current(int chn, int port){
    ltc2487.setAddress(addrLUT[chn].adc);
    ltc2487.writePort(VALVE_FET_AMP);
    wait(0.08);
    ltc2487.read();
    wait(0.08);
}

/* Function: turn_valve_on
   **************************************************************
   Description: Turn valve on and green status LED on
   Receives: chn: the channel of the fixture
   Returns: N/A
*/

void turn_valve_on(int chn){
    io_control.setAddress(addrLUT[chn].io);
    io_control.init();
    io_control.writeOutput(1,0,1,0);
}

/* Function: turn_valve_off
   **************************************************************
   Description: Turn valve off and green status LED on
   Receives: chn: the channel of the fixture
   Returns: N/A
*/

void turn_valve_off(int chn){
    io_control.setAddress(addrLUT[chn].io);
    io_control.init();
    io_control.writeOutput(0,0,1,0);
}

/* Function: turn_heater_on
   **************************************************************
   Description: Turn heater on and green status LED on
   Receives: chn: the channel of the fixture
   Returns: N/A
*/

void turn_heater_on(int chn){
    io_control.setAddress(addrLUT[chn].io);
    io_control.init();
    io_control.writeOutput(0,1,1,0);
}

/* Function: turn_heater_off
   **************************************************************
   Description: Turn heater off and green status LED on
   Receives: chn: the channel of the fixture
   Returns: N/A
*/

void turn_heater_off(int chn){
    io_control.setAddress(addrLUT[chn].io);
    io_control.init();
    io_control.writeOutput(0,0,1,0);
}

/* Function: status_led
   **************************************************************
   Description: Turn status LED on (turns on green or red)
   Receives: chn: the channel of the fixture
             status: the status of channel (good (1) or bad (0))
   Returns: N/A
*/

void status_led(int chn, int status){
    io_control.setAddress(addrLUT[chn].io);
    if(status){
        io_control.writeOutput(0,0,1,0);
    }
    else{
        //turn valve on too
        io_control.writeOutput(1,0,0,1);
    }
}

/* Function: test_mcp23008
   **************************************************************
   Description: Test each output of the MCP23009
   Receives: N/A
   Returns: N/A
*/

void test_mcp23008(int chn){
    turn_valve_on(chn);
    wait(0.5);
    turn_valve_off(chn);
    wait(0.5);
    turn_heater_on(chn);
    wait(0.5);
    turn_heater_off(chn);
    wait(0.5);
    status_led(chn, 0);
    wait(0.5);
    status_led(chn, 1);
}

/* Function: test_ltc2487
   **************************************************************
   Description: Test the reading from LTC2487
   Receives: N/A
   Returns: N/A
*/

void test_ltc2487(){
    for(int chnl = 0; chnl < CHN_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);
    }
}

//***************************************************************
// Build packet with temperature readings to send to GUI
//***************************************************************
void sendTempReadings(){
    RESPONSE_TEMP_CMD response;
    unsigned char *ptr = (unsigned char *)&response;
    int i;

    response.SOF_flag = TX_SOF;
    response.cmd_type = TEMP_DATA;
    response.len = 5+(sizeof(response.chTemp));
    response.Delim = DELIMETER;
    response.chTemp[0] = channelTempData[0].currTempBack;
    response.chTemp[1] = channelTempData[1].currTempBack;
    response.chTemp[2] = channelTempData[2].currTempBack;
    response.chTemp[3] = channelTempData[3].currTempBack;
    response.chTemp[4] = channelTempData[4].currTempBack;
    response.chTemp[5] = channelTempData[5].currTempBack;
    response.chTemp[6] = channelTempData[6].currTempBack;
    response.chTemp[7] = channelTempData[7].currTempBack;
    /*float *dst = (float *)&response.chTemp[0];
    float *src = (float *)&channelTempData[0];
    memcpy(dst, src, sizeof(channelTempData));*/
    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 Board UID (Unique Identification)
//***************************************************************
void sendUID ()
{
    UID_RESPONSE response;
    unsigned char *ptr = (unsigned char *)&response;
    int i;

    response.SOF_flag = TX_SOF;
    response.cmd_type = UID_DATA;
    response.len = 17;
    response.Delim = DELIMETER;
    response.UIDMH = (uint32_t)SIM->UIDMH;
    response.UIDML = (uint32_t)SIM->UIDML;
    response.UIDL = (uint32_t)SIM->UIDL;
    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)
{
    RESPONSE_CMD response;
    unsigned char *ptr = (unsigned char *)&response;
    int i;

    response.SOF_flag = TX_SOF;
    response.cmd_type = ERROR_DATA;
    response.len = 9;
    response.Delim = DELIMETER;
    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");
}

/* Function: error_check
   **************************************************************
   Description: Checks for any system errors
   Recieves: frontTemp: temp. of front thermistor
             backTemp: temp. of back thermistor
             currTimeMin: currentTime in minutes
   Returns: N/A
*/

void error_check(int chnl, float currentTempFront, float currentTempBack, int currTimeMin){
    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);
    }
    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);
    }
    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);
    }
    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].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);
        }
    }
    if(chnlStatus[chnl].error == 1){
        status_led(chnl, STATUS_BAD);
        chnlStatus[chnl].error = 1;
    }
}


/*************************************************************/
/*                       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;

    // Setup serial port
    // Look for RX_EOF
    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;

    while(1) {
        //test_mcp23008(0);
        if(DEBUG3) {
            pc.printf("DBG: <%f>[UID: %04X%08X%08X] PSTARTED\n", t.read(), UIDMH, UIDML, UIDL);
        }

        //SETUP TIMER USED TO TRACK HOW LONG THE HEATER IS ON
        float time_sec = t.read();

        if(time_sec >= 60){
            time_min++;
            //time_sec = 0;
            t.reset();
        }

        if(time_min >= 60){
           time_min = 0;
        }
        
        //GET TEMPERATURE DATA
        get_temp_data();

        //SEND TEMPERATURE DATA FOR LOGGING
        sendTempReadings();
        
        time_sec = t.read();
        pc.printf("\r TIME: %f s\r\n", time_sec);

        //CONTROL LOOP: LOOPS THROUGH EVERY CHANNEL AND CONTROLS THE FIXTURE IN RESPONSE
        for(int chnl = 0; chnl < CHN_COUNT; chnl++){

            //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;

            //Error check on fixture
            error_check(chnl, currentTempFront, currentTempBack, time_min);

            if(DEBUG5) pc.printf("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;
            }
        }
    }
}