System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Diff: outDiagnostics/outDiagnostics.cpp
- Revision:
- 38:8efacce315ae
- Parent:
- 36:0afc0fc8f86b
- Child:
- 39:ddf38df9699e
--- a/outDiagnostics/outDiagnostics.cpp Thu Jan 22 07:59:48 2015 +0000 +++ b/outDiagnostics/outDiagnostics.cpp Sat Feb 07 08:54:51 2015 +0000 @@ -1,13 +1,18 @@ #include "outDiagnostics.h" +#include "outMacros.h" -osThreadId serialID = 0; // RTOS thread ID of thread_serialOut -const int max_charsPerLine = 80; // Max chars per line of printed information +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 -void empty(MODSERIAL_IRQ_INFO *q) { +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) { @@ -39,182 +44,347 @@ AddtoBuffer(line); } - -// Macros for working with the strings -#define ADD_SPRINTF_LINE padCenter(max_charsPerLine, temp, ' '); // Cetner the string, then add newlines, and add to chunk -#define DIVIDER_LINE padCenter(max_charsPerLine, "", 196); // Generate a line full of divider char 196, add to chunk -#define TITLE(string) padCenter(max_charsPerLine, string, 196); // Generate a title line (centered, surrounded by char 196), add to chunk -#define BLANK_LINE padCenter(max_charsPerLine, "", ' '); // Generate a line full of spaces (blank), add to chunk -#define BOOL(VAR) (VAR)?"ERR":"OK" - // 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 + 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 - pc.attach(&empty, MODSERIAL::TxEmpty); // Attach the tx empty interrupt which paces this thread + // Use these bools to track changes in display mode between iterations + bool lastModeExtended = param->extendedSerial; + bool inExtendedMode = param->extendedSerial; - tempData.parseGoodChar = ' '; - tempData.inputStr[0] = 0; - - Timer serialLoop; // Timer to track the serial loop time, since this thread paces itself - int serialTime_ms = 0; + // 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 - - //const char barSpace[4] = { ' ', 179, ' ', 0 }; // Commonly used string with char 179 + serialLoop.start(); // Start the counter for tracking serial loop time while(1) { - - serialTime_ms = serialLoop.read_ms(); // Update loop timer, reset for next loop + 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 - + 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 - - TITLE(" GLV Battery ") - BLANK_LINE - sprintf(temp, "Current: %4.3fA Capacity: %4.3fAh", data.glvCurrent, data.glvCapacity); + + 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 + snprintf(temp, max_charsPerLine, "XbeeBaud: %6d %sXbeeTxSize: %4d%sXbeeRxSize: %4d %s CANack: %5s", dashParam->XbeeBaud, barSpace, dashParam->XbeeTxSize,barSpace, dashParam->XbeeRxSize,barSpace, dashParam->CANnoAck?"NOACK":"ACK"); + 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 - sprintf(temp, "Amphours: %4.3fAh SOC: %5.3f Overcurrent: %s", data.glvAmphours, data.glvSOC, BOOL(data.glvOverCurrent)); + 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; - BLANK_LINE - TITLE(" DC-DC Converter ") + // 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 - 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; - sprintf(temp, "Active: %3s Mode: %10s AIRS: %6s StatusByte: 0x%02x", (DCDC & ConvOn)?"YES":"NO", dcdcModesStr[dcdcMode], CANdata.airsClosed?"CLOSED":"OPEN", DCDC); - ADD_SPRINTF_LINE - sprintf(temp, "Current: %5.2fA Overcurrent: %3s SensorFault: %3s", data.dcdcCurrent, BOOL(DCDC & OverCurrent), BOOL(DCDC & SensorFault)); - ADD_SPRINTF_LINE - sprintf(temp, "StartFault: %3s StopFault: %3s CritErrors: %3s", BOOL(DCDC & FailStart), BOOL(DCDC & FailStop), BOOL(data.dcdcError)); + 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 - TITLE(" PWM Channels ") + 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 - sprintf(temp, "Actual: FAN1: %5.3f FAN2: %5.3f PUMP1: %5.3f PUMP2: %5.3f", data.dcdcFan1Duty, data.dcdcFan2Duty, data.dcdcPump1Duty, data.dcdcPump2Duty); + 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, "Requestd: FAN1: %5.3f FAN2: %5.3f PUMP1: %5.3f PUMP2: %5.3f", CANdata.dcdcFan1Duty, CANdata.dcdcFan2Duty, CANdata.dcdcPump1Duty, CANdata.dcdcPump2Duty); + 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 - TITLE(" IMD ") - BLANK_LINE - const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDFLT","INVALID"}; - sprintf(temp, "Status: %10s Resistance: %7.0fkohm CritError: %3s",IMDstr[data.imdStatus], data.imdResistance/1e3, BOOL(data.imdError)); + 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 - TITLE(" Latch Circuit Monitors ") - BLANK_LINE - char AMSerr = data.AMSlatchError; - char IMDerr = data.IMDlatchError; - sprintf(temp, "AMS - OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (AMSerr & 1)?"LOW":"HIGH", BOOL(AMSerr & 2), BOOL(AMSerr & 4), BOOL(AMSerr & 8)); - ADD_SPRINTF_LINE - sprintf(temp, "IMD - OK: %4s Latch: %3s SoftFault: %3s HardFault: %3s", (IMDerr & 1)?"LOW":"HIGH", BOOL(IMDerr & 2), BOOL(IMDerr & 4), BOOL(IMDerr & 8)); + snprintf(temp, max_charsPerLine, " IMD %s", freeze?"(Viewing Freeze of Last Fault) ":""); + TITLE(temp) + const char IMDstr[7][12] = {"OFF","NORMAL","UNDERVOLT","SPEEDSTART","ERROR","GROUNDFLT","INVALID"}; + sprintf(temp, "Status: %10s Resistance: %7.0fKohm Error: %3s", IMDstr[dashOp->imd.status], dashOp->imd.resistance/1.0e3, dashOp->imd.error?"ERR":"OK"); ADD_SPRINTF_LINE BLANK_LINE - TITLE(" Shutdown Switches ") + 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 - char switches = data.switchState; + 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 BLANK_LINE - TITLE(" Telemetry ") - BLANK_LINE - sprintf(temp, "Channel 1 - MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX1in, xbeeRelay.counterX1out); + snprintf(temp, max_charsPerLine, " Telemetry %s", freeze?"(Viewing Freeze of Last Fault) ":""); + TITLE(temp) + sprintf(temp, "Channel 1 - MsgIn: %5d MsgOut: %5d %5.2f", dashOp->xbee1.msgIn, dashOp->xbee1.msgOut, dashOp->xbee1.rateOut); ADD_SPRINTF_LINE - sprintf(temp, "Channel 2 - MessagesIn: %5d MessagesOut: %5d", xbeeRelay.counterX2in, xbeeRelay.counterX2out); + sprintf(temp, "Channel 2 - MsgIn: %5d MsgOut: %5d %5.2f", dashOp->xbee2.msgIn, dashOp->xbee2.msgOut, dashOp->xbee2.rateOut); ADD_SPRINTF_LINE - BLANK_LINE - TITLE(" Miscellaneous ") - BLANK_LINE - sprintf(temp, "Temp: %5.1fC %3s canFault: %3s Watchdog: %3s ErrorCode: 0x%02x SerialTime: %3dms", data.internalTemp, BOOL(data.internalOverTemp), BOOL(data.canFault), BOOL(data.watchdogReset), data.errorFrame, serialTime_ms); - ADD_SPRINTF_LINE - - // Erase screen every 5sec to remove glitches - static int count=0; - if (count%50==0) { - pc.printf("\033[2J"); // Clear the screen + // 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++; } } -// Macros to streamline can bus message formatting and sending -#define SEND_CAN(LEN, ID) msg.len=LEN; msg.id=ID; msg.type = CANData; msg.format = CANStandard; if (!can.txWrite(msg)) data.canFault = true; xbeeRelay.send(msg); -#define FLOAT(DATA, ID) *((float*)((void*)&msg.data[0])) = DATA; SEND_CAN(sizeof(float), ID) -#define UINT(DATA, ID) *((uint32_t*)((void*)&msg.data[0])) = DATA; SEND_CAN(sizeof(uint32_t), ID) -#define FLOAT_PAIR(DATA1, DATA2, ID) *((float*)((void*)&msg.data[0])) = DATA1; *((float*)((void*)&msg.data[4])) = DATA2; SEND_CAN(2*sizeof(float), ID) -#define UINT_PAIR(DATA1, DATA2, ID) *((uint32_t*)((void*)&msg.data[0])) = DATA1; *((uint32_t*)((void*)&msg.data[4])) = DATA2; SEND_CAN(2*sizeof(uint32_t), ID) -#define CHAR(DATA, ID) msg.data[0] = DATA; SEND_CAN(sizeof(char), ID) - void outDiagnostics::thread_canOut(void const *args) { - CANMessage msg; + 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) { - // Sys Mgmt Error Frame - CHAR(data.errorFrame, SYS_ERROR_ID) + 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, SYS_ERROR_ID) + + // Mode + CAN_SINGLE(mode, SYS_MODE_ID) + + // Flags + CAN_SINGLE(signals, SYS_FLAGS_ID) + + // Profile + char byte = (op->profileIndex != -1) ? op->profileIndex : 1<<6; // Mark the second to last bit of the byte if using Freeze profile (data[0]=64 for freeze, data[0]=0 for default) + 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, SYS_PROFILE_ID); + + // Time + CAN_PAIR(SysTime, startTime, SYS_TIME_ID) // Xbee1 Counter - UINT_PAIR(xbeeRelay.counterX1in, xbeeRelay.counterX1out, SYS_XBEE1_ID) + CAN_PAIR(xbee1.msgIn, xbee1.msgOut, SYS_XBEE1_MSG_ID) // Xbee2 Counter - UINT_PAIR(xbeeRelay.counterX2in, xbeeRelay.counterX2out, SYS_XBEE2_ID) + CAN_PAIR(xbee2.msgIn, xbee2.msgOut, SYS_XBEE2_MSG_ID) // Internal temperature - FLOAT(data.internalTemp, SYS_TEMP_ID) + CAN_SINGLE(internalTemp, SYS_TEMP_ID) // GLV Battery - FLOAT(data.glvCurrent, SYS_GLV_CURRENT_ID) - FLOAT(data.glvCapacity, SYS_GLV_CAPACITY_ID) - FLOAT(data.glvAmphours, SYS_GLV_AH_ID) - FLOAT(data.glvSOC, SYS_GLV_SOC_ID) - + CAN_SINGLE(glvBat.current, SYS_GLV_CURRENT_ID) + CAN_SINGLE(glvBat.capacity, SYS_GLV_CAPACITY_ID) + CAN_SINGLE(glvBat.Ah, SYS_GLV_AH_ID) + CAN_SINGLE(glvBat.SOC, SYS_GLV_SOC_ID) + CAN_SINGLE(glvBat.error, SYS_GLV_ERROR_ID) + // DC-DC Converter - FLOAT(data.dcdcCurrent, SYS_DCDC_CURRENT_ID) - CHAR(data.dcdcStatus, SYS_DCDC_STATUS_ID) + CAN_SINGLE(dcdc.current, SYS_DCDC_CURRENT_ID) + CAN_SINGLE(dcdc.status, SYS_DCDC_STATUS_ID) // PWM Channels - FLOAT_PAIR(data.dcdcFan1Duty, data.dcdcFan2Duty, SYS_PWM_FAN_ID) - FLOAT_PAIR(data.dcdcPump1Duty, data.dcdcPump2Duty, SYS_PWM_PUMP_ID) + CAN_PAIR(dcdc.actual.fan1, dcdc.actual.fan2, SYS_PWM_FAN_ID) + CAN_PAIR(dcdc.actual.pump1, dcdc.actual.pump2, SYS_PWM_PUMP_ID) // IMD - FLOAT(data.imdStatus, SYS_IMD_STATUS_ID) - CHAR(data.imdResistance, SYS_IMD_RESIST_ID) + CAN_SINGLE(imd.status, SYS_IMD_STATUS_ID) + CAN_SINGLE(imd.resistance, SYS_IMD_RESIST_ID) // Latches - CHAR(data.IMDlatchError, SYS_IMD_LATCH_ID) - CHAR(data.AMSlatchError, SYS_AMS_LATCH_ID) + CAN_SINGLE(latch.imd, SYS_IMD_LATCH_ID) + CAN_SINGLE(latch.ams, SYS_AMS_LATCH_ID) // Shutdown Switches - CHAR(data.switchState, SYS_SWITCHES_ID) - + CAN_SINGLE(switchState, SYS_SWITCHES_ID) + osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<4); // Signal watchdog thread Thread::wait(CAN_LOOP*1000); }