ROM Comm / Mbed 2 deprecated espar_mini_control_CAN

Dependencies:   mbed mbed-STM32F103C8T6

heatcontrol.cpp

Committer:
lorded
Date:
2020-06-12
Revision:
10:a82e51837e2b
Parent:
9:6126b83608be
Child:
11:b571de4666c9

File content as of revision 10:a82e51837e2b:

#include "mbed.h"
#include "heatcontrol.h"
#include "globals.h" // includes CAN2
#include "espar_can.h"
/******************************************************
 *                    Constants
 ******************************************************/
//#define EASYSTARTFORMAT 1
#define LIN_BAUD              1200

extern void DebugWrite(const char * str);
extern char printbuff[256];

extern unsigned long lifetimer;

#define NOREPORTING 0
#define HEATERCALLEDON 1

char heaterDetected = 0;

//const uint16_t HEATER1ID = 0x0054;
//const uint16_t CTRLCHANNEL = 0x07A0;
//#define EASYSTARTFORMAT
#ifdef EASYSTARTFORMAT
const uint16_t HEATER1ID = 0x0054; // 0x009C heater 1
const uint16_t CTRLCHANNEL = 0x07A0;
const uint16_t CTRLRESPONSE = 0x073C;// heater1 0x073C, response 0x073D heater 2

const uint16_t HEATER2ID = 0x0057;// 0x009C heater 1
const uint16_t CTRLCHANNEL2 = 0x07A1;
const uint16_t CTRLRESPONSE2 = 0x073D;// heater1 0x073C, response 0x073D heater 2

#else
const uint16_t HEATER1ID = 0x009C; // 0x009C heater 1
const uint16_t CTRLCHANNEL = 0x07A0;
const uint16_t CTRLRESPONSE = 0x073C; // heater1 0x073C, response 0x073D heater 2

const uint16_t HEATER2ID = 0x00F3; // 0x009C heater 1
const uint16_t CTRLCHANNEL2 = 0x07A1;
const uint16_t CTRLRESPONSE2 = 0x073D; // heater1 0x073C, response 0x073D heater 2

#endif

/******************************************************
 *                   Enumerations
 ******************************************************/

/******************************************************
 *                 Type Definitions
 ******************************************************/

/******************************************************
 *                    Structures
 ******************************************************/
extern struct sSystemSettings Settings; // structure to hold system settings //
/******************************************************
 *               Function Declarations
 ******************************************************/
void printCAN(CANMessage *canMsg);
void printCANTx(CANMessage *canMsg);

void printPacketBuffer(unsigned int length, struct sHeatVars *s);
void parseLINBuffer(struct sHeatVars *s);
void readLINBuffer(struct sHeatVars *s);
unsigned char fromHexAscii(char ascii);
extern void resetTimerAsync(struct sHeatVars *s);
extern void resetTimer(struct sHeatVars *s);
int doFindExpectedResponse(CANMessage* msg, const uint16_t expectedID, const char* expectedResponse, int charsInMatch);
/******************************************************
 *               Variable Definitions
 ******************************************************/

// local vars
// external timer variables to use for timing (ie 1 minute, etc.)
extern volatile unsigned char idletimer;
extern void DebugWrite(const char* str);
struct sHeatVars heaterState[HEATERSTATECOUNT];

char otherControllerDetected = 0;
/******************************************************
 *               Function Definitions
 ******************************************************/

/*
 * 0-ID,0054:00 00 FE FF FE FF 00 00

 0-ID,0625:25 00 B5 54 C0 BB E4 01

 0-ID,0054:00 00 FE FF FE FF 00 00

 0-ID,0057:00 00 FE FF FE FF 00 00

 0-ID,0625:25 00 B5 54 C0 BB E4 01

 0-ID,02C4:03 00 04 00 18 03 00 00

 0-ID,02C6:F4 01 84 03 00 00 00 00

 0-ID,0625:25 00 B5 54 C0 BB E4 01

 0-ID,02C6:F4 01 84 03 00 00 00 00

 0-ID,073C:02 7E 00 02 7B 00 02 11

 0-ID,02C6:F4 01 84 03 00 00 00 00

 0-ID,0625:25 00 B5 54 C0 BB E4 01

 0-ID,02C6:F4 01 84 03 00 00 00 00

 * */

void initHeaterState(struct sHeatVars *s)
{
    s->internalAltitude = 0;
    s->battV = 0;
    s->primeFuelPumpCount = 0;
    s->heatCallDetected = WICED_FALSE;
    s->heaterTemp = -9999;
    s->initTimer = 3; // 3s before we do anything other than "I'm here"
    s->tasksequence = 0;
    s->currentError = 0xff;
    s->heatOn = 0; // default 0
    //unsigned char errorHistory[8];
    s->errorChangeFlag = 0;
    s->heatcontrolstate = 0; // default 0
    s->lastRequest = 0; // default = 0;
    s->lastResponse = 0; //default = 0;
    s->noResponseCount = 0; //default = 0;
    s->retryHC = 0; // = 0;
    s->heatrunning = 0; // = 0;
    s->reset_fault_codes = WICED_FALSE; // WICED_FALSE
    s->isAnalogHeater = WICED_FALSE;
    s->heattime = 0;
    s->heatresettime = RESETHEATTIME;
    s->reportflag = 0;
    s->preheattime = 0;
    s->heaterSetpointChange = 0;
    s->primeFuelPump = WICED_FALSE;
    s->OBAltitude = WICED_FALSE;
    s->altitudeMode = WICED_TRUE;
}
// do checksum calc
int testChecksum(unsigned int length, struct sHeatVars *s)
{
    unsigned int checksum = 0;
    int i;
    for (i = s->working; i < (s->working + length + 3); i++)
    {
        checksum += s->linbuff[i];
    }
    // convert the last 2 bytes to checksum
    if ((checksum % 256) == (fromHexAscii(s->linbuff[s->working + length + 3]) * 16 + fromHexAscii(s->linbuff[s->working + length + 4])))
    {
        return 1;
    }
    return 0;
}
#define CANSPEED_500      500000 
void InitCAN()
{
    if ( can2.frequency(CANSPEED_500) ) {
           
    }
    otherControllerDetected = 0;
    DebugWrite("Init can\r\n");
    int result;
    // can is just there.
}

void setHeatSetpoint(struct sHeatVars* s, int setpoint)
{
    printf("setting setpoint of %d\r\n", setpoint);
    if ((setpoint > 50) && (setpoint <= 380))
    {
        s->heaterSetpointChange = setpoint;
    }
}
void primeFuelPump(struct sHeatVars* s)
{
    s->primeFuelPump = WICED_TRUE;
}
void resetFaultCodes(struct sHeatVars* s)
{
    //printf("Reset Fault codes on\r\n");
    s->reset_fault_codes = WICED_TRUE;
}
void set_heat_con(struct sHeatVars* s, heatcall on_off)
{
    resetTimerAsync(s);
    if (on_off == HEATCALLINIT)
    {
        s->heatOn = HEATCALLINIT;
        //heattime = 100; //60*Settings.DefaultHeaterRuntime;
        s->heattime = 24*60*60;
        s->heatresettime = RESETHEATTIME;

        s->preheattime = 0;
        //printf("Init heater, preheat %lu\n", preheattime);
    }
    else if (on_off == HEATCALLOFF)
    {
        s->heatOn = HEATCALLOFF;
        s->heattime = 0;
        s->heatresettime = RESETHEATTIME;
        s->preheattime = 0;
        ///printf("Turning heater OFF\n");
    }
    else if (on_off == HEATCALLON)
    {
        // skip preheat
        s->heatOn = HEATCALLON;
        s->heattime = 24*60*60;
        s->heatresettime = RESETHEATTIME;
        s->preheattime = 0;
        //printf("Turning heater ON (skip preheat)\n");
    }
    else
    {
        //printf("\n unknown command\n");
    }
}

void WakeHeater(struct sHeatVars* s)
{
    if (s->heatcontrolstate == 0)
    {
        //InitDigHeater();
        s->retryHC = 0;
        s->heatcontrolstate = 1;
    }
}

void sendCANCommand(uint16_t id, const char*data, int length)
{
    //return; // listen mode

    CANMessage TxMessage(id, data, length);
    can2.write(TxMessage);
    printCAN(&TxMessage);
}

void sendRepeatMode(struct sHeatVars* s)
{
    const char wake[8] =
    { 0x0F, 0x11, 0xC9, 0x22, 0x00, 0x20, 0x60, 0x00 };
    if (s->heaternum == 1)
    {
        sendCANCommand(0x060F, wake, 8);
    }
    //else if (s->heaternum == 2)
    //{
    //  sendCANCommand(CTRLCHANNEL2, wake, 8);
    //}
}
void sendWakeCommand(struct sHeatVars* s)
{
    //DebugWrite("Wake command\r\n");
    // "3e is "tester present"
    const char wake[8] =
    { 0x02, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    //{0x0F, 0x10, 0x03, 0x00, 0x20, 0x60, 0x00, 0x00};
    if (s->heaternum == 1)
    {
        sendCANCommand(CTRLCHANNEL, wake, 8);
    }
    else if (s->heaternum == 2)
    {
        sendCANCommand(CTRLCHANNEL2, wake, 8);
    }

    //const char wake2[8] = {0x0F, 0x10, 0x03, 0x00, 0x20, 0x60, 0x00, 0x00};
    //sendCANCommand(CTRLCHANNEL2, wake2, 8);
}
void sendHeatOffCommand(struct sHeatVars* s)
{
    //DebugWrite("Heat Off command\r\n");
    const char heatoncmd[8] =
#ifdef EASYSTARTFORMAT
            {   0x00, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00};
#else
            { 0x05, 0x00, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00 };
#endif
    if (s->heaternum == 1)
    {
        sendCANCommand(HEATER1ID, heatoncmd, 8);
    }
    else if (s->heaternum == 2)
    {
        sendCANCommand(HEATER2ID, heatoncmd, 8);
    }
}
void sendHeatVentConmmand(struct sHeatVars* s)
{
    DebugWrite("SENDHEATVENT\r\n");
    const char heatoncmd[8] =
    { 0x01, 0x02, 0xFE, 0xFF, 0xF8, 0x02, 0x00, 0x00 };
    if (s->heaternum == 1)
    {
        sendCANCommand(HEATER1ID, heatoncmd, 8);
    }
    else if (s->heaternum == 2)
    {
        sendCANCommand(HEATER2ID, heatoncmd, 8);
    }
}

void sendHeatOnCommand(struct sHeatVars* s)
{
    DebugWrite("SENDHEATON\r\n");
    char heatoncmd[8] =
#ifdef EASYSTARTFORMAT
            {   0x01, 0x01, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00};  // works?
#else
            { 0x07, 0x01, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00 };  // works?
#endif
    //{ 0x07, 0x01, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00 };

    uint16_t setpointbytes = 65534;
    char *usetpoint = (char*) &setpointbytes;
    // heater 2 has setpoint in 2/3... heater1 in 3/4??????
    heatoncmd[2] = usetpoint[0];  // LSB in slot 2
    heatoncmd[3] = usetpoint[1];
    heatoncmd[4] = usetpoint[0];  // LSB in slot 2
    heatoncmd[5] = usetpoint[1];
    //{ 0x07, 0x01, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00 }; // "mode is "preheating"?
    if (s->heaternum == 1)
    {
        //need to reintroduce this...
        if ((s->OBAltitude == WICED_FALSE))
        {
            char mysteryCommand[8] =
            { 0x0F, 0x00, 0xC9, 0x22, 0x00, 0x00, 0x00, 0x00 };
            sendCANCommand(0x060D, mysteryCommand, 8);
        }

        sendCANCommand(HEATER1ID, heatoncmd, 8);
    }
    else if (s->heaternum == 2)
    {
        sendCANCommand(HEATER2ID, heatoncmd, 8);
    }
}
void sendAltitudeMode(struct sHeatVars *s)
{
    if (s->OBAltitude == WICED_TRUE)
    {
        return; // don't send if altitude mode on board.
    }

    char highAltitudeCmd[8] =
    { 0x4c, 0x1d, 0, 0, 0, 0, 0, 0 };

    // no idea what this is for?
    //5000      60D  205935687 0008 0D 11 C9 22 00 20 60 00
//#ifdef EASYSTARTFORMAT

//#endif
    // 4C,1D - 7500 for high altitude
    // 10,27 - 10000 for low altitude

    //uint16_t setpointbytes = 6800;
    uint16_t setpointbytes = 6800;
    if (s->internalAltitude > 0)
    {
        setpointbytes = (s->internalAltitude * 10);
        //sprintf(printbuff, "-- Internal alt\r\n %d\r\n", s->internalAltitude);
        //DebugWrite(printbuff);
    }
    else
    {
        setpointbytes = 6800;
    }
    char *usetpoint = (char*) &setpointbytes;
    highAltitudeCmd[0] = usetpoint[0];  // LSB in slot 2
    highAltitudeCmd[1] = usetpoint[1];
    char lowAltitudeCmd[8] =
    { 0x10, 0x27, 0, 0, 0, 0, 0, 0 };

    if (s->internalAltitude > 0)
    {
        setpointbytes = (s->internalAltitude * 10);
        //  sprintf(printbuff, "-- Internal alt %d\r\n", s->internalAltitude);
        //  DebugWrite(printbuff);
    }
    else
    {
        setpointbytes = 10000;
    }

    lowAltitudeCmd[0] = usetpoint[0];  // LSB in slot 2
    lowAltitudeCmd[1] = usetpoint[1];

    if (s->heaternum == 1)
    {
        if (s->altitudeMode == WICED_TRUE)
        {

            sendCANCommand(0x0055, highAltitudeCmd, 8);
//          sendCANCommand(0x0056, highAltitudeCmd, 8);
            sendCANCommand(HEATER1ID + 1, highAltitudeCmd, 8);
        }
        else
        {
            sendCANCommand(0x0055, lowAltitudeCmd, 8);
//          sendCANCommand(0x0056, lowAltitudeCmd, 8);
            sendCANCommand(HEATER1ID + 1, lowAltitudeCmd, 8);
        }

    }
    /*
     else if (s->heaternum == 2)
     {
     if (s->altitudeMode == WICED_TRUE)
     {
     sendCANCommand(HEATER2ID + 1, highAltitudeCmd, 8);
     sendCANCommand(0x0055, lowAltitudeCmd, 8);
     sendCANCommand(0x0056, highAltitudeCmd, 8);
     }
     else
     {
     sendCANCommand(HEATER2ID + 1, lowAltitudeCmd, 8);
     sendCANCommand(0x0055, lowAltitudeCmd, 8);
     sendCANCommand(0x0056, lowAltitudeCmd, 8);
     }

     }
     */
}
void sendHeatOnCommandSetpoint(struct sHeatVars* s)
{
    DebugWrite("SENDHEATONSETPOINT\r\n");
    sprintf(printbuff, "Setpoint is %d", s->setpoint);
    DebugWrite(printbuff);
    char heatoncmd[8] =
    //{ 0x01, 0x04, 0xFE, 0xFF, 0xFE, 0xFF, 0x00, 0x00 }; // "mode is "setpoint with temp"?
            { 0x07, 0x04, 0xFE, 0xFF, 0xFF, 0xFE, 0x00, 0x00 }; // "mode is "setpoint with temp"?

    uint16_t setpointbytes = 65534;
    char *usetpoint = (char*) &setpointbytes;
    // heater 2 has setpoint in 2/3... heater1 in 3/4??????
    heatoncmd[2] = usetpoint[0];  // LSB in slot 2
    heatoncmd[3] = usetpoint[1];
    heatoncmd[4] = usetpoint[0];  // LSB in slot 2
    heatoncmd[5] = usetpoint[1];

    setpointbytes = s->setpoint;
    usetpoint = (char*) &setpointbytes;
    // heater 2 has setpoint in 2/3... heater1 in 3/4??????
    if (s->heaternum == 2)
    {
        heatoncmd[2] = usetpoint[0];  // LSB in slot 2
        heatoncmd[3] = usetpoint[1];
        //heatoncmd[4] = usetpoint[0];  // LSB in slot 2
        //heatoncmd[5] = usetpoint[1];
        sendCANCommand(HEATER2ID, heatoncmd, 8);
    }
    else
    {
        heatoncmd[4] = usetpoint[0];  // LSB in slot 2
        heatoncmd[5] = usetpoint[1];
        sendCANCommand(HEATER1ID, heatoncmd, 8);
    }

}
void doOtherResetSequence(struct sHeatVars* s)
{
    //DebugWrite("**************\r\n");
    CANMessage msg;

    DebugWrite("Send wake\r\n");
    sendWakeCommand(s);

    int id = CTRLCHANNEL;
    int resp = CTRLRESPONSE;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }
    char switchToSession[8] =
    { 0x10, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
    sendCANCommand(id, switchToSession, 8);
    DebugWrite("Switch To Session\r\n");
    if (doFindExpectedResponse(&msg, resp, NULL, 0) > 0)
    {
        DebugWrite("Got a response!\r\n");
        printCAN(&msg);
        //return;
    }
    else
    {

    }
    // request seed

    //DebugWrite("**************\r\n");
}
void doPrimeSequence(struct sHeatVars* s)
{
    int extrabyte = 0;
    int count;
    sendWakeCommand(s);

    CANMessage msg;
    int id = CTRLCHANNEL;
    int resp = CTRLRESPONSE;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }

    char pump[8] =
    { 0x07, 0x31, 0x01, 0xF0, 0x00, 0x64, 0x00, 0x05 };
    char pump2[8] =
    { 0x04, 0x31, 0x03, 0xF0, 0x00, 0x00, 0x00, 0x00 };

    // read data F1F2 identifiers...
    char reset1[8] =
    { 0x03, 0x22, 0xF1, 0xF2, 0x00, 0x00, 0x00, 0x00 };
    char res1[5] =
    { 0x10, 0x09, 0x62, 0xF1, 0xF2 };

    // not sure
    char reset2[8] =
    { 0x30, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char res2[5] =
    { 0x21, 0x00, 0x00, 0x60, 0xF2 };

    // security access
    char reset3[8] =
    { 0x02, 0x27, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00 };
    // security response
    char res3[4] =
    { 0x06, 0x67, 0x63, 0x00 };

    char reset3a[8] =
    { 0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char res3a[3] =
    { 0x06, 0x50, 0x01 };

    // change to session '60'
    char reset3b[8] =
    { 0x02, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char res3b[3] =
    { 0x06, 0x50, 0x60 };

    // scurity access
    char reset4a[8] =
    { 0x06, 0x27, 0x64, 0x00, 0x00, 0x10, 0x60, 0x00 };
    char res4a[4] =
    { 0x02, 0x67, 0x64, 0x00 };
    count = 0;
    DebugWrite("***RESET1\r\n");
    sendCANCommand(id, reset1, 8);
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res1, 3) > 0)
        {
            printf("1!\r\n");
            break;
        }
        else
        {
            if (msg.id == 0x073)
            {
                DebugWrite("Got-");
                printCAN(&msg);
            }
        }
    }
    if (count >= 20)
    {
        DebugWrite("FAILED(1)\r\n");
        return;
    }
    count = 0;
    sendCANCommand(id, reset2, 8);
    DebugWrite("***RESET2\r\n");
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res2, 3) > 0)
        {
            DebugWrite("2!\r\n");
            break;
        }
        else
        {

        }
    }
    if (count >= 20)
    {
        DebugWrite("FAILED(2)\r\n");
        return;
    }

    // check msg byte 4, if 01, additional commands
    extrabyte = msg.data[3];
    if (extrabyte > 0)
    {
        count = 0;
        sendCANCommand(id, reset3a, 8);
        while (count++ < 20)
        {
            if (doFindExpectedResponse(&msg, resp, res3a, 3) > 0)
            {
                DebugWrite("3a!\r\n");
                break;
            }
            else
            {

            }
        }
        if (count >= 20)
        {
            DebugWrite("FAILED(3)\r\n");
            return;
        }
        count = 0;
        sendCANCommand(id, reset3b, 8);
        while (count++ < 20)
        {
            if (doFindExpectedResponse(&msg, resp, res3b, 3) > 0)
            {
                DebugWrite("3b!\r\n");
                break;
            }
            else
            {

            }
        }
        if (count >= 20)
        {
            DebugWrite("FAILED(4)\r\n");
            return;
        }
    }

    count = 0;
    sendCANCommand(id, reset3, 8);
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res3, 3) > 0)
        {
            DebugWrite("3!\r\n");
            break;
        }
        else
        {

        }
    }
    if (count >= 20)
    {
        DebugWrite("FAILED(5)\r\n");
        return;
    }
    if (extrabyte > 0)
    {
        count = 0;
        sendCANCommand(id, reset4a, 8);
        while (count++ < 20)
        {
            if (doFindExpectedResponse(&msg, resp, res4a, 3) > 0)
            {
                DebugWrite("4a!\r\n");
                break;
            }
            else
            {

            }
        }
        if (count >= 20)
        {
            DebugWrite("FAILED(6)\r\n");
            return;
        }
    }
    count = 0;

    DebugWrite("SENDING PUMP COMMAND\r\n");
    sendCANCommand(id, pump, 8);
    DebugWrite("SEQUENCE ON COMMAND\r\n");
    sendCANCommand(id, pump2, 8);
    s->primeFuelPumpCount = 5;
}

void doResetSequence(struct sHeatVars* s)
{
    int extrabyte = 0;
    int count;
    sendWakeCommand(s);

    CANMessage msg;
    int id = CTRLCHANNEL;
    int resp = CTRLRESPONSE;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }
    // read data F1F2 identifiers...
    char reset1[8] =
    { 0x03, 0x22, 0xF1, 0xF2, 0x00, 0x00, 0x00, 0x00 };
    char res1[5] =
    { 0x10, 0x09, 0x62, 0xF1, 0xF2 };

    // not sure
    char reset2[8] =
    { 0x30, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char res2[5] =
    { 0x21, 0x00, 0x00, 0x60, 0xF2 };

    // security access
    char reset3[8] =
    { 0x02, 0x27, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00 };
    // security response
    char res3[4] =
    { 0x06, 0x67, 0x63, 0x00 };

    // clear diagnostics
    char reset4[8] =
    { 0x04, 0x14, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00 };
    // response
    char res4[4] =
    { 0x01, 0x54, 0x63, 0x00 };

    // routine control
    char reset5[8] =
    { 0x04, 0x31, 0x01, 0xF0, 0x05, 0x00, 0x00, 0x00 };
    char res5[5] =
    { 0x04, 0x71, 0x01, 0xF0, 0x05 };

    char reset3a[8] =
    { 0x02, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char res3a[3] =
    { 0x06, 0x50, 0x01 };

    // change to session '60'
    char reset3b[8] =
    { 0x02, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char res3b[3] =
    { 0x06, 0x50, 0x60 };

    // scurity access
    char reset4a[8] =
    { 0x06, 0x27, 0x64, 0x00, 0x00, 0x10, 0x60, 0x00 };
    char res4a[4] =
    { 0x02, 0x67, 0x64, 0x00 };
    count = 0;
    DebugWrite("***RESET1\r\n");
    sendCANCommand(id, reset1, 8);
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res1, 3) > 0)
        {
            printf("1!\r\n");
            break;
        }
        else
        {
            if (msg.id == 0x073)
            {
                DebugWrite("Got-");
                printCAN(&msg);
            }
        }
    }
    if (count >= 20)
    {
        DebugWrite("FAILED(1)\r\n");
        return;
    }
    count = 0;
    sendCANCommand(id, reset2, 8);
    DebugWrite("***RESET2\r\n");
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res2, 3) > 0)
        {
            DebugWrite("2!\r\n");
            break;
        }
        else
        {

        }
    }
    if (count >= 20)
    {
        DebugWrite("FAILED(2)\r\n");
        return;
    }
    // check msg byte 4, if 01, additional commands
    extrabyte = msg.data[3];
    if (extrabyte > 0)
    {
        count = 0;
        sendCANCommand(id, reset3a, 8);
        while (count++ < 20)
        {
            if (doFindExpectedResponse(&msg, resp, res3a, 3) > 0)
            {
                DebugWrite("3a!\r\n");
                break;
            }
            else
            {

            }
        }
        if (count >= 20)
        {
            DebugWrite("FAILED(3)\r\n");
            return;
        }
        count = 0;
        sendCANCommand(id, reset3b, 8);
        while (count++ < 20)
        {
            if (doFindExpectedResponse(&msg, resp, res3b, 3) > 0)
            {
                DebugWrite("3b!\r\n");
                break;
            }
            else
            {

            }
        }
        if (count >= 20)
        {
            DebugWrite("FAILED(4)\r\n");
            return;
        }
    }
    count = 0;
    sendCANCommand(id, reset3, 8);
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res3, 3) > 0)
        {
            DebugWrite("3!\r\n");
            break;
        }
        else
        {

        }
    }
    if (count >= 20)
    {
        DebugWrite("FAILED(5)\r\n");
        return;
    }
    if (extrabyte > 0)
    {
        count = 0;
        sendCANCommand(id, reset4a, 8);
        while (count++ < 20)
        {
            if (doFindExpectedResponse(&msg, resp, res4a, 3) > 0)
            {
                DebugWrite("4a!\r\n");
                break;
            }
            else
            {

            }
        }
        if (count >= 20)
        {
            DebugWrite("FAILED(6)\r\n");
            return;
        }
    }
    count = 0;
    sendCANCommand(id, reset4, 8);
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res4, 3) > 0)
        {
            printf("4!\r\n");
            break;
        }
        else
        {

        }
    }
    if (count >= 20)
    {
        printf("FAILED(7)\r\n");
        return;
    }
    count = 0;
    sendCANCommand(id, reset5, 8);
    while (count++ < 20)
    {
        if (doFindExpectedResponse(&msg, resp, res5, 3) > 0)
        {
            printf("5!\r\n");
            break;
        }
        else
        {

        }
    }
    if (count >= 20)
    {
        printf("FAILED(8)\r\n");
        return;
    }
    printf("SUCCESS\r\n");
}
int doFindExpectedResponse(CANMessage* msg, const uint16_t expectedID, const char* expectedResponse, int charsInMatch)
{
    char buff[256];
    //printf("fe-a\r\n");
    int timeout = 0;
    wiced_bool_t couldRead = WICED_FALSE;
    int incoming = 0;

    while ((incoming == 0) && (timeout++ < 10))
    {

        incoming = can2.read(*msg);
        //printf("fe-b %d\r\n", incoming);
        if (incoming > 0)
        {
            couldRead = WICED_TRUE;
        }
        if (!couldRead)
        {
            wait(0.01);
        }
    }
    //printf("fe-c\r\n");
    if (incoming > 0)
    {

        //CAN_FIFORelease(CAN1, CAN_FIFO0);
        if (msg->id != expectedID)
        {
            //sprintf(buff, "No match: %04X\r\n", (unsigned int) msg->StdId);
            //DebugWrite(buff);
            return 0; // not a match
        }
        // ignore byte 1
        for (int i = 1; i < charsInMatch; i++)
        {
            if (!(msg->data[i] == expectedResponse[i]))
            {
                // no match
                return 0;
            }
            return 1; // match
        }
        // no chars in match, always a match?
        return 1;
    }
    else
    {
        return -1; // no read
    }
}
void printCAN(CANMessage *canMsg)
{
    char buff[256];
    sprintf(buff, "ID,%04X:", (unsigned int) canMsg->id);

    DebugWrite(buff);
    for (int i = 0; i < canMsg->len; i++)
    {
        sprintf(buff, "%02X ", canMsg->data[i]);
        DebugWrite(buff);
    }
    DebugWrite("\r\n");
}

void printCANTx(CANMessage *canMsg)
{
    char buff[256];
    sprintf(buff, "->ID,%04X:", (unsigned int) canMsg->id);

    DebugWrite(buff);
    for (int i = 0; i < canMsg->len; i++)
    {
        sprintf(buff, "%02X ", canMsg->data[i]);
        DebugWrite(buff);
    }
    DebugWrite("\r\n");
}
void sendGetRuntime(struct sHeatVars *s, char *buff)
{
    int count = 0;
    CANMessage rxMsg;
    int id;
    int resp;
    id = CTRLCHANNEL;
    resp = CTRLRESPONSE;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }

    const char msgbytes[8] =
    { 0x03, 0x22, 0xFD, 0x17, 0x00, 0x00, 0x00, 0x00 };
    const char continuePacket[8] =
    { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    sendCANCommand(id, msgbytes, 8);
    //The control unit reads out the operating hours counter using the UDS service 22 ID: FD17
    while (count++ < 10)
    {
        // just expect the ID (0
        if (doFindExpectedResponse(&rxMsg, resp, msgbytes, 0) > 0)
        {
            printCAN(&rxMsg);
            // response in the format 59
            // the first byte dictates the length

            //073C:03 59 02 7B 05 48 C3 01

            if (rxMsg.data[0] < 0x10)
            {
                DebugWrite("Single Message. Shouldn't happen\r\n");
            }
            else if (rxMsg.data[0] < 0x20)
            {

                int totalLength = rxMsg.data[1];
                unsigned int totalExpectedPackets = ((totalLength - 7) / 7) + 1;
                unsigned char dataBytes[6 + totalExpectedPackets * 7];
                memset(dataBytes, 0, 6 + totalExpectedPackets * 7);

                // first packet contains 6 bytes of data, additional contain 7
                // length 11: 1 extra packet        ((11 - 6 - 1) \ 7) + = 4\7 + 1 = 1
                // length 13: 1 extra packet        ((13 - 6 - 1) \ 7) + = 6\7 + 1 = 1
                // length 14: 2 packets             ((14 - 6 - 1) \ 7) + = 7\7 + 1 = 2
                // length 20: 2 packets             ((20 - 6 - 1) \ 7) + = 7\7 + 1 = 2
                // length 21: 3 packets             ((21 - 6 - 1) \ 7) + = 7\7 + 1 = 3
                // Packets = lenght is ((length - 7) \ 7) + 1

              sprintf(buff, "multi message start, length %d\r\n", rxMsg.data[1]);
              DebugWrite(buff);

                printCAN(&rxMsg);
                /*Query 03 19 02 08
                 * ID,073C:[10 0B] [59 02] [7B] 00 02 11]
                 * ID,073C:21 2B 00 02 A1 2A xx xx
                 * 10: Multi message start packet
                 * 0B: Length (11 DATA bytes).  x'd out non-data
                 * 59: response type 59
                 * 02: subfunction 2
                 * 7B: mask
                 * 00 02 11: first 3 bytes of fault.  Need next part
                 */
                // get the first fault code, bytes 4-7
                sendCANCommand(id, continuePacket, 8);
                CANMessage additionalRxMsg[totalExpectedPackets];
                int currentPacket = 0;
                while (count++ < 10)
                {

                    if (doFindExpectedResponse(&(additionalRxMsg[currentPacket]), resp, msgbytes, 0) > 0)
                    {
                        count = 0;
                        currentPacket++;
                        if (currentPacket >= totalExpectedPackets)
                        {
                            DebugWrite("Found all additional packets\r\n");

                            memcpy(dataBytes, rxMsg.data + 2, 6); // 6 initial data bytes
                            for (int i = 0; i < totalExpectedPackets; i++)
                            {
                                memcpy(dataBytes + 6 + (totalExpectedPackets * i), additionalRxMsg[i].data + 1, 7);
                            }

                            DebugWrite("Runtime Data bytes: ");
                            for (int i = 0; i < totalLength; i++)
                            {
                                sprintf(buff, "%02X ", dataBytes[i]);
                                DebugWrite(buff);
                            }
                            //DebugWrite("\r\n");

                            long runtime = -1;
                            // bytes 3-6 are runtime
                            if (totalLength > 6)
                            {
                                runtime = dataBytes[3];
                                runtime = runtime << 8;
                                runtime = runtime + dataBytes[4];
                                runtime = runtime << 8;
                                runtime = runtime + dataBytes[5];
                                runtime = runtime << 8;
                                runtime = runtime + dataBytes[6];
                                s->heaterRuntime = runtime;
                            }
                            s->heaterRuntime = runtime;
                            break;
                        }

                    }
                } // outer while
            }
        }
    } // while
    printf("f-b\r\n");
    if (count >= 10)
    {
        printf("FAILED or done\r\n");
        return;
    }
    return;
}
wiced_result_t sendGetGeneric(struct sHeatVars *s, char *buff, const char msgbytes[8], CANMessage* rxMsg)
{
    int id;
    int resp = CTRLRESPONSE;
    id = CTRLCHANNEL;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }

    const char continuePacket[8] =
    { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    //DebugWrite("************\r\n");
    sendCANCommand(id, msgbytes, 8);
    if (doFindExpectedResponse(rxMsg, resp, msgbytes, 0) > 0)
    {
        return WICED_SUCCESS;
    }
    return WICED_NOT_FOUND;
}
void sendGetTemperatures(struct sHeatVars *s, char *buff)
{

    int id;
    int count;
    int resp = CTRLRESPONSE;
    id = CTRLCHANNEL;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }
    CANMessage rxMsg;
    const char msgbytes[8] =
    { 0x03, 0x22, 0xFD, 0x01, 0x00, 0x00, 0x00, 0x00 };

    const char continuePacket[8] =
    { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    count = 0;

    //DebugWrite("************\r\n");
    sendCANCommand(id, msgbytes, 8);
    // just expect the ID (0

    if (doFindExpectedResponse(&rxMsg, resp, msgbytes, 0) > 0)
    {
        //DebugWrite("********(a)****\r\n");
        printCAN(&rxMsg);

        // response is a multi part
        if (rxMsg.data[0] < 0x10)
        {
            DebugWrite("Single Message. Shouldn't happen\r\n");
        }
        else if (rxMsg.data[0] < 0x20)
        {
            int totalLength = rxMsg.data[1];
            unsigned int totalExpectedPackets = ((totalLength - 7) / 7) + 1;
            unsigned char dataBytes[6 + totalExpectedPackets * 7];
            memset(dataBytes, 0, 6 + totalExpectedPackets * 7);

            // first packet contains 6 bytes of data, additional contain 7
            // length 11: 1 extra packet        ((11 - 6 - 1) \ 7) + = 4\7 + 1 = 1
            // length 13: 1 extra packet        ((13 - 6 - 1) \ 7) + = 6\7 + 1 = 1
            // length 14: 2 packets             ((14 - 6 - 1) \ 7) + = 7\7 + 1 = 2
            // length 20: 2 packets             ((20 - 6 - 1) \ 7) + = 7\7 + 1 = 2
            // length 21: 3 packets             ((21 - 6 - 1) \ 7) + = 7\7 + 1 = 3
            // Packets = lenght is ((length - 7) \ 7) + 1

            sprintf(buff, "multi message start, length %d\r\n", rxMsg.data[1]);
            DebugWrite(buff);

            printCAN(&rxMsg);
            /*Query 03 19 02 08
             * ID,073C:[10 0B] [59 02] [7B] 00 02 11]
             * ID,073C:21 2B 00 02 A1 2A xx xx
             * 10: Multi message start packet
             * 0B: Length (11 DATA bytes).  x'd out non-data
             * 59: response type 59
             * 02: subfunction 2
             * 7B: mask
             * 00 02 11: first 3 bytes of fault.  Need next part
             */
            // get the first fault code, bytes 4-7
            sendCANCommand(id, continuePacket, 8);
            CANMessage additionalRxMsg[totalExpectedPackets];
            int currentPacket = 0;
            while (count++ < 10)
            {

                if (doFindExpectedResponse(&(additionalRxMsg[currentPacket]), resp, msgbytes, 0) > 0)
                {
                    count = 0;
                    currentPacket++;
                    if (currentPacket >= totalExpectedPackets)
                    {
                        //DebugWrite("Found all additional packets\r\n");

                        memcpy(dataBytes, rxMsg.data + 2, 6); // 6 initial data bytes
                        for (int i = 0; i < totalExpectedPackets; i++)
                        {
                            memcpy(dataBytes + 6 + (totalExpectedPackets * i), additionalRxMsg[i].data + 1, 7);
                        }

                        s->flameTemp = dataBytes[3];
                        s->flameTemp = s->flameTemp << 8;
                        s->flameTemp += dataBytes[4];
                        s->flameTemp -= 5000;

                        s->inletTemp = dataBytes[5];
                        s->inletTemp = s->inletTemp << 8;
                        s->inletTemp += dataBytes[6];
                        s->inletTemp -= 5000;

                        s->outletTemp = dataBytes[7];
                        s->outletTemp = s->outletTemp << 8;
                        s->outletTemp += dataBytes[8];
                        s->outletTemp -= 5000;

                        DebugWrite(" **\r\n");
                        //DebugWrite("\r\n");

                        //long runtime = -1;
                        // bytes 3-6 are runtime
                        /*
                         if (totalLength > 6)
                         {
                         runtime = dataBytes[3];
                         runtime = runtime << 8;
                         runtime = runtime + dataBytes[4];
                         runtime = runtime << 8;
                         runtime = runtime + dataBytes[5];
                         runtime = runtime << 8;
                         runtime = runtime + dataBytes[6];
                         s->heaterRuntime = runtime;
                         }
                         s->heaterRuntime = runtime;
                         */
                        break;
                    }
                }
            }
        }
    }
    printf("f-b\r\n");
    if (count >= 10)
    {
        printf("FAILED\r\n");
        return;
    }
    return;
}
void sendGetBattery(struct sHeatVars *s, char *buff)
{
    int count;
    CANMessage rxMsg;
    char msgbytes[8] =
    { 0x03, 0x22, 0xFD, 0x04, 0x00, 0x00, 0x00, 0x00 };
// response is on 73C: 0x05, 0x62, 0xFD, 0x04, [0x00, 0x7D], 0xB0, 0x1C
    int id;
    int resp = CTRLRESPONSE;
    id = CTRLCHANNEL;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }
    count = 0;
    sendCANCommand(id, msgbytes, 8);
    int batt = 0;
    msgbytes[1] = 0x62;
    while (count++ < 10)
    {
// just expect the ID (0
        if (doFindExpectedResponse(&rxMsg, resp, msgbytes, 4) > 0)
        {
            printCAN(&rxMsg);
            batt = rxMsg.data[4];
            batt = batt << 8;
            batt += rxMsg.data[5];
            s->battV = batt;
        }
    }
}
void sendGetAltitude(struct sHeatVars *s, char *buff)
{
    //DebugWrite("ALTITUDE******\r\n");
    int count;
    CANMessage rxMsg;
    char msgbytes[8] =
    { 0x03, 0x22, 0xFD, 0x36, 0x00, 0x00, 0x00, 0x00 };
// response is on 73C: 0x05, 0x62, 0xFD, 0x04, [0x00, 0x7D], 0xB0, 0x1C
    int id;
    int resp = CTRLRESPONSE;
    id = CTRLCHANNEL;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }
    count = 0;
    sendCANCommand(id, msgbytes, 8);
    int alt = 0;
    msgbytes[1] = 0x62;
    while (count++ < 10)
    {
// just expect the ID (0
        if (doFindExpectedResponse(&rxMsg, resp, msgbytes, 4) > 0)
        {
            printCAN(&rxMsg);
            alt = rxMsg.data[4];
            alt = alt << 8;
            alt += rxMsg.data[5];
            s->altitude = alt / 10;
        }
    }
    //DebugWrite("ALTITUDE******\r\n");
}

void sendGetFault(struct sHeatVars *s, char *buff)
{
    //DebugWrite("Fault command\r\n");
    CANMessage rxMsg;
    int count;
    // 3 bytes, function 19, command 2, mask 8 (all confirmed errors) (failed this cycle)
    const char msgbytes[8] =
    { 0x03, 0x19, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00 };
    const char continuePacket[8] =
    { 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    int id;
    int resp = CTRLRESPONSE;
    id = CTRLCHANNEL;
    if (s->heaternum == 2)
    {
        id = CTRLCHANNEL2;
        resp = CTRLRESPONSE2;
    }
    count = 0;
    sendCANCommand(id, msgbytes, 8);

    while (count++ < 10)
    {
        // just expect the ID (0
        if (doFindExpectedResponse(&rxMsg, resp, msgbytes, 0) > 0)
        {
            printCAN(&rxMsg);
            // response in the format 59
            // the first byte dictates the length

            //073C:03 59 02 7B 05 48 C3 01

            if (rxMsg.data[0] < 0x10)
            {
                DebugWrite("Single Message. ");
                if (rxMsg.data[0] == 0x03)
                {
                    // 59 is a resonse.  Mask info isnt useful because no faults
                    if (rxMsg.data[1] == 0x59)
                    {
                        // no faults
                        if (s->currentError != 0)
                        {
                            s->errorChangeFlag = 1;
                        }
                        sprintf(buff, "NO FAULTS (reset)\r\n");
                        DebugWrite(buff);
                        s->currentError = 0x00;
                        s->errorHistory[0] = 0x0;
                        s->errorHistory[1] = 0x0;
                        s->errorHistory[2] = 0x0;
                        s->errorHistory[3] = 0x0;
                        s->errorHistory[4] = 0x0;
                        s->errorHistory[5] = 0x0;
                        break; // out of the loop
                    }
                }
                else if ((rxMsg.data[0] == 0x07) && rxMsg.data[1] == 0x59)
                {

                    //ID,073C:07 59 02 7B 00 02 11 2A
                    // 07 length
                    // 59 response

                    // one fault.  Is it a current fault?
                    if ((rxMsg.data[5] == 0x00) && (rxMsg.data[6] == 0x00))
                    {
                        // the fault isn't a fault.
                        sprintf(buff, "NO FAULTS\r\n");
                        DebugWrite(buff);
                        if (s->currentError != 0)
                        {
                            s->errorChangeFlag = 1;
                        }
                        s->currentError = 0x00;
                        s->errorHistory[0] = 0x0;
                        s->errorHistory[1] = 0x0;
                        s->errorHistory[2] = 0x0;
                        s->errorHistory[3] = 0x0;
                        s->errorHistory[4] = 0x0;
                        s->errorHistory[5] = 0x0;
                    }
                    else
                    {

                        //A: 0010 1010 bit 1 is test failed this cycle
                        //B: 0010 1011 bit 0 is test failed.  Seems to be considered
                        //                   active if bit 0 is '1'

                        // bit 5 test failed since last clear

                        //07 59 02 7B 00 02 11 2A

                        uint16_t newError = rxMsg.data[5];
                        newError *= 256;
                        newError += rxMsg.data[6];
                        wiced_bool_t gotAnError = WICED_FALSE;
                        // is it a current fault?
                        if ((rxMsg.data[7] & 0x01) == 0x01)
                        {
                            gotAnError = WICED_TRUE;
                            if (s->currentError != newError)
                            {
                                s->errorChangeFlag = 1;
                            }
                            // active fault
                            s->currentError = newError;
                        }
                        if (!gotAnError)
                        {
                            s->currentError = 0;
                        }
                        // also first history fault
                        s->errorHistory[0] = newError;

                        sprintf(buff, "FAULT(h%d): %02X%02X\r\n", s->heaternum, rxMsg.data[5], rxMsg.data[6]);
                        DebugWrite(buff);

//                      if (s->currentError != newError)
//                      {
//                          s->errorChangeFlag = 1;
//                      }
                        //errorChangeFlag
                    }
                }
            }
            else if (rxMsg.data[0] < 0x20)
            {

                int totalLength = rxMsg.data[1];
                unsigned int totalExpectedPackets = ((totalLength - 7) / 7) + 1;
                unsigned char dataBytes[6 + totalExpectedPackets * 7];
                memset(dataBytes, 0, 6 + totalExpectedPackets * 7)

                ;
                // first packet contains 6 bytes of data, additional contain 7
                // length 11: 1 extra packet        ((11 - 6 - 1) \ 7) + = 4\7 + 1 = 1
                // length 13: 1 extra packet        ((13 - 6 - 1) \ 7) + = 6\7 + 1 = 1
                // length 14: 2 packets             ((14 - 6 - 1) \ 7) + = 7\7 + 1 = 2
                // length 20: 2 packets             ((20 - 6 - 1) \ 7) + = 7\7 + 1 = 2
                // length 21: 3 packets             ((21 - 6 - 1) \ 7) + = 7\7 + 1 = 3
                // Packets = lenght is ((length - 7) \ 7) + 1

//              sprintf(buff, "multi message start, length %d\r\n", rxMsg.data[1]);
//              DebugWrite(buff);

                printCAN(&rxMsg);
                /*Query 03 19 02 08
                 * ID,073C:[10 0B] [59 02] [7B] 00 02 11]
                 * ID,073C:21 2B 00 02 A1 2A xx xx
                 * 10: Multi message start packet
                 * 0B: Length (11 DATA bytes).  x'd out non-data
                 * 59: response type 59
                 * 02: subfunction 2
                 * 7B: mask
                 * 00 02 11: first 3 bytes of fault.  Need next part
                 */
                // get the first fault code, bytes 4-7
                sendCANCommand(id, continuePacket, 8);
                CANMessage additionalRxMsg[totalExpectedPackets];
                int currentPacket = 0;
                while (count++ < 10)
                {
                    if (doFindExpectedResponse(&(additionalRxMsg[currentPacket]), resp, msgbytes, 0) > 0)
                    {
                        count = 0;
                        currentPacket++;
                        if (currentPacket >= totalExpectedPackets)
                        {
                            DebugWrite("Found all additional packets\r\n");

                            memcpy(dataBytes, rxMsg.data + 2, 6); // 6 initial data bytes
                            for (int i = 0; i < totalExpectedPackets; i++)
                            {
                                sprintf(printbuff, "- copying packet %d to databytes + %d\r\n", i, 6 + (i) * 7);
                                DebugWrite(printbuff);
                                memcpy(dataBytes + 6 + ((i) * 7), additionalRxMsg[i].data + 1, 7);

                            }
                            DebugWrite("Data bytes: ");
                            for (int i = 0; i < totalLength; i++)
                            {
                                sprintf(buff, "%02X ", dataBytes[i]);
                                DebugWrite(buff);
                            }
                            DebugWrite("\r\n");

                            uint16_t newError;
                            wiced_bool_t gotAnError = WICED_FALSE;
                            //Data bytes: 59 02 7B [00 02 11 2B] [00 02 A1 28]

                            for (int i = 0; i < 6; i++)
                            {
                                s->errorHistory[i] = 0;
                            }
                            for (int i = 3; i < totalLength; i += 4)
                            {
                                newError = dataBytes[i + 1];
                                newError *= 256;
                                newError += dataBytes[i + 2];

                                // is it a current fault?
                                if ((dataBytes[i + 3] & 0x01) == 0x01)
                                {
                                    gotAnError = WICED_TRUE;
                                    if (s->currentError != newError)
                                    {
                                        s->errorChangeFlag = 1;
                                    }
                                    // active fault
                                    s->currentError = newError;
                                }
                                // history fault
                                if (((i - 3) / 4) < 6)
                                {
                                    s->errorHistory[(i - 3) / 4] = newError;
                                }

                                sprintf(buff, "FAULT: %02X%02X\r\n", dataBytes[i + 1], dataBytes[i + 2]);
                                DebugWrite(buff);
                            }
                            if (!gotAnError)
                            {
                                s->currentError = 0; // no error to start.
                            }
                            // clear the remainder
                            break;
                        }
                    }
                }
            }
        }
    } // while
    printf("f-b\r\n");
    if (count >= 10)
    {
        printf("FAILED\r\n");
        return;
    }
    printf("f-c\r\n");
    if ((rxMsg.data[0] == 0x03) && (rxMsg.data[1] == 0x59) && (rxMsg.data[5] == 0x56) && (rxMsg.data[6] == 0x78))
    {

        if (s->currentError != 0)
        {
            s->errorChangeFlag = 1;
        }
        sprintf(buff, "NO FAULTS (reset)\r\n");
        DebugWrite(buff);
        s->currentError = 0x00;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
    }
    else if ((rxMsg.data[0] == 0x03) && (rxMsg.data[1] == 0x59) && (rxMsg.data[5] == 0x00) && (rxMsg.data[6] == 0x00))
    {
        if (s->currentError != 0)
        {
            s->errorChangeFlag = 1;
        }
        sprintf(buff, "NO FAULTS(1)\r\n");
        DebugWrite(buff);
        s->currentError = 0x00;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
        s->errorHistory[0] = 0x0;
    }
    else if ((rxMsg.data[0] == 0x07) && (rxMsg.data[1] == 0x59) && (rxMsg.data[2] == 0x02))
    {
        if ((rxMsg.data[5] == 0x00) && (rxMsg.data[6] == 0x00))
        {
            sprintf(buff, "NO FAULTS\r\n");
            DebugWrite(buff);
            if (s->currentError != 0)
            {
                s->errorChangeFlag = 1;
            }
            s->currentError = 0x00;
            s->errorHistory[0] = 0x0;
            s->errorHistory[1] = 0x0;
            s->errorHistory[2] = 0x0;
            s->errorHistory[3] = 0x0;
            s->errorHistory[4] = 0x0;
            s->errorHistory[5] = 0x0;
        }
        else
        {
            sprintf(buff, "FAULT: %02X%02X\r\n", rxMsg.data[5], rxMsg.data[6]);
            DebugWrite(buff);
            uint16_t newError = rxMsg.data[5];
            newError *= 256;
            newError += rxMsg.data[6];
            if (s->currentError != newError)
            {
                s->errorChangeFlag = 1;
            }
            //errorChangeFlag
            s->currentError = newError;
            s->errorHistory[0] = newError;
        }
        printf("SUCCESS\r\n");
    }
    else if ((rxMsg.data[0] == 0x03) && (rxMsg.data[1] == 0x59) && (rxMsg.data[2] == 0x02))
    {
        // this means cleared in both cases!
        if (s->currentError != 0)
        {
            s->errorChangeFlag = 1;
        }
        sprintf(buff, "NO FAULTS(2)\r\n");
        DebugWrite(buff);
        s->currentError = 0x00;
        s->errorHistory[0] = 0x0;
        s->errorHistory[1] = 0x0;
        s->errorHistory[2] = 0x0;
        s->errorHistory[3] = 0x0;
        s->errorHistory[4] = 0x0;
        s->errorHistory[5] = 0x0;
    }
    else if ((rxMsg.data[0] == 0x10) && (rxMsg.data[1] == 0x0B))
    {
        sprintf(buff, " MULTI FAULT: %02X%02X\r\n", rxMsg.data[6], rxMsg.data[7]);
        DebugWrite(buff);
        uint16_t newError = rxMsg.data[6];
        newError *= 256;
        newError += rxMsg.data[7];
        if (s->currentError != newError)
        {
            s->errorChangeFlag = 1;
        }
        s->currentError = newError;
        s->errorHistory[0] = newError;
    }
    else
    {
        sprintf(buff, "OTHER RESPONSE\r\n");
        DebugWrite(buff);
        printCAN(&rxMsg);
    }
    printf("f-d\r\n");
}

void readCAN(struct sHeatVars *s)
{
    // find the heater to update in some cases
    int count = 0;
    struct sHeatVars* heaterToUpdate = NULL;
    //DebugWrite("read\r\n");
    CANMessage canMsg;
    
    int incoming = can2.read(canMsg);
    while ((incoming > 0) && (count++ < 10))
    {
       
        // start blank
        if ((canMsg.id == 0x0055)) {
            // sub our own
            DebugWrite("SUBSTITUTE ALTITUDE CMD\r\n");
            sendAltitudeMode(s);
        }
        if ((canMsg.id == 0x07A0) || (canMsg.id == 0x060D) || (canMsg.id == 0x0057) )
        {
            otherControllerDetected = 300;
            DebugWrite("\r\n****OTHER CONTROLLER ON NETWORK*****\r\n");
        }
        if (((canMsg.id != 0x0625) && (canMsg.id != 0x02C4)) && (canMsg.id != 0x02C6) && (canMsg.id != 0x0626) && (canMsg.id != 0x02D0)
                && (canMsg.id != 0x02CE))
        {
            
            DebugWrite("0-");
            printCAN(&canMsg);
        }
        else if ((canMsg.id == 0x0625) || (canMsg.id == 0x0626))
        {
            if ((canMsg.id == 0x0625) && (heaterState[0].bustype == HEATERTYPECAN) && (heaterState[0].heaternum == 1))
            {
                heaterToUpdate = &(heaterState[0]);
            }
            else if ((canMsg.id == 0x0626) && (heaterState[0].bustype == HEATERTYPECAN) && (heaterState[0].heaternum == 2))
            {
                heaterToUpdate = &(heaterState[0]);
            }
            heaterToUpdate->heaterDetected = 60; // preserve for a min.
            // unpack and document
            NM_Heater_1_t heaterInfo;
            Unpack_NM_Heater_1_mydbc(&heaterInfo, canMsg.data, 0);
            //DebugWrite("NM_HEATER_");

            /*
             sprintf(printbuff, "%d,%lu,", heaterToUpdate->heaternum, heaterInfo.SerialNumber);
             DebugWrite(printbuff);
             if (heaterInfo.HeaterInitFinished)
             {
             DebugWrite("DoneInit,");
             }
             else
             {
             DebugWrite("NOINIT,");
             }
             */
            if (heaterInfo.HeaterType == 0)
            {
//              DebugWrite("Air,");
                if (heaterToUpdate->setpoint == 0)
                {
                    heaterToUpdate->setpoint = 250;
                }
            }
            else if (heaterInfo.HeaterType == 1)
            {
//              DebugWrite("Water,");
                heaterToUpdate->setpoint = 0;
            }
            else
            {
//              DebugWrite("Unknown,");
            }
            if (heaterInfo.AltitudeSensorOnBoard)
            {
//              DebugWrite("OB Alt,");
                heaterToUpdate->OBAltitude = WICED_TRUE;
            }
            else
            {
//              DebugWrite("NO OB ALT,");
                heaterToUpdate->OBAltitude = WICED_FALSE;
            }
            /*(
             if (heaterInfo.OperateEasyFan)
             {
             DebugWrite("EZFAN,");
             }
             else
             {
             DebugWrite("NO-EZFAN,");
             }
             sprintf(printbuff, "Op:%u,", heaterInfo.OperatingModes);
             DebugWrite(printbuff);

             DebugWrite(",");
             DebugWrite("\r\n");
             */
        }
        else if ((canMsg.id == 0x02C6) || (canMsg.id == 0x02D0))
        {

            if (canMsg.id == 0x02C6)
            {
                if ((heaterState[0].bustype == HEATERTYPECAN) && (heaterState[0].heaternum == 1))
                {
                    heaterToUpdate = &(heaterState[0]);
                }
                else
                {
                    DebugWrite("Unable to update 0x02C6\r\n");
                }
            }
            else if (canMsg.id == 0x02D0)
            {
                if ((heaterState[0].bustype == HEATERTYPECAN) && (heaterState[0].heaternum == 2))
                {
                    heaterToUpdate = &(heaterState[0]);
                }
                else
                {
                    DebugWrite("Unable to update 0x02D0\r\n");
                }
            }
            if (heaterToUpdate == NULL)
            {
                DebugWrite("HEATERTOUPDATENULL\r\n");
                return;
            }
            int lowRange = canMsg.data[1];
            lowRange = lowRange << 8;
            lowRange += canMsg.data[0];

            int highRange = canMsg.data[3];
            highRange = highRange << 8;
            highRange += canMsg.data[2];
            if (lowRange > highRange)
            {
                int temp = lowRange;
                lowRange = highRange;
                highRange = temp;
            }

            //sprintf(printbuff, "Temp range %d - %d heater %d\r\n", lowRange, highRange, heaterToUpdate->heaternum);
            //DebugWrite(printbuff);
            //printCAN(&canMsg);

            /*
             * now detected by heater NM command
             if (heaterToUpdate->heaternum == 2)
             {
             // eventually replace with the equivalent of 0x0625
             if (highRange > 500)
             {
             //sprintf(printbuff, "heater %d setpoint > 500\r\n", heaterToUpdate->heaternum);
             //DebugWrite(printbuff);
             heaterToUpdate->setpoint = 0;

             // fluid heater
             }
             else
             {
             //
             if (heaterToUpdate->setpoint == 0)
             {
             // sprintf(printbuff, "heater %d setpoint 250", heaterToUpdate->heaternum);
             // DebugWrite(printbuff);

             heaterToUpdate->setpoint = 250; // default value.  Ignored mostly in CAN land.
             }
             }
             }
             */
        }
        else if ((canMsg.id == 0x02C4) || (canMsg.id == 0x02CE))
        {
            int heater = 1;
            if (canMsg.id == 0x02CE)
            {
                heater = 2;
            }
            if ((heaterState[0].bustype == HEATERTYPECAN) && (heaterState[0].heaternum == heater))
            {
                heaterToUpdate = &(heaterState[0]);
            }
            else
            {
                DebugWrite("Unable to update 0x02C6\r\n");
            }
            //DebugWrite("OBK_STATUS_HEATER_1\r\n");
            OBK_Status_Heater_1_t heaterStatus;
            Unpack_OBK_Status_Heater_1_mydbc(&heaterStatus, canMsg.data, 0);

            heaterToUpdate->heaterTemp = heaterStatus.HeaterTemperature;
            //sprintf(printbuff, "OBK_STATUS_HEATER_%d,temp %ld,", heater, heaterStatus.HeaterTemperature);
            //DebugWrite(printbuff);
            if (heaterStatus.isValid)
            {
                DebugWrite("Valid,");
            }
            else
            {
                DebugWrite("!Valid,");
            }
            if (heaterStatus.noHeatModeActive)
            {
                DebugWrite("NOHEAT,");
                heaterToUpdate->heatCallDetected = WICED_FALSE;
            }
            if (heaterStatus.standbyHeatingActive)
            {
                DebugWrite("STANBYHEAT,");
                heaterToUpdate->heatCallDetected = WICED_TRUE;
            }
            if (heaterStatus.standbyHeatingWithSetpointActive)
            {
                DebugWrite("STANDBYHEATSETPOINT,");
                heaterToUpdate->heatCallDetected = WICED_TRUE;
            }
            if (heaterStatus.ResidualHeat > 0)
            {
                DebugWrite("RESIDUAL,");
            }
            if (heaterStatus.ErrorClass1)
            {
                DebugWrite("F1,");
            }
            if (heaterStatus.ErrorClass2)
            {
                DebugWrite("F2,");
            }
            if (heaterStatus.ErrorClass3)
            {
                DebugWrite("F3,");
            }
            if (heaterStatus.ErrorClass4)
            {
                DebugWrite("F4,");
            }
            if (heaterStatus.ErrorClass5)
            {
                DebugWrite("F5,");
            }
            if (heaterStatus.ErrorClass6)
            {
                DebugWrite("F6,");
            }
            if (heaterStatus.HeatingUpActive)
            {
                DebugWrite("HUA,");
            }
            if (heaterStatus.SetpointInvalid)
            {
                DebugWrite("SetpointInvalid,");
            }
            else
            {
                DebugWrite("SetpointValid,");
            }
            if (heaterStatus.AltitudeModeActive)
            {
                DebugWrite("!!**ALT**!!,");
            }
            else
            {
                DebugWrite("NoALT,");
            }

            DebugWrite("V");
            sprintf(printbuff, "%d", heaterStatus.ventilationActive);
            DebugWrite(printbuff);
            DebugWrite("\r\n");

        }
        incoming = can2.read(canMsg);
    }
    //incoming = CAN_MessagePending(CAN1, CAN_FIFO1);

    //DebugWrite("doneread\r\n");
}

//#define LISTENONLY
/* primary heat task start */

wiced_bool_t repeatSent = WICED_FALSE;

void doHeatTaskCAN(struct sHeatVars *s)
{
    if (!(s->bustype == HEATERTYPECAN))
    {
        return;
    }

    char buff[256];

#ifdef LISTENONLY
//  sprintf(buff,"heattask %d\r\n", s->tasksequence);
//  DebugWrite(buff);
#endif
  sprintf(buff,"heattask %d\r\n", s->tasksequence);
  DebugWrite(buff);
    //DebugWrite("Listen Only\r\n");

    readCAN(s);
    if ((otherControllerDetected > 0))
    {
        s->tasksequence = 0;
        s->heatOn = HEATCALLOFF;
        
        return; // don't send anything.
    }
#ifdef LISTENONLY
    return;
#endif
    //return; // listen only.
    idletimer = 60; // disable idle
    if ((s->heatOn != HEATCALLOFF))
    {
        idletimer = 60;
    }
    if ((idletimer <= 0) && (s->heatOn == HEATCALLOFF))
    {
        s->tasksequence = -1;
        DebugWrite("*idle*\r\n");
        return;
    }
    if (s->initTimer > 0)
    {
        sprintf(printbuff,"InitTimer %d\r\n", s->initTimer);
        DebugWrite(printbuff);
        s->tasksequence = 0;
    }
    else if (s->primeFuelPump == WICED_TRUE)
    {
        s->tasksequence = 2;
    }
    else if (s->reset_fault_codes == WICED_TRUE)
    {
        s->tasksequence = 2;
    }
    switch (s->tasksequence++)
    {
        case 4:
            //60F: 0F 11 C9 22 00 20 60 00
            if ((s->heaterDetected > 0) && s->heaternum == 1) // only send if heater is detected.
            {
                if (!repeatSent)
                {
                    repeatSent = WICED_TRUE;
                    sendRepeatMode(s);
                    break;
                }
            }
            //no break
        case 0:
        case 8:
        case 12:
            printf("SendWake\r\n");
            sendWakeCommand(s);

            break;
        case 1:
        case 5:
        case 9:
        case 13:
            sendGetBattery(s, buff);
            sendAltitudeMode(s);
            if ((s->heatOn == HEATCALLINIT) || (s->heatOn == HEATCALLON))
            {

                // a cyclic heat call is always required.
                if (s->setpoint > 0)
                {
                    if (s->heaterSetpointChange != s->setpoint)
                    {
                        s->setpoint = s->heaterSetpointChange;
                    }
                    sendHeatOnCommandSetpoint(s);
                }
                else
                {
                    sendHeatOnCommand(s);
                }

                if (s->heatOn == HEATCALLINIT)
                {
                    s->heatOn = HEATCALLON;
                }
            }
            else if (s->heatOn == HEATCALLOFF)
            {
                sendHeatOffCommand(s);
                // double-if just for clarity
                if ((s->OBAltitude == WICED_FALSE) && (s->heatCallDetected))
                {
                    if ((s->altitudeMode == WICED_TRUE) || (s->internalAltitude > 0))
                    {
                        // send ONLY if heater is in "ON" state.
                        char mysteryCommand[8] =
                        { 0x0F, 0x00, 0xC9, 0x22, 0x00, 0x00, 0x00, 0x00 };
                        sendCANCommand(0x060D, mysteryCommand, 8);
                    }

                }
            }
            break;
        case 2:
        case 6:
        case 10:
        case 14:
            if ((s->heatOn == HEATCALLOFF) && (s->primeFuelPump == WICED_TRUE))
            {
                DebugWrite("IN prime call\r\n");
                s->primeFuelPump = WICED_FALSE; // no prime allowed if heat on
                doPrimeSequence(s);
            }
            else if (s->primeFuelPump == WICED_TRUE)
            {
                DebugWrite("IN prime call FORCED FALSE\r\n");
                s->primeFuelPump = WICED_FALSE; // no prime allowed if heat on
            }
            if (s->reset_fault_codes == WICED_TRUE)
            {
//              doPrimeSequence(s);
//              s->reset_fault_codes = WICED_FALSE;

                printf("RESET faults\r\n");
                s->reset_fault_codes = WICED_FALSE;
                doResetSequence(s);
                // reset fault codes
                printf("****sendGetFaults***\r\n");
                sendGetFault(s, buff);
                printf("***doneGetFaults***\r\n");
            }
            else
            {
                printf("****sendGetFaults***\r\n");
                sendGetFault(s, buff);
                if ((s->errorHistory[0] == 0) || (s->errorHistory[0] == 255))
                {
                    s->reset_fault_codes = WICED_FALSE;
                }
                printf("***doneGetFaults***\r\n");
            }
            // check faults
            break;
        case 3:
            sendGetTemperatures(s, buff);
            break;
        case 7:
            sendGetRuntime(s, buff);
            break;
        case 11:
            sendGetBattery(s, buff);
            break;
            //case 4:
        case 15:
            sendGetAltitude(s, buff);
            break;
        default:
            s->tasksequence = 0;
            break;
    }
    printf("/done\r\n");
    // start with "Wake" message

    return;
}



// imported from picus

void doHeatLogicTask(struct sHeatVars* s)
{
// error flag valid after LINPulse 0.
    if (s->errorChangeFlag == 1)
    {
        s->errorChangeFlag = 0;
        //printf("Error Change %d \r\n",currentError);

        //printf("History %d,%d,%d,%d,%d\r\n",errorHistory[0],errorHistory[1],errorHistory[2],errorHistory[3],errorHistory[4]);

        // reset timer
        resetTimer(s);
        s->reportflag = 1;
        //UARTWrite(1,"Timer reset\r\n");
    }
    //sprintf(printbuff, "tickcount: %d, heaton: %d, heattime: %d\n", s->tickcount, s->heatOn, s->heattime);
    //DebugWrite(printbuff);
// if the error is stable for 15 seconds, report.
    if (s->reportflag == 1 && s->tickcount > 15000 && s->heatOn > 0 && (s->heatcontrolstate != IDLE) && s->resettick == 0)
    {
        // stable for 15 seconds, do report
        if (s->currentError == 0 && s->heatOn > 0)
        {
            s->reportflag = 0;
        }
        else if (s->currentError != 0xFF)
        {
            //printf("Error (heatOn & currentError !=0xFF) \r\n");
            s->reportflag = 0;
            s->heatOn = HEATCALLOFF;
            // disabled retry function per neil at this point.
        }
        else
        {
            //printf( "Error FF: No communication.  Allow heat to continue, but report\r\n");
            // -OR-
            // Retry algorighm on LIN pulse
            s->reportflag = 0;
        }
    }
    else
    {
        //sprintf(printbuff,"%d\r\n",tickcount);
        //UARTWrite(1,printbuff);
    }
    if (s->heatOn == HEATCALLON && (s->heattime == 0 || s->heattime > 86400))
    {
        //printf("Heat off due to time expiry.");
        // no final report.

        if (s->heattime > 0)
        {
            s->heatOn = HEATCALLLONGRUN;
            s->heatresettime = RESETHEATTIME
            ; // reset heat timer
        }
        else
        {
            s->heatOn = HEATCALLOFF;
        }

        s->reportflag = 0;
    }
}

//=========================================================
unsigned char fromHexAscii(char ascii)
{
    if (ascii >= '0' && ascii <= '9')
    {
        return ascii - '0';
    }
    else if (ascii >= 'A' && ascii <= 'F')
    {
        return ascii - 'A' + 10;
    }
    else
    {
        return 255;
    }
}