System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
outDiagnostics/outDiagnostics.cpp
- Committer:
- pspatel321
- Date:
- 2015-02-11
- Revision:
- 39:ddf38df9699e
- Parent:
- 38:8efacce315ae
File content as of revision 39:ddf38df9699e:
#include "outDiagnostics.h" #include "outMacros.h" Timer serialLoop; Timer CANloop; int serialTime_ms = 0; int CANtime_ms = 0; const int max_charsPerLine = 80; // Max chars per line of printed information // Use the txEmpty interrupt from MODSERIAL to pace the thread so it always runs as fast as possible osThreadId serialID=0; void empty(MODSERIAL_IRQ_INFO *q) { osSignalSet(serialID, 1); } // Output a string to the MODSERIAL tx buffer, wait when buffer full void AddtoBuffer(char *str, bool newline=true) { const int waitT = TX_SIZE * CHAR_TIME*1000; // Max wait time to empty the tx buffer = max time to send out all chars int len = strlen(str); int times = newline ? (len + 2) : (len); // If newline requested, add 2 chars for "\r\n" for (int i = 0; i < times; i++) { if (!pc.writeable()) { // Keep writing till it fills osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<3); // Check-in with watchdog thread Thread::signal_wait(1, waitT); // Wait for empty signal from MODSERIAL tx empty interrupt, timeout in waitT ms } if (i < len) pc.putc(str[i]); // Print the string else if (i == len) pc.putc('\r'); // Add carriage return else if (i > len) pc.putc('\n'); // Add newline } } // Print to internal string buffer, pad to maxLen chars and center it with char pad, str must be null terminated! void padCenter(int LineLen, char *str, char pad) { static char line[max_charsPerLine+5]; // String buffer to work with one line at a time int len = strlen(str); // Length of input string int padL = (LineLen-len)/2; // How many pad chars needed on left side? for (int i=0; i<padL; i++) line[i] = pad; // Fill in the left padding chars strcpy(line+padL, str); // Copy to line string for (int i = padL+len; i<LineLen; i++) line[i] = pad; // Fill remaining with padding chars line[LineLen-1] = '\0'; // Add null terminator AddtoBuffer(line); } // Generates the serial dashboard, uses MODSERIAL, self-paced (thread yields when buffer is full, resumes when empty) void outDiagnostics::thread_serialOut(void const *args) { serialID = Thread::gettid(); // Record thread ID so empty() can signal this thread char temp[max_charsPerLine+5]; // String buffer to sprintf into, max 1 line pc.attach(&empty, MODSERIAL::TxEmpty); // Attach the tx empty interrupt which paces this thread pc.printf("\033[2J"); // Clear the screen to get rid of reset message // Use these bools to track changes in display mode between iterations bool lastModeExtended = param->extendedSerial; bool inExtendedMode = param->extendedSerial; // For determining where the data displayed is coming from bool freeze = false; // Not a freeze frame bool notLiveProfile = false; // Live data const char barSpace[4] = { ' ', 179, ' ', 0 }; // Commonly used string with char 179 OperatingInfo* dashOp = op; Profile* dashParam = param; serialLoop.reset(); serialLoop.start(); // Start the counter for tracking serial loop time while(1) { serialTime_ms = serialLoop.read_ms(); // Update loop timer, reset for next loop serialLoop.reset(); // Update display mode, change detection used at end of while(1) loop lastModeExtended = inExtendedMode; inExtendedMode = param->extendedSerial; // Determine whether to display freeze frame, change pointers accordingly if (tempData.freeze != NULL) { freeze = true; // Indicate showing freeze dashOp = &(tempData.freeze->op.op); // Point to freeze dashParam = &(tempData.freeze->param.param); // Point to freeze // Determine whether to display a non-live profile, change pointers accordingly } else if (tempData.viewProfile != NULL && tempData.viewProfileNum != -2) { dashParam = tempData.viewProfile; // Point to other profile notLiveProfile = true; // Indicate notLive // Show live data only } else { freeze = false; // Not freeze notLiveProfile = false; // Live profile dashOp = op; // Point to live RAM data dashParam = param; // Point to live RAM data } sprintf(temp, "\033[0;0H\033[0;0H"); AddtoBuffer(temp, false); // Move to 0,0, do not append newline DIVIDER_LINE TITLE(" Penn Electric Racing - REV0 System Management Controller Dashboard ") DIVIDER_LINE int tempLength=0; tempLength += sprintf(temp, "Command Input:%c %s%c", tempData.parseGoodChar, tempData.inputStr, 176); // Command input: print header, reply, input string, and cursor marker for (int i = 0; i < max_charsPerLine - tempLength - 1; i++) { // Fill in the rest of the line with blanks tempLength += sprintf(temp+tempLength, " "); // Append spaces } AddtoBuffer(temp); // Add this to the chunk const char profile[NUM_STORED_PROFILES+2][8] = {"Freeze", "Default", "1", "2", "3"}; if (inExtendedMode) { // Parameters Section 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)?") ":""); TITLE(temp) 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); ADD_SPRINTF_LINE 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); ADD_SPRINTF_LINE 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); ADD_SPRINTF_LINE snprintf(temp, max_charsPerLine, "CANtxSize: %4d %sCANrxSize: %4d %sSerialBaud: %6d%sSerialTx: %5d", dashParam->CANtxSize,barSpace, dashParam->CANrxSize,barSpace, dashParam->SerialBaud,barSpace, dashParam->SerialTxSize); ADD_SPRINTF_LINE BLANK_LINE } snprintf(temp, max_charsPerLine, " Operating Info %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) // Operating mode const char modeStr[3][8] = {"FAULT", "OKAY", "INVALID"}; tempLength = 0; tempLength += sprintf(temp+tempLength, "Sloop: %3dms CANloop: %3dms Time: %s", serialTime_ms, CANtime_ms, ctime(&dashOp->SysTime)); tempLength--; char modeN = dashOp->mode; if (modeN == FAULT) modeN=0; else if (modeN == OKAY) modeN=1; else modeN=2; tempLength += sprintf(temp+tempLength, " Uptime: %5ds", dashOp->SysTime - dashOp->startTime); ADD_SPRINTF_LINE tempLength = snprintf(temp, max_charsPerLine, "Profile: %7s%10s Mode: %7s%6s Faults: ", profile[dashOp->profileIndex+1], dashOp->profileModded?", MODIFIED":"", modeStr[modeN], dashOp->faultCode?"+ERROR":""); // Fault codes const char topErrStr[12][20] = {"WATCHDOG", "BROWNOUT", "CAN_FAULT", "INT_OVER_TEMP", "IMD_LATCH", "AMS_LATCH", "IMD_FAULT", "DCDC_FAULT", "GLVBAT_FAULT", "FREEZE_FRAME"}; int numFaults = 0; for (int i = 0; i < sizeof(dashOp->faultCode)*8; i++) { if (dashOp->faultCode & (1<<i)) numFaults++; } if (numFaults == 0) tempLength+=sprintf(temp+tempLength, "No Faults"); // Start new appending chain string, faults not present else tempLength+=sprintf(temp+tempLength, "(%d 0x%04x)", numFaults, dashOp->faultCode); // Start new appending chain string, faults present ADD_SPRINTF_LINE tempLength = 0; temp[0] = 0; // Print max number of strings that will fit per line, then dump line and continue till finished all error flags int num = 0; for (int i = 0; i < 29; i++) { if (dashOp->faultCode & (1<<i)) { // Fault found // Room for fault string? if (max_charsPerLine-tempLength > strlen(topErrStr[i])+2) { // Yes, append tempLength += sprintf(temp+tempLength, "%s ", topErrStr[i]); num++; } else { // No, Dump then start new line ADD_SPRINTF_LINE tempLength = 0; tempLength += sprintf(temp+tempLength, "%s ", topErrStr[i]); num++; } } if (num >= numFaults || numFaults == 0) { // Done printing all faults tempLength = 0; num = 0; if (numFaults != 0) { ADD_SPRINTF_LINE } break; } } BLANK_LINE 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); ADD_SPRINTF_LINE BLANK_LINE snprintf(temp, max_charsPerLine, " GLV Battery %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) 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); ADD_SPRINTF_LINE // GLV Fault codes const char glvBatErrStr[12][20] = {"OVER_CHARGE_I", "OVER_DISCHARGE_I", "CAP_INIT", "SOC_INIT" }; numFaults = 0; for (int i = 0; i < sizeof(dashOp->glvBat.error)*8; i++) { if (dashOp->glvBat.error & (1<<i)) numFaults++; } if (numFaults == 0) tempLength+=sprintf(temp+tempLength, "No Faults"); // Start new appending chain string, faults not present else tempLength+=sprintf(temp+tempLength, "(%d 0x%04x)", numFaults, dashOp->glvBat.error); // Start new appending chain string, faults present ADD_SPRINTF_LINE tempLength = 0; temp[0] = 0; // Print max number of strings that will fit per line, then dump line and continue till finished all error flags num = 0; for (int i = 0; i < 29; i++) { if (dashOp->glvBat.error & (1<<i)) { // Fault found // Room for fault string? if (max_charsPerLine-tempLength > strlen(glvBatErrStr[i])+2) { // Yes, append tempLength += sprintf(temp+tempLength, "%s ", glvBatErrStr[i]); num++; } else { // No, Dump then start new line ADD_SPRINTF_LINE tempLength = 0; tempLength += sprintf(temp+tempLength, "%s ", glvBatErrStr[i]); num++; } } if (num >= numFaults || numFaults == 0) { // Done printing all faults tempLength = 0; num = 0; if (numFaults != 0) { ADD_SPRINTF_LINE } break; } } BLANK_LINE snprintf(temp, max_charsPerLine, " DC-DC Converter %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) char DCDC = dashOp->dcdc.status; const char dcdcModesStr[5][12] = {"INVALID","POWER-UP","POWER-DOWN","SET-ON","SET-OFF"}; int dcdcMode = 0; if (DCDC & POWER_UP) dcdcMode = 1; else if (DCDC & POWER_DOWN) dcdcMode = 2; else if (DCDC & SET_ON) dcdcMode = 3; else if (!(DCDC & SET_ON)) dcdcMode = 4; sprintf(temp, "Active: %3s %s Mode: %10s %s Status: 0x%02x", (DCDC & CONV_ON)?"YES":"NO", barSpace, dcdcModesStr[dcdcMode], barSpace, DCDC); ADD_SPRINTF_LINE 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"); ADD_SPRINTF_LINE BLANK_LINE snprintf(temp, max_charsPerLine, " DC-DC PWM Channels %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) 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); ADD_SPRINTF_LINE 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); ADD_SPRINTF_LINE BLANK_LINE snprintf(temp, max_charsPerLine, " IMD %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) char imdStatN=6; if (dashOp->imd.status & OFF) imdStatN=0; if (dashOp->imd.status & NORMAL) imdStatN=1; if (dashOp->imd.status & UNDERVOLT) imdStatN=2; if (dashOp->imd.status & SPEEDSTART) imdStatN=3; if (dashOp->imd.status & ERROR) imdStatN=4; if (dashOp->imd.status & GROUNDERR) imdStatN=5; const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDERR","INVALID"}; sprintf(temp, "Status: %10s Resistance: %7.0fKohm Error: %3s", IMDstr[imdStatN], dashOp->imd.resistance/1.0e3, dashOp->imd.error?"ERR":"OK"); ADD_SPRINTF_LINE BLANK_LINE snprintf(temp, max_charsPerLine, " Latch Monitors %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) char AMSerr = dashOp->latch.ams; char IMDerr = dashOp->latch.imd; 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"); ADD_SPRINTF_LINE 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"); ADD_SPRINTF_LINE BLANK_LINE snprintf(temp, max_charsPerLine, " Shutdown Switches %s", freeze?"(Viewing Freeze of Last Fault) ":""); TITLE(temp) char switches = dashOp->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"}; if (switches == 0) sprintf(temp, "All switches are CLOSED."); else sprintf(temp, "%s is OPEN.", switchNames[switches-1]); ADD_SPRINTF_LINE // Erase screen every few counts to remove glitches static int count = 0; if (count % 50 == 0 || lastModeExtended != inExtendedMode) { sprintf(temp, "\033[2J"); AddtoBuffer(temp, false); // Clear the screen } count++; } } void outDiagnostics::thread_canOut(void const *args) { bool lastCANnoAck = param->CANnoAck; // Get initial noAck mode setting bool thisCANnoAck = param->CANnoAck; if (param->CANnoAck) { // Turn on noack mode can.mode(NoAck); } else { // Setup normal mode can.mode(Normal); } can.mode(FIFO); CANloop.reset(); CANloop.start(); while(1) { CANtime_ms = CANloop.read_ms(); CANloop.reset(); // Update last and this variables to check for changes in noAck mode lastCANnoAck = thisCANnoAck; thisCANnoAck = param->CANnoAck; if (thisCANnoAck && !lastCANnoAck) { // NoAck mode turn on can.mode(NoAck); can.mode(FIFO); can.txFlush(); // Must flush buffer when switching modes, or else buffer gets stuck } if (!thisCANnoAck && lastCANnoAck) { // NoAck mode turn off can.mode(Normal); can.mode(FIFO); can.txFlush(); // Must flush buffer when switching modes, or else buffer gets stuck } // OPERATING DIAGNOSTICS // Error Frame CAN_SINGLE(faultCode, FAULTCODE_TX_ID) // Mode CAN_SINGLE(mode, MODE_TX_ID) // Flags CAN_SINGLE(signals, SIGNALS_TX_ID) // Profile char byte=0; byte = (op->profileIndex != -1)? 1 << op->profileIndex : 1<<6; 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) SEND_CAN_SINGLE(byte, PROFILE_TX_ID); // Time CAN_PAIR(SysTime, startTime, TIME_TX_ID) // Internal temperature CAN_SINGLE(internalTemp, TEMP_TX_ID) // GLV Battery CAN_SINGLE(glvBat.current, GLV_CURRENT_TX_ID) CAN_SINGLE(glvBat.capacity, GLV_CAPACITY_TX_ID) CAN_SINGLE(glvBat.Ah, GLV_AH_TX_ID) CAN_SINGLE(glvBat.SOC, GLV_SOC_TX_ID) CAN_SINGLE(glvBat.error, GLV_ERROR_TX_ID) // DC-DC Converter CAN_SINGLE(dcdc.current, DCDC_CURRENT_TX_ID) CAN_SINGLE(dcdc.status, DCDC_STATUS_TX_ID) // PWM Channels CAN_PAIR(dcdc.actual.fan1, dcdc.actual.fan2, PWM_FAN_TX_ID) CAN_PAIR(dcdc.actual.pump1, dcdc.actual.pump2, PWM_PUMP_TX_ID) // IMD CAN_SINGLE(imd.status, IMD_STATUS_TX_ID) CAN_SINGLE(imd.resistance, IMD_RESIST_TX_ID) // Latches CAN_SINGLE(latch.imd, IMD_LATCH_TX_ID) CAN_SINGLE(latch.ams, AMS_LATCH_TX_ID) // Shutdown Switches uint16_t tmp=0; if (op->switchState != 0) tmp |= 1 << (op->switchState-1); SEND_CAN_SINGLE(tmp, SWITCHES_TX_ID); osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<4); // Signal watchdog thread Thread::wait(CAN_LOOP*1000); } }