Penn Electric Racing / Mbed 2 deprecated SystemManagement

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

outDiagnostics/outDiagnostics.cpp

Committer:
pspatel321
Date:
2015-01-06
Revision:
33:6bc82b6b62e5
Parent:
31:7eaa5e881b56
Child:
34:18bcf276d3bf

File content as of revision 33:6bc82b6b62e5:

#include "outDiagnostics.h"

// Macros for working with the string
#define ADD_LINE                  len+=sprintf(buff+len,"%s\r\n",line);                                                    // Add newlines, add it to the working buffer 
#define ADD_SPRINTF_LINE          padCenter(line,max_charsPerLine-2,temp,' '); len+=sprintf(buff+len,"%s\r\n",line);       // Add newlines, add it to the working buffer 
#define BOOL(VAR)                 (VAR)?"ERR":"OK"

// Print to a string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
void padCenter(char *buff, int LineLen, char *str, char pad) {
    int len = strlen(str);
    int padL = (LineLen-len)/2;                              // -1 to save room for the null terminator
    for (int i=0; i<padL; i++) buff[i] = pad;                // Fill in the left padding chars
    strcpy(buff+padL, str);
    for (int i = padL+len; i<LineLen; i++) buff[i] = pad;    // Fill remaining with padding chars
    buff[LineLen-1] = '\0';                                  // Add null terminator
}

// Generates the serial dashboard, uses MODDMA MODSERIAL to speed up printing
void outDiagnostics::thread_serialOut(void const *args) {
    const int max_charsPerLine = 81;                 // Max chars per line
    const int max_lines = 35;                        // Max lines that the layout prints out
    pc.printf("\033[2J");                            // Clear the screen to get rid of reset message

    char buff[max_charsPerLine*max_lines];           // Giant string to store the printout
    char line[max_charsPerLine];                     // String buffer to work with one line at a time
    char temp[max_charsPerLine];                     // String buffer to sprintf into
    while(1) {

        int len = 0;
        len += sprintf(buff+len, "\033[0;0H");                      // Home the cursor
        padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE     // Generate a line full of -'s
        padCenter(line, max_charsPerLine-2, " Penn Electric Racing - REV0 System Management Controller Serial Dashboard ", '-'); ADD_LINE
        padCenter(line, max_charsPerLine-2, "-", '-'); ADD_LINE     // Generate a line full of -'s

        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
        padCenter(line, max_charsPerLine-2, " GLV Battery ", '*'); ADD_LINE
        sprintf(temp, "Current: %4.3fA Capacity: %4.3fAh", data.glvCurrent, data.glvCapacity); ADD_SPRINTF_LINE
        sprintf(temp, "Amphours: %4.3fAh SOC: %5.1f%% Overcurrent: %s", data.glvAmphours, data.glvSOC*100.0, BOOL(data.glvOverCurrent)); ADD_SPRINTF_LINE
        
        char DCDC = data.dcdcStatus;
        char dcdcModesStr[5][12] = {"INVALID","POWER-UP","POWER-DOWN","ON","OFF"};
        int dcdcMode = 0;
        if (DCDC & PowerUp)        dcdcMode = 1;
        else if (DCDC & PowerDown) dcdcMode = 2;
        else if (DCDC & SetOn)     dcdcMode = 3;
        else if (!(DCDC & SetOn))  dcdcMode = 4;
        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
        padCenter(line, max_charsPerLine-2, " DC-DC Converter ", '*'); ADD_LINE
        sprintf(temp, "Current: %5.3fA Overcurrent: %s SensorFault: %s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault)); ADD_SPRINTF_LINE
        sprintf(temp, "Active: %s Mode: %s AIRS: %s StatusByte: 0x%x", (DCDC & ConvOn)?"YES":"NO", dcdcModesStr[dcdcMode], CANdata.airsClosed?"CLOSED":"OPEN", DCDC); ADD_SPRINTF_LINE
        sprintf(temp, "StartFault: %s StopFault: %s CritErrors: %s", BOOL(DCDC & FailStart), BOOL(DCDC & FailStop), BOOL(data.dcdcError)); ADD_SPRINTF_LINE

        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
        padCenter(line, max_charsPerLine-2, " PWM Channels ", '*'); ADD_LINE
        sprintf(temp, "Actual:   FAN1: %5.1f%% FAN2: %5.1f%% PUMP1: %5.1f%% PUMP2: %5.1f%%", data.dcdcFan1Duty*100.0, data.dcdcFan2Duty*100.0, data.dcdcPump1Duty*100.0, data.dcdcPump2Duty*100.0); ADD_SPRINTF_LINE
        sprintf(temp, "Requestd: FAN1: %5.1f%% FAN2: %5.1f%% PUMP1: %5.1f%% PUMP2: %5.1f%%", CANdata.dcdcFan1Duty*100.0, CANdata.dcdcFan2Duty*100.0, CANdata.dcdcPump1Duty*100.0, CANdata.dcdcPump2Duty*100.0); ADD_SPRINTF_LINE

        const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDFLT","INVALID"};
        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
        padCenter(line, max_charsPerLine-2, " IMD ", '*'); ADD_LINE
        sprintf(temp, "Status: %s Resistance: %7.0fkohm CritError: %s",IMDstr[data.imdStatus], data.imdResistance/1e3, BOOL(data.imdError)); ADD_SPRINTF_LINE
        
        char AMSerr = data.AMSlatchError;
        char IMDerr = data.IMDlatchError;
        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
        padCenter(line, max_charsPerLine-2, " Latch Circuits ", '*'); ADD_LINE
        sprintf(temp, "AMS: OK: %s Latch: %s SoftFault: %s HardFault: %s", (AMSerr & 1)?"LOW":"HIGH", (AMSerr & 2)?"OPEN":"OK", BOOL(AMSerr & 4), BOOL(AMSerr & 8)); ADD_SPRINTF_LINE
        sprintf(temp, "IMD: OK: %s Latch: %s SoftFault: %s HardFault: %s", (IMDerr & 1)?"LOW":"HIGH", (IMDerr & 2)?"OPEN":"OK", BOOL(IMDerr & 4), BOOL(IMDerr & 8)); ADD_SPRINTF_LINE

        char switches = data.switchState;
        const char switchNames[12][26] = {"FUSE","AMS LATCH","IMD LATCH","PCM RELAY","BRAKE PLAUSIBILITY RELAY","LEFT E-STOP","INERTIA SWITCH","BRAKE OVER-TRAVEL SWITCH","COCKPIT E-STOP","RIGHT E-STOP","HVD","TSMS"};
        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line
        padCenter(line, max_charsPerLine-2, " Shutdown Switches ", '*'); ADD_LINE
        if (switches == 0) sprintf(temp, "All switches are CLOSED.");
        else sprintf(temp, "%s is OPEN.", switchNames[switches-1]);
        ADD_SPRINTF_LINE
        
        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE   // Generate blank line
        padCenter(line, max_charsPerLine-2, " Telemetry ", '*'); ADD_LINE
        sprintf(temp, "Channel 1: MessagesIn: %d MessagesOut: %d", xbeeRelay.counterX1in, xbeeRelay.counterX1out); ADD_SPRINTF_LINE
        sprintf(temp, "Channel 2: MessagesIn: %d MessagesOut: %d", xbeeRelay.counterX2in, xbeeRelay.counterX2out); ADD_SPRINTF_LINE

        padCenter(line, max_charsPerLine-2, " ", ' '); ADD_LINE     // Generate blank line 
        padCenter(line, max_charsPerLine-2, " Miscellaneous ", '*'); ADD_LINE
        sprintf(temp, "Temp: %5.1fC OverTemp: %s canFault: %s WatchdogReset: %s ErrorFrame: 0x%x", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame); ADD_SPRINTF_LINE

        // Write it all at once to output tx buffer
        for (int i = 0; i < strlen(buff); i++) {
            pc.putc(buff[i]);   
        }
        // Erase screen every 5sec to remove glitches
        static int count=0;
        if (count%50==0) {
            pc.printf("\033[2J");        // Clear the screen
        }
        count++;
        Thread::wait(100);
    }
}

template <typename T>
void sendCAN(int ID, T dat) {
    CANMessage msg;
    msg.id = ID;
    msg.len = sizeof(T);
    memcpy(&msg.data[0], (void*)&dat, sizeof(T));
    if (!can.txWrite(msg)) data.canFault = true;
    xbeeRelay.send(msg);
}

void outDiagnostics::thread_canOut(void const *args) {

    while(1) {
        CANMessage msg;

        // Sys Mgmt Error Frame
        sendCAN(SYS_ERROR_ID, data.errorFrame);
        
        // Xbee1 Counter
        msg.id = SYS_XBEE1_ID;
        msg.len = 2*sizeof(int);
        memcpy(&msg.data[0], (void*)&xbeeRelay.counterX1in, sizeof(int));
        memcpy(&msg.data[4], (void*)&xbeeRelay.counterX1out, sizeof(int));
        if (!can.txWrite(msg)) data.canFault = true;
        xbeeRelay.send(msg);

        // Xbee2 Counter
        msg.id = SYS_XBEE2_ID;
        msg.len = 2*sizeof(int);
        memcpy(&msg.data[0], (void*)&xbeeRelay.counterX2in, sizeof(int));
        memcpy(&msg.data[4], (void*)&xbeeRelay.counterX2out, sizeof(int));
        if (!can.txWrite(msg)) data.canFault = true;
        xbeeRelay.send(msg);
        
        // Internal temperature
        sendCAN(SYS_TEMP_ID, data.internalTemp);

        // GLV Battery
        sendCAN(SYS_GLV_CURRENT_ID, data.glvCurrent);
        sendCAN(SYS_GLV_CAPACITY_ID, data.glvCapacity);
        sendCAN(SYS_GLV_AH_ID, data.glvAmphours);
        sendCAN(SYS_GLV_SOC_ID, data.glvSOC);

        // DC-DC Converter
        sendCAN(SYS_DCDC_CURRENT_ID, data.dcdcCurrent);
        sendCAN(SYS_DCDC_STATUS_ID, data.dcdcStatus);

        // PWM Channels        
        msg.id = SYS_PWM_FAN_ID;
        msg.len = 2*sizeof(float);
        memcpy(&msg.data[0], (void*)&data.dcdcFan1Duty, sizeof(float));
        memcpy(&msg.data[4], (void*)&data.dcdcFan2Duty, sizeof(float));
        if (!can.txWrite(msg)) data.canFault = true;
        xbeeRelay.send(msg);

        msg.id = SYS_PWM_PUMP_ID;
        msg.len = 2*sizeof(float);
        memcpy(&msg.data[0], (void*)&data.dcdcPump1Duty, sizeof(float));
        memcpy(&msg.data[4], (void*)&data.dcdcPump2Duty, sizeof(float));
        if (!can.txWrite(msg)) data.canFault = true;
        xbeeRelay.send(msg);
        
        // IMD
        sendCAN(SYS_IMD_STATUS_ID, data.imdStatus);
        sendCAN(SYS_IMD_RESIST_ID, data.imdResistance);

        // Latches
        sendCAN(SYS_IMD_LATCH_ID, data.IMDlatchError);
        sendCAN(SYS_AMS_LATCH_ID, data.AMSlatchError);

        // Shutdown Switches
        sendCAN(SYS_SWITCHES_ID, data.switchState);

        Thread::wait(CAN_LOOP*1000);
    }   
}