System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
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 }
Generated on Fri Jul 15 2022 06:07:18 by
1.7.2
