Rivian Irvine Team / Mbed 2 deprecated TCTF_Control_Main

Dependencies:   MODSERIAL mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 // MBED SCRIPT FOR CONTROLLING THE TEMPERATURE CONTROLLED TEST FIXTURE (TCTF)
00002 // DATE: SEPTEMBER 2017
00003 //CHANGE THE PYTHON CODE TO REFLECT ERROR STATE ENTERED
00004 
00005 #include "mbed.h"
00006 #include "MODSERIAL.h"
00007 #include "MCP23008.h"
00008 #include "LTC2487.h"
00009 #include <string>
00010 
00011 
00012 //DEFINITIVE VARIABLES
00013 #define DEBUG_LOOP_TIME      0x00000001
00014 #define RXDATA_PRINT         0x00000002
00015 #define UID_PRINT            0x00000004
00016 #define ERROR_PRINT          0x00000008
00017 #define ADC_VAL_PRINT        0x00000010
00018 #define HEATER_CHILLER_PRINT 0x00000020
00019 #define HEATER_ON_TIME_PRINT 0x00000040
00020 #define LED_PRINT            0x00000080
00021 #define TEMP_PRINT           0x00000100
00022 #define I2C_PRINT            0x00000200
00023 
00024 #define IO_I2C_LINE          1
00025 #define ADC_I2C_LINE         2
00026 
00027 #define CHAN_COUNT           8
00028 #define ERROR_COUNT          6
00029 #define MIN_TEMP             10
00030 #define MAX_TEMP             65
00031 #define TEMP_MARGIN          10
00032 #define HYST_LOW             0.3
00033 #define HYST_HIGH            1
00034 #define VALVE_ON             1
00035 #define HEATER_ON            2
00036 #define GREEN_STATUS_ON      3
00037 #define RED_STATUS_ON        4
00038 #define ERROR_STATUS_ON      5
00039 #define ALL_OFF              6
00040 #define sizeLUT              34
00041 #define BACK_THERM           0
00042 #define FRONT_THERM          1
00043 #define HEAT_FET_AMP         2
00044 #define VALVE_FET_AMP        3
00045 #define NUM_EMAIL_SEND       2
00046 #define STATUS_COOLING       1
00047 #define STATUS_HEATING       2
00048 #define STATUS_INACTIVE      3
00049 #define STATUS_STANDBY       4
00050 #define MIN_AD_COUNT         10428 //65C
00051 #define MAX_AD_COUNT         49169 //10C
00052 #define MAX_TIME_TO_SP       60    //allow 60 minutes for channel to reach set point
00053 
00054 #define READ_TEMP_TASK_TIME  .300f //300ms to read one A/D value
00055 #define I2C_READ_WAIT_TIME   0.08f
00056 
00057 // Defines for use with Serial communication
00058 #pragma pack (1)
00059 #define RX_SOF                  0x7B
00060 #define RX_EOF                  0x7D
00061 #define TX_SOF                  0x7B
00062 #define TX_EOF                  0x7D
00063 #define DELIMETER               0x2E
00064 #define SET_TEMPERATURE         0xB0
00065 #define SELECT_CHANNEL          0xB1
00066 #define READ_UID                0xB2
00067 #define READ_FW_VERSION         0xB3
00068 #define DEBUG_CONTROL           0xB4
00069 #define RESPONSE_DATA           0xD0
00070 #define TEMP_DATA               0xD1
00071 #define UID_DATA                0xD2
00072 #define FW_VERSION_DATA         0xD3
00073 #define ERROR_DATA              0xDF
00074 
00075 // Defines for errors
00076 #define ERR_OVER_TEMP           0
00077 #define ERR_UNDER_TEMP          1
00078 #define ERR_TEMP_DIFF           2
00079 #define ERR_ACK_LTC             3
00080 #define ERR_ACK_MCP             4
00081 #define ERR_SP_TIME             5
00082 #define MAX_ERROR_CNT           8
00083 
00084 #define PRINT_ERROR_CHECK_VALS  0
00085 #define PRINT_ERRORS            0
00086 
00087 
00088 
00089 
00090 const char FW_Version[8] =  "V0.01D";
00091 unsigned int chanSel_SendTemp = 0;
00092 unsigned int chanSel_SetTemp = 0;
00093 // Default to chan 0
00094 int currChan = 0;
00095 bool newTempSet = false;
00096 bool readFrontThermistor = true;
00097 bool newTempData = false;
00098 bool newTempDataAvailable = false;
00099 unsigned int UID_print_count = 0;
00100 unsigned int debug_control = 0x80;
00101 
00102 //***********************************************
00103 // Timers
00104 //***********************************************
00105 Ticker frontTempDoneTicker;
00106 Ticker backTempDoneTicker;
00107 Ticker readThermistorTicker;
00108 Ticker frontTempInProgTicker;
00109 Ticker backTempInProgTicker;
00110 Ticker setPointTimeTicker;
00111 
00112 //***********************************************
00113 // LEDs
00114 //***********************************************
00115 DigitalOut rLed(LED1);
00116 DigitalOut gLed(LED2);
00117 
00118 //***********************************************
00119 // Functions Declarations
00120 //***********************************************
00121 void sendUID ();
00122 void sendFWVersion();
00123 void read_front_temp();
00124 void read_back_temp();
00125 void update_front_temp_data();
00126 void update_back_temp_data();
00127 void temperatureDataReady();
00128 
00129 //***********************************************
00130 // Serial Rx Packet Format
00131 //***********************************************
00132 typedef struct {
00133     unsigned char SOF_flag;
00134     unsigned char cmd_type;
00135     unsigned char len;
00136     unsigned char Delim;
00137 } HOST_CMD_HEADER;
00138 
00139 typedef struct {
00140     HOST_CMD_HEADER cmd_header;
00141     unsigned char chanID;
00142     unsigned char tempDelim;
00143     float setTemp;
00144     unsigned char chanStatDelim;
00145     unsigned char chanStat;
00146 } SET_TEMPERATURE_CMD;
00147 
00148 typedef struct {
00149     HOST_CMD_HEADER cmd_header;
00150     unsigned char chanIDSel;
00151     unsigned char chanDelim;
00152     unsigned char chanStat;
00153 } SELECT_CHANNEL_CMD;
00154 
00155 typedef struct {
00156     unsigned char SOF_flag;
00157     unsigned char cmd_type;
00158     unsigned char len;
00159     unsigned char Delim;
00160     uint32_t channel;
00161     float data;
00162     unsigned char EOF_flag;
00163 } RESPONSE_CMD;
00164 
00165 typedef struct {
00166     unsigned char SOF_flag;
00167     unsigned char cmd_type;
00168     unsigned char len;
00169     unsigned char Delim;
00170     float chTemp[CHAN_COUNT];
00171     unsigned char EOF_flag;
00172 } RESPONSE_TEMP_CMD;
00173 
00174 typedef struct {
00175     HOST_CMD_HEADER cmd_header;
00176     unsigned char chanIDSel;
00177     unsigned char chanDelim;
00178     unsigned char chanStat;
00179 } READ_UID_CMD;
00180 
00181 typedef struct {
00182     HOST_CMD_HEADER cmd_header;
00183     unsigned char chanIDSel;
00184     unsigned char chanDelim;
00185     uint32_t commandData;
00186 } GUI_STANDARD_CMD;
00187 
00188 typedef struct {
00189     unsigned char SOF_flag;
00190     unsigned char cmd_type;
00191     unsigned char len;
00192     unsigned char Delim;
00193     unsigned char FW_Version[8];
00194     unsigned char EOF_flag;
00195 } FW_VERSION_RESPONSE;
00196 
00197 typedef struct {
00198     unsigned char SOF_flag;
00199     unsigned char cmd_type;
00200     unsigned char len;
00201     unsigned char Delim;
00202     uint32_t UIDMH;
00203     uint32_t UIDML;
00204     uint32_t UIDL;
00205     unsigned char EOF_flag;
00206 } UID_RESPONSE;
00207 
00208 //TCTF CHANNEL DATA
00209 struct CHNL_DATA{
00210    bool status;
00211    float setTemp;
00212    bool error;
00213    int state;
00214    int LTCi2cAckRxed;
00215    int MCPi2cAckRxed;
00216    bool SPReached;
00217    int SPTime;
00218 };
00219 
00220 CHNL_DATA chnlStatus[] = {
00221     {0, NULL, false, 0, 0, 0, false, 0},
00222     {0, NULL, false, 0, 0, 0, false, 0},
00223     {0, NULL, false, 0, 0, 0, false, 0},
00224     {0, NULL, false, 0, 0, 0, false, 0},
00225     {0, NULL, false, 0, 0, 0, false, 0},
00226     {0, NULL, false, 0, 0, 0, false, 0},
00227     {0, NULL, false, 0, 0, 0, false, 0},
00228     {0, NULL, false, 0, 0, 0, false, 0}
00229 };
00230 
00231 
00232 //I2C AADRESS LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
00233 struct I2C_ADDR_LUT{
00234    int adc;
00235    int io;
00236 };
00237 
00238 I2C_ADDR_LUT addrLUT[] = {
00239     {0x23, 0x10},
00240     {0x53, 0x60},
00241     {0x43, 0x70},
00242     {0x73, 0x40},
00243     {0x63, 0x50},
00244     {0x22, 0x11},
00245     {0x52, 0x61},
00246     {0x42, 0x71}
00247 };
00248 
00249 //THERMISTOR LOOK UP TABLE, CREATED IN EXCEL SHEET (COUNT, TEMP)
00250 struct THERM_LUT{
00251    int adc;
00252    int temp;
00253 };
00254 
00255 THERM_LUT thermLUT[] = {
00256     {113779,-40},
00257     {109152,-35},
00258     {103830,-30},
00259     {97855,-25},
00260     {91319,-20},
00261     {84352,-15},
00262     {77124,-10},
00263     {69820,-5},
00264     {62621,0},
00265     {55693,5},
00266     {49169,10},
00267     {43144,15},
00268     {37669,20},
00269     {32768,25},
00270     {28429,30},
00271     {24622,35},
00272     {21309,40},
00273     {18439,45},
00274     {15962,50},
00275     {13831,55},
00276     {12002,60},
00277     {10428,65},
00278     {9080,70},
00279     {7919,75},
00280     {6923,80},
00281     {6063,85},
00282     {5323,90},
00283     {4685,95},
00284     {4130,100},
00285     {3653,105},
00286     {3234,110},
00287     {2876,115},
00288     {2563,120},
00289     {2284,125}
00290 };
00291 
00292 
00293 
00294 //TCTF CHANNEL TEMPERATURE
00295 typedef struct{
00296    float currADCFront;
00297    float currADCBack;
00298    float currTempFront;
00299    float currTempBack;
00300 }CHNL_TEMP;
00301 
00302 CHNL_TEMP channelTempData[CHAN_COUNT];
00303 
00304 //SERIAL COMMUNICATION SETUP
00305 MODSERIAL pc(USBTX, USBRX);
00306 
00307 //DEFINE PINS
00308 DigitalOut myled(LED2);
00309 
00310 //I2C FOR MCP23008 (I/O Control)
00311 MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
00312 
00313 //I2C FOR LTC2487 (ADC Control)
00314 LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
00315 
00316 //GLOBAL VARIABLES
00317 volatile bool dataReceived = false; //used to check if data has been received
00318 volatile bool dataTxReady = false;
00319 char rxBuf[50];
00320 int chnlSel;
00321 bool standbyLED[CHAN_COUNT] = {false,false,false,false,false,false,false,false};
00322 
00323 int errorCount[CHAN_COUNT][ERROR_COUNT] =
00324     {
00325         {0,0,0,0,0,0},
00326         {0,0,0,0,0,0},
00327         {0,0,0,0,0,0},
00328         {0,0,0,0,0,0},
00329         {0,0,0,0,0,0},
00330         {0,0,0,0,0,0},
00331         {0,0,0,0,0,0},
00332         {0,0,0,0,0,0}
00333     };
00334 
00335 int errorEmailSent[CHAN_COUNT][ERROR_COUNT] =
00336     {
00337         {0,0,0,0,0,0},
00338         {0,0,0,0,0,0},
00339         {0,0,0,0,0,0},
00340         {0,0,0,0,0,0},
00341         {0,0,0,0,0,0},
00342         {0,0,0,0,0,0},
00343         {0,0,0,0,0,0},
00344         {0,0,0,0,0,0}
00345     };
00346     
00347 void resetErrorCount(){
00348    for(int i = 0; i < CHAN_COUNT; i++){
00349        for(int i = 0; i < ERROR_COUNT; i++){
00350            errorCount[CHAN_COUNT][ERROR_COUNT] = 0;
00351            errorEmailSent[CHAN_COUNT][ERROR_COUNT] = 0;
00352         }
00353     } 
00354 }
00355 
00356 /* Function: turnOffChannel
00357    **************************************************************
00358    Description: Turns off a channel
00359    Recieves: chnl: channel to turn off
00360    Returns: N/A
00361 */
00362 
00363 void turnOffChannel(int chnl){
00364     io_control.setAddress(addrLUT[chnl].io);
00365     io_control.init();
00366     io_control.writeOutput(0,0,0,0);
00367 }
00368 
00369 
00370 /* Function: rxInterrupt
00371    **************************************************************
00372    Description: serial rx interupt handler
00373    Receives: N/A
00374    Returns: N/A
00375 */
00376 
00377 //***********************************************
00378 // Rx Interrupt from serial Host interface
00379 //***********************************************
00380 void rxInterrupt(MODSERIAL_IRQ_INFO *info)
00381 {
00382     gLed = 0;
00383     dataReceived = true;
00384     //wait(.5);
00385     gLed = 1;
00386 }
00387 
00388 
00389 //***************************************************************
00390 // Tx Interrupt from serial Host interface
00391 //***************************************************************
00392 void txInterrupt(MODSERIAL_IRQ_INFO *info)
00393 {
00394     gLed = 1;
00395     dataTxReady = true;
00396     gLed = 1;
00397 }
00398 
00399 
00400 /* Function: parseRXData
00401    **************************************************************
00402    Description: The parse received data into
00403    Receives: chn: The channel we want to put into the channel
00404    Returns: N/A
00405 */
00406 void processRxUARTData()
00407 {
00408     HOST_CMD_HEADER *pRxPktHdr;
00409     string data = "";
00410 
00411     pRxPktHdr = (HOST_CMD_HEADER *)rxBuf;
00412 
00413     if (debug_control & RXDATA_PRINT) {
00414         pc.printf("DBG: SOF=%02x, Len=%02x, CMD=%02x\r\n", pRxPktHdr->SOF_flag, pRxPktHdr->len, pRxPktHdr->cmd_type);
00415         pc.printf("DBG: ");
00416         for (int i=0; i <5; i++)
00417             pc.printf("%02x ", rxBuf[i]);
00418         pc.printf("\n");
00419     }
00420 
00421     // Exit if the packet does not contain correct header
00422     // Maybe send NAK?
00423     if ((pRxPktHdr->SOF_flag != RX_SOF) || (pRxPktHdr->Delim != DELIMETER))
00424         return;
00425 
00426     switch (pRxPktHdr->cmd_type)
00427     {
00428         case SET_TEMPERATURE:
00429             // Process set temp for specified channel
00430             {
00431                 SET_TEMPERATURE_CMD *pRxPkt = (SET_TEMPERATURE_CMD *)(rxBuf);
00432 
00433                 if (debug_control & RXDATA_PRINT)
00434                     pc.printf("DBG: SETTEMP: ch = %02x, tempSet = %f, chanStat = %02x\r\n",
00435                                 pRxPkt->chanID, pRxPkt->setTemp, pRxPkt->chanStat);
00436 
00437                 if ((pRxPkt->tempDelim != DELIMETER) || (pRxPkt->chanStatDelim != DELIMETER)) {
00438                     // Send NAK back
00439                     pc.printf("DBG: Error\n");
00440                 }
00441                 else {
00442                     if((pRxPkt->setTemp < MAX_TEMP) && (pRxPkt->setTemp > MIN_TEMP)){
00443                         chanSel_SetTemp = pRxPkt->chanID;
00444                         chnlStatus[pRxPkt->chanID].status = pRxPkt->chanStat;
00445                         chnlStatus[pRxPkt->chanID].state = STATUS_INACTIVE;
00446                         chnlStatus[pRxPkt->chanID].setTemp = pRxPkt->setTemp;
00447                         chnlStatus[pRxPkt->chanID].error = false;
00448                         chnlStatus[pRxPkt->chanID].LTCi2cAckRxed = 0;
00449                         chnlStatus[pRxPkt->chanID].MCPi2cAckRxed = 0;
00450                         chnlStatus[pRxPkt->chanID].SPReached = false;
00451                         chnlStatus[pRxPkt->chanID].SPTime = 0;
00452                         memset(errorCount[pRxPkt->chanID], 0, sizeof(int)*ERROR_COUNT);
00453                         memset(errorEmailSent[pRxPkt->chanID], 0, sizeof(int)*ERROR_COUNT);
00454                         newTempSet = true;
00455                     }
00456                 }
00457             }
00458             break;
00459 
00460         case SELECT_CHANNEL:
00461             // Select channel to send temp data to
00462             {
00463                 SELECT_CHANNEL_CMD *pRxPkt = (SELECT_CHANNEL_CMD *)(rxBuf);
00464 
00465                 chanSel_SendTemp = pRxPkt->chanIDSel;
00466 
00467                 // Send back FW version for each select channel
00468                 sendFWVersion();
00469                 if (debug_control & RXDATA_PRINT)
00470                     pc.printf("DBG: CHAN_SEL: chan=%02x, chanStat = %02x\r\n", pRxPkt->chanIDSel, pRxPkt->chanStat);
00471 
00472             }
00473             break;
00474 
00475         case READ_UID:
00476             {
00477                 READ_UID_CMD *pRxPkt = (READ_UID_CMD *)(rxBuf);
00478                 if (debug_control & RXDATA_PRINT)
00479                     pc.printf("DBG: Read UID: chan%02x\n", pRxPkt->chanIDSel);
00480 
00481                 sendUID();
00482             }
00483             break;
00484 
00485         case READ_FW_VERSION:
00486             {
00487                 sendFWVersion();
00488                 if (debug_control & RXDATA_PRINT)
00489                     pc.printf("DBG: Read SW Version\r\n");
00490 
00491             }
00492             break;
00493 
00494         case DEBUG_CONTROL:
00495             {
00496                 GUI_STANDARD_CMD *pRxPkt = (GUI_STANDARD_CMD *)rxBuf;
00497                 debug_control = pRxPkt->commandData;
00498                 if (debug_control & RXDATA_PRINT)
00499                     pc.printf ("DBG: Rx'd DEBUG CMD: %04x\r\n", pRxPkt->commandData);
00500             }
00501             break;
00502 
00503 
00504         default:
00505             // Error
00506             break;
00507     }
00508 }
00509 
00510 /* Function: get_temp
00511    **************************************************************
00512    Description: Convert A/D count to temperature value
00513    Receives: ADC_val: the count from the A/D reading
00514    Returns: the temp. of the A/D reading
00515 */
00516 
00517 float get_temp(float ADC_val){
00518     myled = 1;
00519     //ltc2487.setAddress(addrLUT[chn].adc);
00520 
00521     //float ADC_val = ltc2487.readOutput(port); //(65536*1.334)/2.5
00522 
00523     int i = 0;
00524 
00525     while((i < sizeLUT) && (thermLUT[i].adc > ADC_val)){
00526         i++;
00527     }  //find the temp. above therm temp
00528 
00529     //Point slope formula extrapolation:
00530     // m = (y1-y0)/(x1-x0)+ y0 , y = temp. value, x = adc value
00531     // y1 = thermLUT[i-1].temp   y0 = thermLUT[i].temp
00532     // x1 = thermLUT[i-1].adc    x0 =thermLUT[i].adc
00533     float a = float(thermLUT[i-1].temp - thermLUT[i].temp); //slope of temp between points where therm temp is between (Tmax - Tmin)
00534     float b = float(thermLUT[i-1].adc - thermLUT[i].adc);   //slope of adc between points where therm adc is between (Amax - Amin)
00535 
00536     float m = a/b;
00537     float y = (m*(ADC_val-thermLUT[i].adc))+thermLUT[i].temp;
00538 
00539     if (debug_control & ADC_VAL_PRINT)
00540         pc.printf("DBG: ADC VAL: %f TEMP: %f \r\n", ADC_val, y);
00541 
00542     return y;
00543 }
00544 
00545 /* Function: get_front_temp_DATA
00546    **************************************************************
00547    Description: Read A/D data from LTC2487 and set array with front temp.
00548                 Save values in CHNL_TEMP data struct
00549    Receives: N/A
00550    Returns: int If the write recieved an ACK
00551 */
00552 void read_front_temp_data()
00553 {
00554     readThermistorTicker.detach();
00555     //Write to all 8 channels selecting the front port to read
00556     for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
00557         chnlStatus[chnl].LTCi2cAckRxed = 0;
00558         ltc2487.setAddress(addrLUT[chnl].adc);
00559         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00560         chnlStatus[chnl].LTCi2cAckRxed = !ltc2487.writePort(FRONT_THERM);
00561     }
00562     //wait until next clock cycle on LTC
00563     //wait(I2C_READ_WAIT_TIME);
00564     frontTempInProgTicker.attach(&update_front_temp_data, I2C_READ_WAIT_TIME);
00565 }
00566 
00567 void update_front_temp_data(){
00568     float countVal;
00569     frontTempInProgTicker.detach();
00570     for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
00571         ltc2487.setAddress(addrLUT[chnl].adc);
00572         countVal = ltc2487.read();
00573         channelTempData[chnl].currADCFront = countVal;
00574         channelTempData[chnl].currTempFront = get_temp(countVal);
00575     }
00576     //wait until next clock cycle on LTC
00577     //wait(0.08);
00578     frontTempDoneTicker.attach(&read_back_temp, I2C_READ_WAIT_TIME);
00579 }
00580 
00581 /* Function: get_back_temp_DATA
00582    **************************************************************
00583    Description: Read A/D data from LTC2487 and set array with back temp.
00584                 Save values in CHNL_TEMP data struct
00585    Receives: N/A
00586    Returns: N/A
00587 */
00588 
00589 void read_back_temp()
00590 {
00591     frontTempDoneTicker.detach();
00592     //Write to all 8 channels selecting the front port to read
00593     for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
00594         chnlStatus[chnl].LTCi2cAckRxed = 0;
00595         ltc2487.setAddress(addrLUT[chnl].adc);
00596         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00597         chnlStatus[chnl].LTCi2cAckRxed = !ltc2487.writePort(BACK_THERM);
00598     }
00599 
00600     //wait until next clock cycle on LTC
00601     //wait(I2C_READ_WAIT_TIME);
00602     backTempInProgTicker.attach(&update_back_temp_data, I2C_READ_WAIT_TIME);
00603 }
00604 
00605 void update_back_temp_data(){
00606     float countVal;
00607     backTempInProgTicker.detach();
00608     for(int chnl = 0; chnl < CHAN_COUNT; chnl++){
00609         ltc2487.setAddress(addrLUT[chnl].adc);
00610         countVal = ltc2487.read();
00611         channelTempData[chnl].currADCBack = countVal;
00612         channelTempData[chnl].currTempBack = get_temp(countVal);
00613     }
00614     //wait until next clock cycle on LTC
00615     //wait(0.08);
00616     backTempDoneTicker.attach(&temperatureDataReady, I2C_READ_WAIT_TIME);
00617 
00618 }
00619 
00620 /* Function: temperatureDataReady
00621    **************************************************************
00622    Description: Flag that temperature data is ready to be
00623                 processed
00624                 Restart task timer
00625    Receives: N/A
00626    Returns: N/A
00627 */
00628 void temperatureDataReady()
00629 {
00630     backTempDoneTicker.detach();
00631     newTempDataAvailable = true;
00632     readThermistorTicker.attach(&read_front_temp_data, READ_TEMP_TASK_TIME);
00633 }
00634 
00635 /* Function: get_heater_current
00636    **************************************************************
00637    Description: Retrieve current into heater control MOSFET
00638    Receives: chn: the channel of the fixture to read current from
00639    Returns: the current into the heater control MOSFET
00640 */
00641 void get_heater_current(int chn, int port){
00642     ltc2487.setAddress(addrLUT[chn].adc);
00643     ltc2487.writePort(HEAT_FET_AMP);
00644     wait(0.08);
00645     ltc2487.read();
00646     wait(0.08);
00647 }
00648 
00649 /* Function: get_valve_current
00650    **************************************************************
00651    Description: Retrieve current into valve control MOSFET
00652    Receives: chn: the channel of the fixture to read current from
00653    Returns: the current into the valve control MOSFET
00654 */
00655 
00656 void get_valve_current(int chn, int port){
00657     ltc2487.setAddress(addrLUT[chn].adc);
00658     ltc2487.writePort(VALVE_FET_AMP);
00659     wait(0.08);
00660     ltc2487.read();
00661     wait(0.08);
00662 }
00663 
00664 /* Function: MCP_Control
00665    **************************************************************
00666    Description: Controls valves/status LEDs
00667    Receives: chn: the channel of the fixture
00668              status: the status of channel (good (1) or bad (0))
00669    Returns: N/A
00670 */
00671 
00672 void Chn_Control(int chn, int status){
00673     //writeOutput(VALVE, HEATER, GREEN STATUS LED, RED STATUS LED)
00674     pc.printf("[%i] CHANNEL CONTROL \r\n", chn);
00675     if(status == VALVE_ON){
00676         //valve ON, heater OFF,  green status LED ON, red status led OFF
00677         if(debug_control & LED_PRINT) pc.printf("VALVE ON %d \r\n", chn);
00678         io_control.setAddress(addrLUT[chn].io);
00679         io_control.init();
00680         chnlStatus[chn].MCPi2cAckRxed = 0;
00681         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00682         chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(1,0,1,0);
00683     }
00684     if(status == HEATER_ON){
00685         //valve ON, heater ON,  green status LED ON, red status led OFF
00686         if(debug_control & LED_PRINT) pc.printf("HEATER ON %d \r\n", chn);
00687         io_control.setAddress(addrLUT[chn].io);
00688         io_control.init();
00689         chnlStatus[chn].MCPi2cAckRxed = 0;
00690         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00691         chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,1,1,0);
00692     }
00693     if(status == GREEN_STATUS_ON){
00694         //valve OFF, heater OFF,  green status LED ON, red status led OFF
00695         if(debug_control & LED_PRINT) pc.printf("GREEN LED %d \r\n", chn);
00696         io_control.setAddress(addrLUT[chn].io);
00697         io_control.init();
00698          chnlStatus[chn].MCPi2cAckRxed = 0;
00699         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00700         chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,1,0);
00701     }
00702     if(status == RED_STATUS_ON){
00703         //valve OFF, heater OFF,  green status LED OFF, red status led ON
00704         if(debug_control & LED_PRINT) pc.printf("RED LED %d \r\n", chn);
00705         io_control.setAddress(addrLUT[chn].io);
00706         io_control.init();
00707         chnlStatus[chn].MCPi2cAckRxed = 0;
00708         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00709         chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,0,1);
00710     }
00711     if(status == ERROR_STATUS_ON){
00712         //valve ON, heater OFF,  green status LED OFF, red status led ON
00713         if(debug_control & LED_PRINT) pc.printf("RED AND BLUE LED %d \r\n", chn);
00714         io_control.setAddress(addrLUT[chn].io);
00715         io_control.init();
00716         chnlStatus[chn].MCPi2cAckRxed = 0;
00717         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00718         chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(1,0,0,1);
00719     }
00720     if(status == ALL_OFF){
00721         //valve OFF, heater OFF,  green status LED OFF, red status led OFF
00722         if(debug_control & LED_PRINT) pc.printf("ALL OFF %d \r\n", chn);
00723         io_control.setAddress(addrLUT[chn].io);
00724         io_control.init();
00725         chnlStatus[chn].MCPi2cAckRxed = 0;
00726         //Check if write was ack'ed (0 =  ACK, (non)0 = NACK)
00727         chnlStatus[chn].MCPi2cAckRxed = !io_control.writeOutput(0,0,0,0);
00728     }
00729 }
00730 
00731 
00732 //***************************************************************
00733 // Build packet with temperature readings to send to GUI
00734 //***************************************************************
00735 void processTxUARTData()
00736 {
00737     RESPONSE_TEMP_CMD response;
00738     unsigned char *ptr = (unsigned char *)&response;
00739     int i;
00740 
00741     response.SOF_flag = TX_SOF;
00742     response.cmd_type = TEMP_DATA;
00743     response.len = 5+(sizeof(response.chTemp));
00744     response.Delim = DELIMETER;
00745     response.chTemp[0] = channelTempData[0].currTempBack;
00746     response.chTemp[1] = channelTempData[1].currTempBack;
00747     response.chTemp[2] = channelTempData[2].currTempBack;
00748     response.chTemp[3] = channelTempData[3].currTempBack;
00749     response.chTemp[4] = channelTempData[4].currTempBack;
00750     response.chTemp[5] = channelTempData[5].currTempBack;
00751     response.chTemp[6] = channelTempData[6].currTempBack;
00752     response.chTemp[7] = channelTempData[7].currTempBack;
00753 
00754     // Send Errors Count/Info
00755 
00756     /*float *dst = (float *)&response.chTemp[0];
00757     float *src = (float *)&channelTempData[0];
00758     memcpy(dst, src, sizeof(channelTempData));*/
00759     response.EOF_flag = TX_EOF;
00760 
00761     // Send response to GUI
00762     for (i=0; i < response.len; i++, ptr++)
00763         pc.printf("%02x", *ptr);
00764     pc.printf("\n");
00765 }
00766 
00767 //***************************************************************
00768 // Build packet with Board UID (Unique Identification)
00769 //***************************************************************
00770 void sendUID ()
00771 {
00772     UID_RESPONSE response;
00773     unsigned char *ptr = (unsigned char *)&response;
00774     int i;
00775 
00776     response.SOF_flag = TX_SOF;
00777     response.cmd_type = UID_DATA;
00778     response.len = 17;
00779     response.Delim = DELIMETER;
00780     response.UIDMH = (uint32_t)SIM->UIDMH;
00781     response.UIDML = (uint32_t)SIM->UIDML;
00782     response.UIDL = (uint32_t)SIM->UIDL;
00783     response.EOF_flag = TX_EOF;
00784 
00785     // Send response to GUI
00786     for (i=0; i < response.len; i++, ptr++)
00787         pc.printf("%02x", *ptr);
00788     pc.printf("\n");
00789 }
00790 
00791 //***************************************************************
00792 // Build packet with SW Version
00793 //***************************************************************
00794 void sendFWVersion()
00795 {
00796     FW_VERSION_RESPONSE response;
00797     unsigned char *ptr = (unsigned char *)&response;
00798     int i;
00799     rLed = 1;
00800 
00801     for (i=0; i < 20; i++)
00802         rLed = 0;
00803 
00804     rLed = 1;
00805 
00806     response.SOF_flag = TX_SOF;
00807     response.cmd_type = FW_VERSION_DATA;
00808     response.len = 13;
00809     response.Delim = DELIMETER;
00810     memcpy(response.FW_Version, FW_Version, 8);
00811     response.FW_Version[7] = '\0';
00812     response.EOF_flag = TX_EOF;
00813 
00814     // Send response to GUI
00815     for (i=0; i < response.len; i++, ptr++)
00816         pc.printf("%02x", *ptr);
00817     pc.printf("\n");
00818 }
00819 
00820 //***************************************************************
00821 // Build packet with errors to send to GUI
00822 //***************************************************************
00823 void sendError (int chan, float error)
00824 {
00825     RESPONSE_CMD response;
00826     unsigned char *ptr = (unsigned char *)&response;
00827     int i;
00828 
00829     response.SOF_flag = TX_SOF;
00830     response.cmd_type = ERROR_DATA;
00831     response.len = 13;
00832     response.Delim = DELIMETER;
00833     response.channel = chan;
00834     response.data = (float)error;
00835 
00836     response.EOF_flag = TX_EOF;
00837 
00838     // Send response to GUI
00839     for (i=0; i < response.len; i++, ptr++)
00840         pc.printf("%02x", *ptr);
00841     pc.printf("\n");
00842 
00843 }
00844 
00845 /* Function: toggleI2C
00846    **************************************************************
00847    Description: Toggle the I2C line in an attempt to unfreeze it
00848    Receives: N/A
00849    Returns: N/A
00850 */
00851 
00852 void toggleI2C(){
00853     DigitalOut ioSDAIn(PTC9);
00854     DigitalOut adcSDAIn(PTC11);
00855     DigitalOut ioSCLIn(PTC8);
00856     DigitalOut adcSCLIn(PTC10);
00857 
00858     ioSDAIn = 1;
00859     adcSDAIn = 1;
00860     ioSCLIn = 1;
00861     adcSCLIn = 1;
00862     wait(0.5);
00863     ioSDAIn = 0;
00864     adcSDAIn = 0;
00865     ioSCLIn = 0;
00866     adcSCLIn = 0;
00867     wait(0.5);
00868     ioSDAIn = 1;
00869     adcSDAIn = 1;
00870     ioSCLIn = 1;
00871     adcSCLIn = 1;
00872     wait(0.5);
00873     ioSDAIn = 0;
00874     adcSDAIn = 0;
00875     ioSCLIn = 0;
00876     adcSCLIn = 0;
00877     wait(0.5);
00878 
00879     MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
00880     LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
00881 
00882 }
00883 
00884 /* Function: sendErrorEmail
00885    **************************************************************
00886    Description: sends error email
00887    Receives: chn: channel to check error on
00888    Returns: N/A
00889 */
00890 
00891 void sendErrorEmail(int chn){
00892     int error;
00893 
00894     for (error=0; error < ERROR_COUNT; error++){
00895         if((errorCount[chn][error] == MAX_ERROR_CNT) && (!errorEmailSent[chn][error])){
00896             sendError(chn, error);
00897             errorEmailSent[chn][error] = 1;
00898         }
00899     }
00900 }
00901 
00902 /* Function: errorCheck
00903    **************************************************************
00904    Description: Updates error count for the channel
00905    Receives: chn: channel to update
00906              errorFlag: if the error was encountered
00907              errorNum: number of error encountered
00908    Returns: N/A
00909 */
00910 
00911 void errorCheck(int chn, bool errorFlag, int errorNum){
00912     if(errorFlag){
00913         if(errorCount[chn][errorNum] < MAX_ERROR_CNT){
00914             //increase error count
00915             errorCount[chn][errorNum]++;
00916             pc.printf("[%i] ERROR ENCOUNTERED: %i %i \r\n", chn, errorNum, errorCount[chn][errorNum]);
00917         }
00918         else{
00919             //this is an error, set error flag
00920             chnlStatus[chn].error = true;
00921             //pc.printf("[%i] ERROR FLAGGED: %i %i\r\n", chn, errorNum, errorCount[chn][errorNum]);
00922         }
00923     }
00924     else{
00925         if(errorCount[chn][errorNum] > 0){
00926             //decrease error count
00927             errorCount[chn][errorNum]--;
00928         }
00929         //pc.printf("[%i] NO ERROR FLAGGED: %i \r\n\n", chn, errorNum);
00930     }
00931 }
00932 
00933 /* Function: softwareReset
00934    **************************************************************
00935    Description: soft reset
00936    Recieves: N/A
00937    Returns: N/A
00938 */
00939 
00940 void softwareReset(void){
00941     SCB->AIRCR = (0x5FA<<SCB_AIRCR_VECTKEY_Pos)|SCB_AIRCR_SYSRESETREQ_Msk;
00942     for(;;){}
00943 }
00944 
00945 /* Function: SP_Time_Check
00946    **************************************************************
00947    Description: Reset the SP time for each channel every minute
00948                (minutes since SP has been set and SP hasn't been reach)
00949    Recieves: N/A
00950    Returns: N/A
00951 */
00952 
00953 void SP_Time_Check(){
00954     int chan;
00955 
00956     for (chan=0; chan < CHAN_COUNT; chan++){
00957         if(chnlStatus[chan].status == 1){
00958             if(!chnlStatus[chan].SPReached){
00959                 if(chnlStatus[chan].SPTime != MAX_TIME_TO_SP){
00960                     chnlStatus[chan].SPTime++;
00961                 }
00962             }
00963         }
00964     }
00965 }
00966 
00967 /* Function: read I2C Line
00968    **************************************************************
00969    Description: Read the I2C line to check if pulled high
00970    Receives: N/A
00971    Returns: N/A
00972 */
00973 
00974 int readI2CLine(int line)
00975 {
00976     if(line == IO_I2C_LINE){
00977         DigitalIn ioSDAIn(PTC9);
00978         int ioSDA = ioSDAIn.read();
00979         if(I2C_PRINT) pc.printf("DBG: TEMPERATURE SDA LINE: %d \r\n", ioSDA);
00980         MCP23008 io_control(PTC9, PTC8, 0x10, 100000); //sda, scl
00981         return ioSDA;
00982     }
00983     if(line == ADC_I2C_LINE){
00984         DigitalIn adcSDAIn(PTC11);
00985         int adcSDA = adcSDAIn.read();
00986         if(I2C_PRINT) pc.printf("DBG: IO SDA LINE: %d \r\n", adcSDA);
00987         LTC2487 ltc2487(PTC11, PTC10, 0x23, 100000); //sda, scl
00988         return adcSDA;
00989     }
00990     return 0;
00991 }
00992 
00993 
00994 /* Function: systemLogic
00995    **************************************************************
00996    Description: Sets setting for fixture needed to maintain temperature at SP
00997    Receives: N/A
00998    Returns: N/A
00999 */
01000 
01001 void systemLogic(){
01002     int chan;
01003     float currTemp;
01004 
01005     for (chan=0; chan < CHAN_COUNT; chan++)
01006     {
01007         if(chnlStatus[chan].status == 1){
01008             //Current Temperature
01009             currTemp = channelTempData[chan].currTempBack;
01010 
01011             if(currTemp > ((chnlStatus[chan].setTemp)+HYST_HIGH)){
01012                 //TURN COOLING ON
01013                 chnlStatus[chan].state = STATUS_COOLING;
01014             }
01015             else if(currTemp < ((chnlStatus[chan].setTemp)-HYST_LOW)){
01016                 //TURN HEATER ON
01017                 chnlStatus[chan].state = STATUS_HEATING;
01018             }
01019             else{
01020                 //FIXTURE INACTIVE
01021                 chnlStatus[chan].state = STATUS_INACTIVE;
01022             }
01023         }
01024         else{
01025             //FIXTURE STANDBY
01026             pc.printf("FIXTURE IN STANDBY \r\n");
01027             chnlStatus[chan].state = STATUS_STANDBY;
01028         }
01029     }
01030 
01031 }
01032 
01033 /* Function: systemControl
01034    **************************************************************
01035    Description: Changes fixture setting in accordance to logic set in systemLOGIC function
01036    Receives: N/A
01037    Returns: N/A
01038 */
01039 
01040 void systemControl()
01041 {
01042     int chan;
01043     
01044     for (chan=0; chan < CHAN_COUNT; chan++){
01045         pc.printf("[%i] CHANNEL ERRORS: %d \r\n", chan, chnlStatus[chan].error);
01046         if(!chnlStatus[chan].error){
01047             //pc.printf("[%i] CHANNEL NO ERRORS \r\n", chan);
01048             if(errorCount[chan][ERR_ACK_LTC] == 0){
01049                 if(chnlStatus[chan].state == STATUS_INACTIVE){
01050                     //FIXTURE INACTIVE
01051                     Chn_Control(chan, GREEN_STATUS_ON);
01052                     //SP reached
01053                     chnlStatus[chan].SPReached = true;
01054                 }
01055                 else if(chnlStatus[chan].state == STATUS_COOLING){
01056                     //TURN COOLING ON
01057                     Chn_Control(chan, VALVE_ON);
01058                 }
01059                 else if(chnlStatus[chan].state == STATUS_HEATING){
01060                     //TURN HEATER ON (have to toggle bc of charge pump in circuit)
01061                     Chn_Control(chan, GREEN_STATUS_ON); //turn heater off
01062                     Chn_Control(chan, HEATER_ON);
01063                 }
01064                 else if(chnlStatus[chan].state == STATUS_STANDBY){
01065                     //FIXTURE IN STANDBY (i.e. off)
01066                     if(standbyLED[chan]){
01067                         Chn_Control(chan, GREEN_STATUS_ON);
01068                         standbyLED[chan] = !standbyLED[chan];
01069                     }
01070                     else{
01071                         Chn_Control(chan, ALL_OFF);
01072                         standbyLED[chan] = !standbyLED[chan];
01073                     }
01074                 }
01075             }
01076         }
01077         else{
01078             sendErrorEmail(chan);
01079         }
01080     }
01081 }
01082 
01083 /* Function: systemDiagnostic
01084    **************************************************************
01085    Description: Checks for any system errors
01086    Receives: chn: Channel to modify
01087    Returns: N/A
01088 */
01089 
01090 void systemDiagnostic(){
01091     int chan;
01092     float backCount;
01093     float frontCount;
01094     float backTemp;
01095     float frontTemp;
01096     bool errorFlag;
01097     float tempDiff;
01098     int LTC_Ack;
01099     int MCP_Ack;
01100     int timeToSP;
01101     bool reachedSP;
01102 
01103     for (chan=0; chan < CHAN_COUNT; chan++){
01104         backCount = channelTempData[chan].currADCBack;
01105         frontCount = channelTempData[chan].currADCFront;
01106         frontTemp = channelTempData[chan].currTempFront;
01107         backTemp = channelTempData[chan].currTempBack;
01108         LTC_Ack = chnlStatus[chan].LTCi2cAckRxed;
01109         MCP_Ack = chnlStatus[chan].MCPi2cAckRxed;
01110         timeToSP = chnlStatus[chan].SPTime;
01111         reachedSP = chnlStatus[chan].SPReached;
01112         
01113         if(PRINT_ERROR_CHECK_VALS){
01114             pc.printf("BAKC COUNT: %f \r\n", backCount);
01115             pc.printf("FRONT COUNT: %f \r\n", frontCount);
01116             pc.printf("TEMP DIFF: %f \r\n", abs(frontTemp-backTemp));
01117             pc.printf("LTC ACK: %f \r\n", LTC_Ack);
01118             pc.printf("MCP ACK: %f \r\n", MCP_Ack);
01119         }
01120 
01121         //Check if the ADC temperature is too high (low ADC count)
01122         errorFlag = false;
01123         if((backCount < MIN_AD_COUNT) || (frontCount < MIN_AD_COUNT)) errorFlag = true;
01124         errorCheck(chan, errorFlag, ERR_OVER_TEMP);
01125 
01126         //Check if the ADC temperature is too low (high ADC count), valve stuck on
01127         errorFlag = false;
01128         if((backCount > MAX_AD_COUNT) || (frontCount > MAX_AD_COUNT)) errorFlag = true;
01129         errorCheck(chan, errorFlag, ERR_UNDER_TEMP);
01130 
01131         //Check for a substantial temp. diff. |b| the front & back of the fixture
01132         errorFlag = false;
01133         tempDiff = abs(frontTemp-backTemp);
01134         if(tempDiff > TEMP_MARGIN) errorFlag = true;
01135         errorCheck(chan, errorFlag, ERR_TEMP_DIFF);
01136 
01137         //Check for ACK from the LTC2487 chip (temperature reading)
01138         errorFlag = false;
01139         if(!LTC_Ack) errorFlag = true;
01140         errorCheck(chan, errorFlag, ERR_ACK_LTC);
01141 
01142         //Check for ACK from the MCP23008 chip (valve/heater controller)
01143         /*errorFlag = false;
01144         if(!MCP_Ack) errorFlag = true;
01145         errorCheck(chan, errorFlag, ERR_ACK_MCP);*/
01146 
01147         //Check if the fixture has not reached SP in X amount of time
01148         errorFlag = false;
01149         if(!reachedSP && (timeToSP == MAX_TIME_TO_SP)) errorFlag = true;
01150         errorCheck(chan, errorFlag, ERR_SP_TIME);
01151         
01152     }
01153 }
01154 
01155 /*************************************************************/
01156 /*                       NEW MAIN FUNCTION                   */
01157 /*************************************************************/
01158 
01159 int main(){
01160     /* INITIALIZATION CODE */
01161     // Setup serial port
01162     // Look for RX_EOF
01163     uint32_t UIDMH, UIDML, UIDL;
01164     int UID_print_count = 0;
01165     //resetErrorCount();
01166 
01167 
01168     //*********************************
01169     // Initial thermistors readings
01170     // Kick of SP time updates
01171     // Kick off temperature reading
01172     // state machine
01173     //*********************************
01174     readThermistorTicker.attach(&read_front_temp_data, .0001);
01175     //setPointTimeTicker.attach(&SP_Time_Check, 60);
01176 
01177     pc.baud(9600);
01178     pc.autoDetectChar(RX_EOF);
01179     pc.attach(&rxInterrupt, MODSERIAL::RxAutoDetect);
01180 
01181     UIDMH = (uint32_t)SIM->UIDMH;
01182     UIDML = (uint32_t)SIM->UIDML;
01183     UIDL = (uint32_t)SIM->UIDL;
01184 
01185     //print UID three times on start-up to ID Mbed board
01186     if(UID_print_count++ < 3)
01187         pc.printf("DBG: [UID: %04X%08X%08X]\n", UIDMH, UIDML, UIDL);
01188 
01189 
01190     while(1) {
01191         //*********************************
01192         // Process Rx UART data from GUI
01193         //*********************************
01194         //pc.printf("LOOP \r\n");
01195         if (dataReceived)
01196         {
01197             dataReceived = false;
01198             if (debug_control & RXDATA_PRINT)
01199                 pc.printf("DBG: %d bytes Rx'd\n", pc.rxBufferGetCount());
01200 
01201             pc.move(rxBuf, 50);
01202             processRxUARTData();
01203             pc.rxBufferFlush();
01204         }
01205 
01206         //*********************************
01207         // Logic Loop
01208         //*********************************
01209         // System Logic/Control
01210         if (newTempDataAvailable)
01211             systemLogic();
01212 
01213         //*********************************
01214         // System Diagnostic & Error Check
01215         //*********************************
01216         systemDiagnostic();
01217 
01218         //*********************************
01219         // Process Tx UART data
01220         // Send Temperature Data/Error to GUI
01221         //*********************************
01222         if (newTempDataAvailable)
01223         {
01224             processTxUARTData();
01225 
01226             //*********************************
01227             //Actuate Loop
01228             //*********************************
01229             systemControl();
01230             newTempDataAvailable = false;
01231         }
01232     }
01233 }