System Management code
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
Diff: inCommands/inCommands.cpp
- Revision:
- 38:8efacce315ae
- Parent:
- 36:0afc0fc8f86b
- Child:
- 39:ddf38df9699e
--- a/inCommands/inCommands.cpp Thu Jan 22 07:59:48 2015 +0000 +++ b/inCommands/inCommands.cpp Sat Feb 07 08:54:51 2015 +0000 @@ -1,95 +1,19 @@ #include "inCommands.h" - -bool inCommands::serviceCAN(CANMessage* fromXbee) -{ - CANMessage msg; - if (fromXbee != NULL) { - memcpy((void*)&msg, (void*)fromXbee, sizeof(CANMessage)); - } else { - if (!can.rxRead(msg)) return false; - } - - switch (msg.id) { - case FAN_CONTROL_ID: - if (msg.len != 2*sizeof(float)) break; - memcpy((void*)&CANdata.dcdcFan1Duty, &msg.data[0], sizeof(float)); - memcpy((void*)&CANdata.dcdcFan2Duty, &msg.data[4], sizeof(float)); - dcdc.setPwm(FAN1, CANdata.dcdcFan1Duty); - dcdc.setPwm(FAN2, CANdata.dcdcFan2Duty); - break; - - case PUMP_CONTROL_ID: - if (msg.len != 2*sizeof(float)) break; - memcpy((void*)&CANdata.dcdcPump1Duty, &msg.data[0], sizeof(float)); - memcpy((void*)&CANdata.dcdcPump2Duty, &msg.data[4], sizeof(float)); - dcdc.setPwm(PUMP1, CANdata.dcdcPump1Duty); - dcdc.setPwm(PUMP2, CANdata.dcdcPump2Duty); - break; - - case DCDC_CONTROL_ID: - if (msg.len != sizeof(char)) break; - if (msg.data[0] == 1) dcdc.set(1); - else dcdc.set(0); - break; - - case AMS_MODE_ID: - if (msg.len != sizeof(char)) break; - if (msg.data[0] & 1<<2) { // AIRs closed? - CANdata.airsClosed = true; - dcdc.set(1); - } else { - CANdata.airsClosed = false; - dcdc.set(0); - } - break; - - case GLVBAT_SETSOC_ID: - if (msg.len != sizeof(float)) break; - glvBat.resetToSOC(*((float*)(&msg.data[0]))); - break; - - case GLVBAT_SETAH_ID: - if (msg.len != sizeof(float)) break; - glvBat.resetToAh(*((float*)(&msg.data[0]))); - break; - - case GLVBAT_SETCAPAC_ID: - if (msg.len != sizeof(float)) break; - glvBat.changeCapacity(*((float*)(&msg.data[0]))); - break; - case STEERING_RESET_ID: - NVIC_SystemReset(); - break; - default: - break; - } - - return true; - -} -// Check for incoming messages from the xbees, relay them to the CAN function and send them out on the bus -bool inCommands::receiveMsgXbee() -{ - CANMessage msg; - if (xbeeRelay.receive(msg)) { // Incoming CAN message string received - if (!can.txWrite(msg)) data.canFault = true; // Send it out on the CAN bus - serviceCAN(&msg); // Send it into the local serviceCAN routine - return true; - } else return false; -} +#include "runTime.h" +#include "inMacros.h" // Compare string to a word in the serial input, shorter to type #define CMP(w, string) if (!strcasecmp(word[w-1], string)) // Serial input -int inCommands::serviceSerial() +int serviceSerial() { - static int end = 0; // End of string position + static int end = 0; // End of string position int c=0; if (pc.readable()) c = pc.getc(); - if (c == -1) return -2; // Invalid char, no char available - + if (c == -1 || c == 0) return 0; + char b = c; // Casted to char type bool process = false; // Is string complete (ready to parse)? @@ -112,7 +36,7 @@ } // Continue to parsing section only if flagged as complete and string not empty if (!process || strlen((char*)tempData.inputStr) == 0) return 0; - + static char word[3][RX_SIZE+1]; // Hold 3 words int pieces = sscanf(tempData.inputStr, "%s %s %s", word[0], word[1], word[2]); // Populate words tempData.inputStr[0] = 0; // Empty the string displayed on screen @@ -125,17 +49,79 @@ NVIC_SystemReset(); return 1; } + // Clear non-volatile fault flags, then reset the microcontroller + CMP(1, "resetClear") { + runTime::clearFaults(); + NVIC_SystemReset(); + return 1; + } + return -1; } // Two word commands if (pieces == 2) { - // Manual DC-DC on/off control - CMP(1, "dcdc") { - CMP(2, "on") { - dcdc.set(1); + // Change the serial dashboard display mode + CMP(1, "display") { + CMP(2, "compact") { + if (param->change_extendedSerial(0)) { + op->profileModded=true; + return 1; // Change function defined by macro + } + } + CMP(2, "extended") { + if (param->change_extendedSerial(1)) { + op->profileModded=true; + return 1; // Change function defined by macro + } + } + } + // Change ACK setting for CAN (noAck allows testing of CAN without other nodes) + CMP(1, "CANack") { + CMP(2, "noack") { // NoAck test mode + if (param->change_CANnoAck(1)) { + op->profileModded=true; + return 1; + } + } + CMP(2, "ack") { // Normal CAN protocol + if (param->change_CANnoAck(0)) { + op->profileModded=true; + return 1; + } + } + return -1; + } + // Artificially capture a freeze frame, save to flash + CMP(1, "capture") { + CMP(2, "freeze") { + if (!FreezeFrame::getError()) { // Only allow capture if spot available (last error frame was cleared manually) + if (FreezeFrame::writeFrame()) { // Copy RAM frame to freezree sector in flash + return 1; + } + } + } + return -1; + } + // Clear fault conditions + CMP(1, "clear") { + CMP(2, "freeze") { // Clear the freeze frame (mark as read) + FreezeFrame::clearError(); // Clear the non-volatile error marker return 1; } - CMP(2, "off") { - dcdc.set(0); + CMP(2, "faults") { // Clear everything + runTime::clearFaults(); + return 1; + } + return -1; + } + // Change the display contents + CMP(1, "view") { + CMP(2, "freeze") { // View the last stored freeze frame + if (FreezeFrame::getFrame(&tempData.freeze)) { // Fetch the pointer from flash + return 1; + } + } + CMP(2, "live") { // View live data from RAM + tempData.freeze = NULL; // Zero the pointer return 1; } return -1; @@ -172,6 +158,44 @@ } return -1; } + + bool parsed=false; + + CHANGE_VAR("GLVchar", chargeCurrent) + CHANGE_VAR("GLVdisch", dischargeCurrent) + CHANGE_VAR("GLVnomCap", nominalCapacity) + CHANGE_VAR("GLVtaps", glvBat_taps) + CHANGE_VAR("dcdcThres", dcdcThreshold) + CHANGE_VAR("dcdcOver", dcdcOverCurrent) + CHANGE_VAR("dcdcStart", dcdcStartDelay) + CHANGE_VAR("dcdcStop", dcdcStopDelay) + CHANGE_VAR("dcdcTaps", dcdc_taps) + CHANGE_VAR("imdStart", imdStartDelay) + CHANGE_VAR("amsStart", amsStartDelay) + CHANGE_VAR("IntOverT", internalOverTemp) + CHANGE_VAR("CANtxSize", CANtxSize) + CHANGE_VAR("CANrxSize", CANrxSize) + CHANGE_VAR("SerialBaud", SerialBaud) + CHANGE_VAR("SerialTx", SerialTxSize) + CHANGE_VAR("XbeeBaud", XbeeBaud) + CHANGE_VAR("XbeeTxSize", XbeeTxSize) + CHANGE_VAR("XbeeRxSize", XbeeRxSize) + CHANGE_VAR("CANack", CANnoAck) + + if (!parsed) return -1; + + CMP(1, "GLVnomCap") return glvBat.changeCapacity(param->nominalCapacity)?1:-1; + CMP(1, "GLVtaps") return glvBat.size(param->glvBat_taps)?1:-1; + CMP(1, "dcdcTaps") return dcdc.size(param->dcdc_taps)?1:-1; + CMP(1, "CANtxSize") return can.txSize(param->CANtxSize)?1:-1; + CMP(1, "CANrxSize") return can.rxSize(param->CANrxSize)?1:-1; + CMP(1, "SerialBaud") pc.baud(param->SerialBaud); + CMP(1, "SerialTx") return (pc.txBufferSetSize(param->SerialTxSize) == 0)?1:-1; + CMP(1, "XbeeBaud") xbeeRelay.baud(param->XbeeBaud); + CMP(1, "XbeeTxSize") return (xbeeRelay.txSize(param->XbeeTxSize))?1:-1; + CMP(1, "XbeeRxSize") return (xbeeRelay.rxSize(param->XbeeRxSize))?1:-1; + + return 1; } // Three word commands if (pieces == 3) { @@ -181,8 +205,8 @@ if (*next == 0) { float val2 = strtod(word[2], &next); if (*next == 0) { - dcdc.setPwm(FAN1, val1); - dcdc.setPwm(FAN2, val2); + op->dcdc.request.fan1 = val1; + op->dcdc.request.fan2 = val2; return 1; } } @@ -195,24 +219,323 @@ if (*next == 0) { float val2 = strtod(word[2], &next); if (*next == 0) { - dcdc.setPwm(FAN1, val1); - dcdc.setPwm(FAN2, val2); + op->dcdc.request.pump1 = val1; + op->dcdc.request.pump2 = val2; + return 1; + } + } + return -1; + } + // Set the system time (RTC) + CMP(1, "Time") { + struct tm t; // Time & date struct + int ret = sscanf(word[1], "%d/%d/%d", &t.tm_mon, &t.tm_mday, &t.tm_year); // Populate date + t.tm_year = t.tm_year - 1900; // Year mod to fix 0 index + t.tm_mon = t.tm_mon - 1; // Month mod to fix 0 index + if (ret == 3) { // All 3 items found + ret = sscanf(word[2], "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); // Populate time + if (ret == 3) { // All 3 items found + set_time(mktime(&t)); // Set the RTC + time_t diff = time(NULL) - op->SysTime; // Get change in time from old to new + op->startTime += diff; // Shift the startTime to new timebase return 1; } } return -1; } + + // Profile manipulations between RAM and flash + CMP(1, "Profile") { + // Write, copy RAM to a flash sector + CMP(2, "Write") { + unsigned int index = strtoul(word[2], &next, 10); // Get index from command "profile write xxx" + if (index <= NUM_STORED_PROFILES && index > 0 && *next == 0) { // Check within bounds + bool s = Profile::saveProfile(index); // Write to flash + if (s) { // Successful? + op->profileModded = false; // Mark it as a fresh, unmodified profile + op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker + return 1; + } + } + return -1; + } + // Load, read from flash to RAM + CMP(2, "Load") { + CMP(3, "default") { // The hard-coded flash profile (found in FreezeFrame.cpp) + Profile::loadProfile(0); // Copy default to RAM + op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker + op->profileModded = false; // Mark it as a fresh, unmodified profile + return 1; + } + CMP(3, "freeze") { // Get the profile portion of the last freeze frame captured + if(Profile::loadProfile(-1)) { // Attemp to retrieve and copy to RAM + op->profileModded = false; // Mark it as a fresh, unmodified profile + op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker + return 1; + } + } + int index = strtol(word[2], &next, 10); // Command was "profile load xxx" + if (index <= NUM_STORED_PROFILES && index >= -1 && *next == 0) { // Valid index found? + if (Profile::loadProfile(index)) { // Attempt to retrieve and copy to RAM + op->profileModded = false; // Mark it as a fresh, unmodified profile + op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker + return 1; + } + } + return -1; + } + // View the profile only (NOT loaded to RAM, just display changed) + CMP(2, "view") { + CMP(3, "default") { // View the hard-coded flash profile + if (Profile::getProfile(&tempData.viewProfile, 0)) { // Attempt to fetch pointer + tempData.viewProfileNum = 0; // Mark the index of the fetched profile + return 1; + } + } + CMP(3, "freeze") { // View the profile portion only of the last captured freeze frame + if (Profile::getProfile(&tempData.viewProfile, -1)) { // Attempt to fetch pointer + tempData.viewProfileNum = -1; // Mark the index of the fetched profile + return 1; + } + } + CMP(3, "live") { // Revert to normal, live view + tempData.viewProfileNum = -2; // Mark live + tempData.viewProfile = NULL; // Clear the pointer + return 1; + } + + int index = strtol(word[2], &next, 10); // Command was "profile view xxx" + if (index <= NUM_STORED_PROFILES && index >= -1 && *next == 0) { // Valid index found? + if (Profile::getProfile(&tempData.viewProfile, index)) { // Attempt to fetch pointer + tempData.viewProfileNum = index; // Mark the index of the fetched profile + return 1; + } + } + return -1; + } + } } return -1; } +// Called when AMS AIRs Mode message stops coming in +Timeout timer_AIRS_CLOSED; +void timeout_AIRS_CLOSED() +{ + op->signals &= ~AIRS_CLOSED; +} + +// Called when Charger CAN messages stop coming in +Timeout timer_CHARGER_DET; +void timeout_CHARGER_DET() +{ + op->signals &= ~CHARGER_DET; +} + +// Called when PCM messages stop coming in +Timeout timer_FANS; +void timeout_FANS() +{ + op->dcdc.request.fan1 = 0; + op->dcdc.request.fan2 = 0; +} +Timeout timer_PUMPS; +void timeout_PUMPS() +{ + op->dcdc.request.pump1 = 0; + op->dcdc.request.pump2 = 0; +} + +#define REFRESH_TIMEOUT(NAME) \ +timer_##NAME.detach(); \ +timer_##NAME.attach(&timeout_##NAME, CAN_DEVICE_TIMEOUT); + +bool serviceCAN(CANMessage* fromXbee) +{ + CANMessage msg; + if (fromXbee != NULL) { + memcpy((void*)&msg, (void*)fromXbee, sizeof(CANMessage)); + } else { + if (!can.rxRead(msg)) return false; + } + // Redirect global car reset + if (msg.id == GLOBAL_CAR_RESET_RX_ID) msg.id = RESETCLEAR_RX_ID; + + switch (msg.id) { + // Reset microntroller + case (RESET_RX_ID): + if (msg.len == 0) { // Length must = 0 + NVIC_SystemReset(); + CAN_SUCCESS + } + CAN_FAIL + + + // Clear non-volatile fault flags, then reset microcontroller + case (RESETCLEAR_RX_ID): + if (msg.len == 0) { // Length must = 0 + FreezeFrame::clearError(); + NVIC_SystemReset(); + CAN_SUCCESS + } + CAN_FAIL + + // Artificially capture a freeze frame + case (CAPTURE_RX_ID): + if (msg.len == 0) { // Length must = 0 + if (!FreezeFrame::getError()) { // Only allow capture if freeze frame from the last error was read + if (FreezeFrame::writeFrame()) { // Capture the RAM contents to flash + CAN_SUCCESS + } + } + } + CAN_FAIL + + // Clear fault conditions + case (CLEAR_RX_ID): + if (msg.len == 1) { // One data byte + if (msg.data[0] == 0) { // Clear only freeze frame error if = 0 + FreezeFrame::clearError(); // Clear non-volatile freeze frame marker + CAN_SUCCESS + } + if (msg.data[0] == 1) { // Clear everything if = 1 + runTime::clearFaults(); + op->faultCode = 0; + CAN_SUCCESS + } + } + CAN_FAIL + + // Set the time (RTC) + case (TIME_RX_ID): + if (msg.len == 6*sizeof(char)) { // 6 Bytes + struct tm t; // Time & date struct + t.tm_mon = msg.data[0]; // Month in byte[0] + t.tm_mday = msg.data[1]; // Day + t.tm_year = msg.data[2]; // Year (offset from 2000) + t.tm_year = t.tm_year - 1900 + 2000; // Apply year index mod and offset + t.tm_mon = t.tm_mon - 1; // Month index mod + t.tm_hour = msg.data[3]; // Get hour of time in byte[3] (24 hr format) + t.tm_min = msg.data[4]; // Minutes + t.tm_sec = msg.data[5]; // Seconds + set_time(mktime(&t)); // Set RTC + time_t diff = time(NULL) - op->SysTime; // Old time to new time change + op->startTime += diff; // Shift the startTime to new timebase + CAN_SUCCESS + } + CAN_FAIL + + // RAM and flash profile manipulations + case (PROFILE_RX_ID): + if (msg.len == 2*sizeof(char)) { // 2 command bytes + if (msg.data[0] == 0) { // Load profile from a flash location to RAM + int index = msg.data[1]; // Second byte contains profile index + if (msg.data[1] == 0xff) index = -1; // If freeze (special case) + if (Profile::loadProfile(index)) { // Attempt to load (copy flash to RAM) + op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker + op->profileModded = false; // Mark it as a fresh, unmodified profile + CAN_SUCCESS + } + } + if (msg.data[0] == 1) { // Write profile to flash from RAM + int index = msg.data[1]; // Get which slot to write to from message + if (msg.data[1] == 0xff) index = -1; // If freeze (special case) + bool s = Profile::saveProfile(index); // Write profile to flash slot + if (s) { + op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker + op->profileModded = false; // Mark it as a fresh, unmodified profile + CAN_SUCCESS + } + } + } + CAN_FAIL + + case FAN_CONTROL_ID: + if (msg.len != 2*sizeof(float)) return false; + REFRESH_TIMEOUT(FANS) + op->dcdc.request.fan1 = *((float*)((void*)(&msg.data[0]))); + op->dcdc.request.fan2 = *((float*)((void*)(&msg.data[4]))); + return true; + + case PUMP_CONTROL_ID: + if (msg.len != 2*sizeof(float)) return false; + REFRESH_TIMEOUT(PUMPS) + op->dcdc.request.pump1 = *((float*)((void*)(&msg.data[0]))); + op->dcdc.request.pump2 = *((float*)((void*)(&msg.data[4]))); + return true; + + case AMS_MODE_ID: + if (msg.len != sizeof(char)) return false; + REFRESH_TIMEOUT(AIRS_CLOSED) + if (msg.data[0] & 1<<2) { // AIRs closed? + op->signals |= AIRS_CLOSED; + } else { + op->signals &= ~AIRS_CLOSED; + } + return true; + case CHARGER_ERR_ID: + REFRESH_TIMEOUT(CHARGER_DET) + op->signals |= CHARGER_DET; + return true; + default: + break; + } + bool parsed=false; + + CAN_CHANGE(chargeCurrent, PROFILE_CHARGECURRENT_RX_ID ) + CAN_CHANGE(dischargeCurrent, PROFILE_DISCHARGECURRENT_RX_ID ) + CAN_CHANGE(nominalCapacity, PROFILE_NOMINALCAPACITY_RX_ID ) + CAN_CHANGE(glvBat_taps, PROFILE_GLVBATTAPS_RX_ID ) + CAN_CHANGE(dcdcThreshold, PROFILE_DCDCONTHRESHOLD_RX_ID ) + CAN_CHANGE(dcdcOverCurrent, PROFILE_DCDCOVERCURRENT_RX_ID ) + CAN_CHANGE(dcdcStartDelay, PROFILE_DCDCSTARTDELAY_RX_ID ) + CAN_CHANGE(dcdcStopDelay, PROFILE_DCDCSTOPDELAY_RX_ID ) + CAN_CHANGE(dcdc_taps, PROFILE_DCDC_TAPS_RX_ID ) + CAN_CHANGE(imdStartDelay, PROFILE_IMDSTARTDELAY_RX_ID ) + CAN_CHANGE(internalOverTemp, PROFILE_INTERNALOVERTEMP_RX_ID ) + CAN_CHANGE(CANnoAck, PROFILE_CANNOACK_RX_ID ) + CAN_CHANGE(extendedSerial, PROFILE_EXTENDSERIAL_RX_ID ) + CAN_CHANGE(CANtxSize, PROFILE_CANTXSIZE_RX_ID ) + CAN_CHANGE(CANrxSize, PROFILE_CANRXSIZE_RX_ID ) + CAN_CHANGE(SerialBaud, PROFILE_SERIALBAUD_RX_ID ) + CAN_CHANGE(SerialTxSize, PROFILE_SERIALTXSIZE_RX_ID ) + CAN_CHANGE(XbeeBaud, PROFILE_XBEEBAUD_RX_ID ) + CAN_CHANGE(XbeeTxSize, PROFILE_XBEETXSIZE_RX_ID ) + CAN_CHANGE(XbeeRxSize, PROFILE_XBEERXSIZE_RX_ID ) + + if (!parsed) return false; + + if (msg.id == PROFILE_NOMINALCAPACITY_RX_ID ) return glvBat.changeCapacity(param->nominalCapacity)?1:-1; + if (msg.id == PROFILE_GLVBATTAPS_RX_ID ) return glvBat.size(param->glvBat_taps)?1:-1; + if (msg.id == PROFILE_DCDC_TAPS_RX_ID ) return dcdc.size(param->dcdc_taps)?1:-1; + if (msg.id == PROFILE_CANTXSIZE_RX_ID ) return can.txSize(param->CANtxSize)?1:-1; + if (msg.id == PROFILE_CANRXSIZE_RX_ID ) return can.rxSize(param->CANrxSize)?1:-1; + if (msg.id == PROFILE_SERIALBAUD_RX_ID ) pc.baud(param->SerialBaud); + if (msg.id == PROFILE_SERIALTXSIZE_RX_ID ) return (pc.txBufferSetSize(param->SerialTxSize) == 0)?1:-1; + if (msg.id == PROFILE_XBEEBAUD_RX_ID ) xbeeRelay.baud(param->XbeeBaud); + if (msg.id == PROFILE_XBEETXSIZE_RX_ID ) return (xbeeRelay.txSize(param->XbeeTxSize))?1:-1; + if (msg.id == PROFILE_XBEERXSIZE_RX_ID ) return (xbeeRelay.rxSize(param->XbeeRxSize))?1:-1; + + return true; +} +// Check for incoming messages from the xbees, relay them to the CAN function and send them out on the bus +bool receiveMsgXbee() +{ + CANMessage msg; + if (xbeeRelay.receive(msg)) { // Incoming CAN message string received + if (!can.txWrite(msg)) op->faultCode |= CAN_FAULT; // Send it out on the CAN bus + serviceCAN(&msg); // Send it into the local serviceCAN routine + return true; + } else return false; +} + void inCommands::thread_getInputs(void const* args) { while(1) { - inCommands::serviceCAN(); - inCommands::receiveMsgXbee(); + serviceCAN(0); + receiveMsgXbee(); - int ret = inCommands::serviceSerial(); + int ret = serviceSerial(); if (ret == -1) tempData.parseGoodChar = 'x'; if (ret == 1) tempData.parseGoodChar = 251; osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<2); // Signal watchdog thread