System Management code

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers outDiagnostics.cpp Source File

outDiagnostics.cpp

00001 #include "outDiagnostics.h"
00002 #include "outMacros.h"
00003 
00004 Timer serialLoop;
00005 Timer CANloop;
00006 int serialTime_ms = 0;
00007 int CANtime_ms = 0;
00008 const int max_charsPerLine = 80;                 // Max chars per line of printed information
00009 
00010 // Use the txEmpty interrupt from MODSERIAL to pace the thread so it always runs as fast as possible
00011 osThreadId serialID=0;
00012 void empty(MODSERIAL_IRQ_INFO *q)
00013 {
00014     osSignalSet(serialID, 1);
00015 }
00016 // Output a string to the MODSERIAL tx buffer, wait when buffer full
00017 void AddtoBuffer(char *str, bool newline=true)
00018 {
00019     const int waitT = TX_SIZE * CHAR_TIME*1000;             // Max wait time to empty the tx buffer = max time to send out all chars
00020     int len = strlen(str);
00021     int times = newline ? (len + 2) : (len);                // If newline requested, add 2 chars for "\r\n"
00022     for (int i = 0; i < times; i++) {
00023         if (!pc.writeable()) {                              // Keep writing till it fills
00024             osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<3);  // Check-in with watchdog thread
00025             Thread::signal_wait(1, waitT);                  // Wait for empty signal from MODSERIAL tx empty interrupt, timeout in waitT ms
00026         }
00027         if (i < len) pc.putc(str[i]);                       // Print the string
00028         else if (i == len) pc.putc('\r');                   // Add carriage return
00029         else if (i > len) pc.putc('\n');                    // Add newline
00030     }
00031 }
00032 
00033 // Print to internal string buffer, pad to maxLen chars and center it with char pad, str must be null terminated!
00034 void padCenter(int LineLen, char *str, char pad)
00035 {
00036     static char line[max_charsPerLine+5];                   // String buffer to work with one line at a time
00037     int len = strlen(str);                                  // Length of input string
00038     int padL = (LineLen-len)/2;                             // How many pad chars needed on left side?
00039     for (int i=0; i<padL; i++) line[i] = pad;               // Fill in the left padding chars
00040     strcpy(line+padL, str);                                 // Copy to line string
00041     for (int i = padL+len; i<LineLen; i++) line[i] = pad;   // Fill remaining with padding chars
00042     line[LineLen-1] = '\0';                                 // Add null terminator
00043 
00044     AddtoBuffer(line);
00045 }
00046 
00047 // Generates the serial dashboard, uses MODSERIAL, self-paced (thread yields when buffer is full, resumes when empty)
00048 void outDiagnostics::thread_serialOut(void const *args)
00049 {
00050     serialID = Thread::gettid();                    // Record thread ID so empty() can signal this thread
00051     char temp[max_charsPerLine+5];                  // String buffer to sprintf into, max 1 line
00052     pc.attach(&empty, MODSERIAL::TxEmpty);          // Attach the tx empty interrupt which paces this thread
00053     pc.printf("\033[2J");                           // Clear the screen to get rid of reset message
00054 
00055     // Use these bools to track changes in display mode between iterations
00056     bool lastModeExtended = param->extendedSerial;
00057     bool inExtendedMode = param->extendedSerial;
00058 
00059     // For determining where the data displayed is coming from
00060     bool freeze = false;                            // Not a freeze frame
00061     bool notLiveProfile = false;                    // Live data
00062 
00063     const char barSpace[4] = { ' ', 179, ' ', 0 };  // Commonly used string with char 179
00064     OperatingInfo* dashOp    = op;
00065     Profile*       dashParam = param;
00066 
00067     serialLoop.reset();
00068     serialLoop.start();                             // Start the counter for tracking serial loop time
00069 
00070     while(1) {
00071         serialTime_ms = serialLoop.read_ms();       // Update loop timer, reset for next loop
00072         serialLoop.reset();
00073 
00074         // Update display mode, change detection used at end of while(1) loop
00075         lastModeExtended = inExtendedMode;
00076         inExtendedMode = param->extendedSerial;
00077 
00078         // Determine whether to display freeze frame, change pointers accordingly
00079         if (tempData.freeze != NULL) {
00080             freeze = true;                          // Indicate showing freeze
00081             dashOp = &(tempData.freeze->op.op);             // Point to freeze
00082             dashParam = &(tempData.freeze->param.param);    // Point to freeze
00083 
00084             // Determine whether to display a non-live profile, change pointers accordingly
00085         } else if (tempData.viewProfile != NULL && tempData.viewProfileNum != -2) {
00086             dashParam = tempData.viewProfile;       // Point to other profile
00087             notLiveProfile = true;                  // Indicate notLive
00088 
00089             // Show live data only
00090         } else {
00091             freeze = false;             // Not freeze
00092             notLiveProfile = false;     // Live profile
00093             dashOp = op;                // Point to live RAM data
00094             dashParam = param;          // Point to live RAM data
00095         }
00096 
00097         sprintf(temp, "\033[0;0H\033[0;0H");
00098         AddtoBuffer(temp, false);                   // Move to 0,0, do not append newline
00099 
00100         DIVIDER_LINE
00101         TITLE(" Penn Electric Racing - REV0 System Management Controller Dashboard ")
00102         DIVIDER_LINE
00103 
00104         int tempLength=0;
00105         tempLength += sprintf(temp, "Command Input:%c %s%c", tempData.parseGoodChar, tempData.inputStr, 176);  // Command input: print header, reply, input string, and cursor marker
00106         for (int i = 0; i < max_charsPerLine - tempLength - 1; i++) {      // Fill in the rest of the line with blanks
00107             tempLength += sprintf(temp+tempLength, " ");                    // Append spaces
00108         }
00109         AddtoBuffer(temp);        // Add this to the chunk
00110 
00111         const char profile[NUM_STORED_PROFILES+2][8] = {"Freeze", "Default", "1", "2", "3"};
00112         if (inExtendedMode) {
00113 
00114             // Parameters Section
00115             snprintf(temp, max_charsPerLine, " Configuration Parameters %s%s%s%s", freeze?"(Viewing Freeze of Last Fault) ":"", (notLiveProfile && !freeze)?" (Viewing Profile ":"", (notLiveProfile && !freeze)?profile[tempData.viewProfileNum+1]:"", (notLiveProfile && !freeze)?") ":"");
00116             TITLE(temp)
00117             snprintf(temp, max_charsPerLine, "GLVchar:    %5.2fA%sGLVdisch: %5.2fA%sGLVnomCap: %5.2fAh%sGLVtaps:     %3d", dashParam->chargeCurrent,barSpace, dashParam->dischargeCurrent,barSpace, dashParam->nominalCapacity,barSpace, dashParam->glvBat_taps);
00118             ADD_SPRINTF_LINE
00119             snprintf(temp, max_charsPerLine, "dcdcThres:  %5.2fA%sdcdcOver: %5.2fA%sdcdcStart: %5.2fs %sdcdcStop: %5.2fs", dashParam->dcdcThreshold,barSpace, dashParam->dcdcOverCurrent,barSpace, dashParam->dcdcStartDelay,barSpace, dashParam->dcdcStopDelay);
00120             ADD_SPRINTF_LINE
00121             snprintf(temp, max_charsPerLine, "dcdcTaps:     %3d %simdStart: %5.1fs%samsStart:  %5.1fs %sIntOverT: %5.1fC",  dashParam->dcdc_taps,barSpace, dashParam->imdStartDelay,barSpace, dashParam->amsStartDelay,barSpace, dashParam->internalOverTemp);
00122             ADD_SPRINTF_LINE
00123             snprintf(temp, max_charsPerLine, "CANtxSize:   %4d %sCANrxSize: %4d %sSerialBaud: %6d%sSerialTx:  %5d",  dashParam->CANtxSize,barSpace, dashParam->CANrxSize,barSpace, dashParam->SerialBaud,barSpace, dashParam->SerialTxSize);
00124             ADD_SPRINTF_LINE
00125             BLANK_LINE
00126         }
00127         snprintf(temp, max_charsPerLine, " Operating Info %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00128         TITLE(temp)
00129 
00130         // Operating mode
00131         const char modeStr[3][8] = {"FAULT", "OKAY", "INVALID"};
00132         tempLength = 0;
00133         tempLength += sprintf(temp+tempLength, "Sloop: %3dms CANloop: %3dms Time: %s", serialTime_ms, CANtime_ms, ctime(&dashOp->SysTime));
00134         tempLength--;
00135         char modeN = dashOp->mode;
00136         if (modeN == FAULT) modeN=0;
00137         else if (modeN == OKAY) modeN=1;
00138         else modeN=2;
00139         tempLength += sprintf(temp+tempLength, " Uptime: %5ds", dashOp->SysTime - dashOp->startTime);
00140         ADD_SPRINTF_LINE
00141         tempLength = snprintf(temp, max_charsPerLine, "Profile: %7s%10s Mode: %7s%6s     Faults: ", profile[dashOp->profileIndex+1], dashOp->profileModded?", MODIFIED":"", modeStr[modeN], dashOp->faultCode?"+ERROR":"");
00142 
00143         // Fault codes
00144         const char topErrStr[12][20] = {"WATCHDOG", "BROWNOUT", "CAN_FAULT", "INT_OVER_TEMP", "IMD_LATCH", "AMS_LATCH", "IMD_FAULT", "DCDC_FAULT", "GLVBAT_FAULT", "FREEZE_FRAME"};
00145         int numFaults = 0;
00146         for (int i = 0; i < sizeof(dashOp->faultCode)*8; i++) {
00147             if (dashOp->faultCode & (1<<i)) numFaults++;
00148         }
00149         if (numFaults == 0) tempLength+=sprintf(temp+tempLength, "No Faults");                          // Start new appending chain string, faults not present
00150         else tempLength+=sprintf(temp+tempLength, "(%d 0x%04x)", numFaults, dashOp->faultCode);  // Start new appending chain string, faults present
00151         ADD_SPRINTF_LINE
00152         tempLength = 0;
00153         temp[0] = 0;
00154 
00155         // Print max number of strings that will fit per line, then dump line and continue till finished all error flags
00156         int num = 0;
00157         for (int i = 0; i < 29; i++) {
00158             if (dashOp->faultCode & (1<<i)) {        // Fault found
00159                 // Room for fault string?
00160                 if (max_charsPerLine-tempLength > strlen(topErrStr[i])+2) {
00161                     // Yes, append
00162                     tempLength += sprintf(temp+tempLength, "%s ", topErrStr[i]);
00163                     num++;
00164                 } else {
00165                     // No, Dump then start new line
00166                     ADD_SPRINTF_LINE
00167                     tempLength = 0;
00168                     tempLength += sprintf(temp+tempLength, "%s ", topErrStr[i]);
00169                     num++;
00170                 }
00171             }
00172             if (num >= numFaults || numFaults == 0) {
00173                 // Done printing all faults
00174                 tempLength = 0;
00175                 num = 0;
00176                 if (numFaults != 0) {
00177                     ADD_SPRINTF_LINE
00178                 }
00179                 break;
00180             }
00181         }
00182         BLANK_LINE
00183         snprintf(temp, max_charsPerLine, "ShtdwnCrct: %6s %s AIRs: %6s %s Charger: %4s %s IntTemp: %5.1f", (dashOp->signals & SHUTDOWN_CLOSED)?"CLOSED":"OPEN", barSpace, (dashOp->signals & AIRS_CLOSED)?"CLOSED":"OPEN", barSpace, (dashOp->signals & CHARGER_DET)?"DET":"NDET", barSpace, dashOp->internalTemp);
00184         ADD_SPRINTF_LINE
00185 
00186         BLANK_LINE
00187         snprintf(temp, max_charsPerLine, " GLV Battery %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00188         TITLE(temp)
00189         sprintf(temp, "Current: %4.3fA %s Cap: %4.3fAh %s Ah: %4.3fAh %s SOC: %5.3f", dashOp->glvBat.current, barSpace, dashOp->glvBat.capacity, barSpace, dashOp->glvBat.Ah, barSpace, dashOp->glvBat.SOC);
00190         ADD_SPRINTF_LINE
00191         // GLV Fault codes
00192         const char glvBatErrStr[12][20] = {"OVER_CHARGE_I", "OVER_DISCHARGE_I", "CAP_INIT", "SOC_INIT" };
00193         numFaults = 0;
00194         for (int i = 0; i < sizeof(dashOp->glvBat.error)*8; i++) {
00195             if (dashOp->glvBat.error & (1<<i)) numFaults++;
00196         }
00197         if (numFaults == 0) tempLength+=sprintf(temp+tempLength, "No Faults");                          // Start new appending chain string, faults not present
00198         else tempLength+=sprintf(temp+tempLength, "(%d 0x%04x)", numFaults, dashOp->glvBat.error);  // Start new appending chain string, faults present
00199         ADD_SPRINTF_LINE
00200         tempLength = 0;
00201         temp[0] = 0;
00202 
00203         // Print max number of strings that will fit per line, then dump line and continue till finished all error flags
00204         num = 0;
00205         for (int i = 0; i < 29; i++) {
00206             if (dashOp->glvBat.error & (1<<i)) {        // Fault found
00207                 // Room for fault string?
00208                 if (max_charsPerLine-tempLength > strlen(glvBatErrStr[i])+2) {
00209                     // Yes, append
00210                     tempLength += sprintf(temp+tempLength, "%s ", glvBatErrStr[i]);
00211                     num++;
00212                 } else {
00213                     // No, Dump then start new line
00214                     ADD_SPRINTF_LINE
00215                     tempLength = 0;
00216                     tempLength += sprintf(temp+tempLength, "%s ", glvBatErrStr[i]);
00217                     num++;
00218                 }
00219             }
00220             if (num >= numFaults || numFaults == 0) {
00221                 // Done printing all faults
00222                 tempLength = 0;
00223                 num = 0;
00224                 if (numFaults != 0) {
00225                     ADD_SPRINTF_LINE
00226                 }
00227                 break;
00228             }
00229         }
00230         
00231         BLANK_LINE
00232         snprintf(temp, max_charsPerLine, " DC-DC Converter %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00233         TITLE(temp)
00234         char DCDC = dashOp->dcdc.status;
00235         const char dcdcModesStr[5][12] = {"INVALID","POWER-UP","POWER-DOWN","SET-ON","SET-OFF"};
00236         int dcdcMode = 0;
00237         if (DCDC & POWER_UP)        dcdcMode = 1;
00238         else if (DCDC & POWER_DOWN) dcdcMode = 2;
00239         else if (DCDC & SET_ON)     dcdcMode = 3;
00240         else if (!(DCDC & SET_ON))  dcdcMode = 4;
00241         sprintf(temp, "Active:    %3s  %s Mode: %10s %s Status:     0x%02x", (DCDC & CONV_ON)?"YES":"NO", barSpace, dcdcModesStr[dcdcMode], barSpace, DCDC);
00242         ADD_SPRINTF_LINE
00243         sprintf(temp, "Current: %5.2fA %s Overcurrent: %3s %s SensorFault: %3s", dashOp->dcdc.current,barSpace, (DCDC & OVER_CURRENT)?"ERR":"OK",barSpace, (DCDC & SENSOR_FAULT)?"ERR":"OK");
00244         ADD_SPRINTF_LINE
00245 
00246         BLANK_LINE
00247         snprintf(temp, max_charsPerLine, " DC-DC PWM Channels %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00248         TITLE(temp)
00249         sprintf(temp, "Actual:      FAN1: %5.3f   FAN2: %5.3f %s PUMP1: %5.3f   PUMP2: %5.3f", dashOp->dcdc.actual.fan1, dashOp->dcdc.actual.fan2, barSpace, dashOp->dcdc.actual.pump1, dashOp->dcdc.actual.pump2);
00250         ADD_SPRINTF_LINE
00251         sprintf(temp, "Requested:   FAN1: %5.3f   FAN2: %5.3f %s PUMP1: %5.3f   PUMP2: %5.3f", dashOp->dcdc.request.fan1, dashOp->dcdc.request.fan2, barSpace, dashOp->dcdc.request.pump1, dashOp->dcdc.request.pump2);
00252         ADD_SPRINTF_LINE
00253 
00254         BLANK_LINE
00255         snprintf(temp, max_charsPerLine, " IMD %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00256         TITLE(temp)
00257         char imdStatN=6;
00258         if (dashOp->imd.status & OFF) imdStatN=0;
00259         if (dashOp->imd.status & NORMAL) imdStatN=1;
00260         if (dashOp->imd.status & UNDERVOLT) imdStatN=2;
00261         if (dashOp->imd.status & SPEEDSTART) imdStatN=3;
00262         if (dashOp->imd.status & ERROR) imdStatN=4;
00263         if (dashOp->imd.status & GROUNDERR) imdStatN=5;
00264         const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDERR","INVALID"};
00265         sprintf(temp, "Status: %10s   Resistance: %7.0fKohm   Error: %3s", IMDstr[imdStatN], dashOp->imd.resistance/1.0e3, dashOp->imd.error?"ERR":"OK");
00266         ADD_SPRINTF_LINE
00267 
00268         BLANK_LINE
00269         snprintf(temp, max_charsPerLine, " Latch Monitors %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00270         TITLE(temp)
00271         char AMSerr = dashOp->latch.ams;
00272         char IMDerr = dashOp->latch.imd;
00273         sprintf(temp, "AMS -    OK: %4s Latch: %3s   SoftFault: %3s   HardFault: %3s", (AMSerr & OK_FAULT)?"LOW":"HIGH", (AMSerr & LATCHED_HARD)?"ERR":"OK", (AMSerr & LATCHED_SOFT)?"ERR":"OK", (AMSerr & HARD_FAULT)?"ERR":"OK");
00274         ADD_SPRINTF_LINE
00275         sprintf(temp, "IMD -    OK: %4s Latch: %3s   SoftFault: %3s   HardFault: %3s", (IMDerr & OK_FAULT)?"LOW":"HIGH", (IMDerr & LATCHED_HARD)?"ERR":"OK", (IMDerr & LATCHED_SOFT)?"ERR":"OK", (IMDerr & HARD_FAULT)?"ERR":"OK");
00276         ADD_SPRINTF_LINE
00277 
00278         BLANK_LINE
00279         snprintf(temp, max_charsPerLine, " Shutdown Switches %s", freeze?"(Viewing Freeze of Last Fault) ":"");
00280         TITLE(temp)
00281         char switches = dashOp->switchState;
00282         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"};
00283         if (switches == 0) sprintf(temp, "All switches are CLOSED.");
00284         else sprintf(temp, "%s is OPEN.", switchNames[switches-1]);
00285         ADD_SPRINTF_LINE
00286 
00287         // Erase screen every few counts to remove glitches
00288         static int count = 0;
00289         if (count % 50 == 0 || lastModeExtended != inExtendedMode) {
00290             sprintf(temp, "\033[2J");
00291             AddtoBuffer(temp, false);     // Clear the screen
00292         }
00293         count++;
00294     }
00295 }
00296 
00297 void outDiagnostics::thread_canOut(void const *args)
00298 {
00299     bool lastCANnoAck = param->CANnoAck;        // Get initial noAck mode setting
00300     bool thisCANnoAck = param->CANnoAck;
00301 
00302     if (param->CANnoAck) {                      // Turn on noack mode
00303         can.mode(NoAck);
00304     } else {                                    // Setup normal mode
00305         can.mode(Normal);
00306     }
00307     can.mode(FIFO);
00308 
00309     CANloop.reset();
00310     CANloop.start();
00311 
00312     while(1) {
00313 
00314         CANtime_ms = CANloop.read_ms();
00315         CANloop.reset();
00316 
00317         // Update last and this variables to check for changes in noAck mode
00318         lastCANnoAck = thisCANnoAck;
00319         thisCANnoAck = param->CANnoAck;
00320         if (thisCANnoAck && !lastCANnoAck) {    // NoAck mode turn on
00321             can.mode(NoAck);
00322             can.mode(FIFO);
00323             can.txFlush();                      // Must flush buffer when switching modes, or else buffer gets stuck
00324         }
00325         if (!thisCANnoAck && lastCANnoAck) {    // NoAck mode turn off
00326             can.mode(Normal);
00327             can.mode(FIFO);
00328             can.txFlush();                      // Must flush buffer when switching modes, or else buffer gets stuck
00329         }
00330 
00331         // OPERATING DIAGNOSTICS
00332         // Error Frame
00333         CAN_SINGLE(faultCode,   FAULTCODE_TX_ID)
00334 
00335         // Mode
00336         CAN_SINGLE(mode,        MODE_TX_ID)
00337 
00338         // Flags
00339         CAN_SINGLE(signals,     SIGNALS_TX_ID)
00340 
00341         // Profile
00342         char byte=0;
00343         byte = (op->profileIndex != -1)? 1 << op->profileIndex : 1<<6;
00344         byte |= (op->profileModded) ? 1<<7 : 0;     // Mark the last bit of the byte if the profile was modified (OR'd with profile id from above)
00345         SEND_CAN_SINGLE(byte, PROFILE_TX_ID);
00346 
00347         // Time
00348         CAN_PAIR(SysTime,       startTime,      TIME_TX_ID)
00349 
00350         // Internal temperature
00351         CAN_SINGLE(internalTemp, TEMP_TX_ID)
00352 
00353         // GLV Battery
00354         CAN_SINGLE(glvBat.current,  GLV_CURRENT_TX_ID)
00355         CAN_SINGLE(glvBat.capacity, GLV_CAPACITY_TX_ID)
00356         CAN_SINGLE(glvBat.Ah,       GLV_AH_TX_ID)
00357         CAN_SINGLE(glvBat.SOC,      GLV_SOC_TX_ID)
00358         CAN_SINGLE(glvBat.error,    GLV_ERROR_TX_ID)
00359 
00360         // DC-DC Converter
00361         CAN_SINGLE(dcdc.current,    DCDC_CURRENT_TX_ID)
00362         CAN_SINGLE(dcdc.status,     DCDC_STATUS_TX_ID)
00363 
00364         // PWM Channels
00365         CAN_PAIR(dcdc.actual.fan1,  dcdc.actual.fan2,  PWM_FAN_TX_ID)
00366         CAN_PAIR(dcdc.actual.pump1, dcdc.actual.pump2, PWM_PUMP_TX_ID)
00367 
00368         // IMD
00369         CAN_SINGLE(imd.status,      IMD_STATUS_TX_ID)
00370         CAN_SINGLE(imd.resistance,  IMD_RESIST_TX_ID)
00371 
00372         // Latches
00373         CAN_SINGLE(latch.imd,       IMD_LATCH_TX_ID)
00374         CAN_SINGLE(latch.ams,       AMS_LATCH_TX_ID)
00375 
00376         // Shutdown Switches
00377         uint16_t tmp=0;
00378         if (op->switchState != 0) tmp |= 1 << (op->switchState-1);
00379         SEND_CAN_SINGLE(tmp,        SWITCHES_TX_ID);
00380 
00381         osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<4);      // Signal watchdog thread
00382         Thread::wait(CAN_LOOP*1000);
00383     }
00384 }