System Management code

Dependencies:   mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP

Fork of SystemManagement by Martin Deng

Committer:
pspatel321
Date:
Wed Feb 11 23:09:57 2015 +0000
Revision:
39:ddf38df9699e
Parent:
38:8efacce315ae
Updated CAN IDs for datalogging.  Changed profile encoding.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pspatel321 34:18bcf276d3bf 1 #include "inCommands.h"
pspatel321 38:8efacce315ae 2 #include "runTime.h"
pspatel321 38:8efacce315ae 3 #include "inMacros.h"
pspatel321 34:18bcf276d3bf 4
pspatel321 34:18bcf276d3bf 5 // Compare string to a word in the serial input, shorter to type
pspatel321 34:18bcf276d3bf 6 #define CMP(w, string) if (!strcasecmp(word[w-1], string))
pspatel321 36:0afc0fc8f86b 7
pspatel321 34:18bcf276d3bf 8 // Serial input
pspatel321 38:8efacce315ae 9 int serviceSerial()
pspatel321 34:18bcf276d3bf 10 {
pspatel321 38:8efacce315ae 11 static int end = 0; // End of string position
pspatel321 34:18bcf276d3bf 12
pspatel321 36:0afc0fc8f86b 13 int c=0;
pspatel321 36:0afc0fc8f86b 14 if (pc.readable()) c = pc.getc();
pspatel321 38:8efacce315ae 15 if (c == -1 || c == 0) return 0;
pspatel321 38:8efacce315ae 16
pspatel321 34:18bcf276d3bf 17 char b = c; // Casted to char type
pspatel321 34:18bcf276d3bf 18 bool process = false; // Is string complete (ready to parse)?
pspatel321 34:18bcf276d3bf 19
pspatel321 34:18bcf276d3bf 20 if (b == '\n' || b == '\r') { // Enter key was pressed, dump for processing
pspatel321 34:18bcf276d3bf 21 tempData.inputStr[end] = 0; // Null terminate
pspatel321 34:18bcf276d3bf 22 end = 0; // Reset to start
pspatel321 34:18bcf276d3bf 23 process = true; // Flag for processing
pspatel321 34:18bcf276d3bf 24
pspatel321 34:18bcf276d3bf 25 } else if (b == '\b' || b == 127) { // Backspace or delete
pspatel321 34:18bcf276d3bf 26 if (end > 0) end--; // Move back one char
pspatel321 34:18bcf276d3bf 27 tempData.inputStr[end] = 0; // Erase char
pspatel321 34:18bcf276d3bf 28
pspatel321 34:18bcf276d3bf 29 } else if (b > 31 && b < 127) { // New valid displayable char
pspatel321 36:0afc0fc8f86b 30 tempData.inputStr[end++] = b; // Add to buffer
pspatel321 34:18bcf276d3bf 31 tempData.inputStr[end] = 0; // Add null terminator
pspatel321 34:18bcf276d3bf 32 if (end >= RX_SIZE) {
pspatel321 34:18bcf276d3bf 33 end = 0; // Reset end location
pspatel321 34:18bcf276d3bf 34 process = true; // Flag for processing
pspatel321 34:18bcf276d3bf 35 }
pspatel321 34:18bcf276d3bf 36 }
pspatel321 34:18bcf276d3bf 37 // Continue to parsing section only if flagged as complete and string not empty
pspatel321 36:0afc0fc8f86b 38 if (!process || strlen((char*)tempData.inputStr) == 0) return 0;
pspatel321 38:8efacce315ae 39
pspatel321 36:0afc0fc8f86b 40 static char word[3][RX_SIZE+1]; // Hold 3 words
pspatel321 34:18bcf276d3bf 41 int pieces = sscanf(tempData.inputStr, "%s %s %s", word[0], word[1], word[2]); // Populate words
pspatel321 34:18bcf276d3bf 42 tempData.inputStr[0] = 0; // Empty the string displayed on screen
pspatel321 36:0afc0fc8f86b 43 char *next; // Used by strtof and strtoul
pspatel321 34:18bcf276d3bf 44
pspatel321 34:18bcf276d3bf 45 // One word commands
pspatel321 34:18bcf276d3bf 46 if (pieces == 1) {
pspatel321 34:18bcf276d3bf 47 // Reset the microcontroller
pspatel321 34:18bcf276d3bf 48 CMP(1, "reset") {
pspatel321 34:18bcf276d3bf 49 NVIC_SystemReset();
pspatel321 34:18bcf276d3bf 50 return 1;
pspatel321 34:18bcf276d3bf 51 }
pspatel321 38:8efacce315ae 52 // Clear non-volatile fault flags, then reset the microcontroller
pspatel321 38:8efacce315ae 53 CMP(1, "resetClear") {
pspatel321 38:8efacce315ae 54 runTime::clearFaults();
pspatel321 38:8efacce315ae 55 NVIC_SystemReset();
pspatel321 38:8efacce315ae 56 return 1;
pspatel321 38:8efacce315ae 57 }
pspatel321 38:8efacce315ae 58 return -1;
pspatel321 34:18bcf276d3bf 59 }
pspatel321 36:0afc0fc8f86b 60 // Two word commands
pspatel321 34:18bcf276d3bf 61 if (pieces == 2) {
pspatel321 38:8efacce315ae 62 // Change the serial dashboard display mode
pspatel321 38:8efacce315ae 63 CMP(1, "display") {
pspatel321 38:8efacce315ae 64 CMP(2, "compact") {
pspatel321 38:8efacce315ae 65 if (param->change_extendedSerial(0)) {
pspatel321 38:8efacce315ae 66 op->profileModded=true;
pspatel321 38:8efacce315ae 67 return 1; // Change function defined by macro
pspatel321 38:8efacce315ae 68 }
pspatel321 38:8efacce315ae 69 }
pspatel321 38:8efacce315ae 70 CMP(2, "extended") {
pspatel321 38:8efacce315ae 71 if (param->change_extendedSerial(1)) {
pspatel321 38:8efacce315ae 72 op->profileModded=true;
pspatel321 38:8efacce315ae 73 return 1; // Change function defined by macro
pspatel321 38:8efacce315ae 74 }
pspatel321 38:8efacce315ae 75 }
pspatel321 38:8efacce315ae 76 }
pspatel321 38:8efacce315ae 77 // Change ACK setting for CAN (noAck allows testing of CAN without other nodes)
pspatel321 38:8efacce315ae 78 CMP(1, "CANack") {
pspatel321 38:8efacce315ae 79 CMP(2, "noack") { // NoAck test mode
pspatel321 38:8efacce315ae 80 if (param->change_CANnoAck(1)) {
pspatel321 38:8efacce315ae 81 op->profileModded=true;
pspatel321 38:8efacce315ae 82 return 1;
pspatel321 38:8efacce315ae 83 }
pspatel321 38:8efacce315ae 84 }
pspatel321 38:8efacce315ae 85 CMP(2, "ack") { // Normal CAN protocol
pspatel321 38:8efacce315ae 86 if (param->change_CANnoAck(0)) {
pspatel321 38:8efacce315ae 87 op->profileModded=true;
pspatel321 38:8efacce315ae 88 return 1;
pspatel321 38:8efacce315ae 89 }
pspatel321 38:8efacce315ae 90 }
pspatel321 38:8efacce315ae 91 return -1;
pspatel321 38:8efacce315ae 92 }
pspatel321 38:8efacce315ae 93 // Artificially capture a freeze frame, save to flash
pspatel321 38:8efacce315ae 94 CMP(1, "capture") {
pspatel321 38:8efacce315ae 95 CMP(2, "freeze") {
pspatel321 38:8efacce315ae 96 if (!FreezeFrame::getError()) { // Only allow capture if spot available (last error frame was cleared manually)
pspatel321 38:8efacce315ae 97 if (FreezeFrame::writeFrame()) { // Copy RAM frame to freezree sector in flash
pspatel321 38:8efacce315ae 98 return 1;
pspatel321 38:8efacce315ae 99 }
pspatel321 38:8efacce315ae 100 }
pspatel321 38:8efacce315ae 101 }
pspatel321 38:8efacce315ae 102 return -1;
pspatel321 38:8efacce315ae 103 }
pspatel321 38:8efacce315ae 104 // Clear fault conditions
pspatel321 38:8efacce315ae 105 CMP(1, "clear") {
pspatel321 38:8efacce315ae 106 CMP(2, "freeze") { // Clear the freeze frame (mark as read)
pspatel321 38:8efacce315ae 107 FreezeFrame::clearError(); // Clear the non-volatile error marker
pspatel321 34:18bcf276d3bf 108 return 1;
pspatel321 34:18bcf276d3bf 109 }
pspatel321 38:8efacce315ae 110 CMP(2, "faults") { // Clear everything
pspatel321 38:8efacce315ae 111 runTime::clearFaults();
pspatel321 38:8efacce315ae 112 return 1;
pspatel321 38:8efacce315ae 113 }
pspatel321 38:8efacce315ae 114 return -1;
pspatel321 38:8efacce315ae 115 }
pspatel321 38:8efacce315ae 116 // Change the display contents
pspatel321 38:8efacce315ae 117 CMP(1, "view") {
pspatel321 38:8efacce315ae 118 CMP(2, "freeze") { // View the last stored freeze frame
pspatel321 38:8efacce315ae 119 if (FreezeFrame::getFrame(&tempData.freeze)) { // Fetch the pointer from flash
pspatel321 38:8efacce315ae 120 return 1;
pspatel321 38:8efacce315ae 121 }
pspatel321 38:8efacce315ae 122 }
pspatel321 38:8efacce315ae 123 CMP(2, "live") { // View live data from RAM
pspatel321 38:8efacce315ae 124 tempData.freeze = NULL; // Zero the pointer
pspatel321 34:18bcf276d3bf 125 return 1;
pspatel321 34:18bcf276d3bf 126 }
pspatel321 34:18bcf276d3bf 127 return -1;
pspatel321 34:18bcf276d3bf 128 }
pspatel321 34:18bcf276d3bf 129 // Artificially update the SOC (battery life %)
pspatel321 34:18bcf276d3bf 130 CMP(1, "SOC") {
pspatel321 34:18bcf276d3bf 131 CMP(2, "Reset") { // Command was "SOC reset" - reset to 100%, do this after a full charge
pspatel321 34:18bcf276d3bf 132 glvBat.resetToSOC(1);
pspatel321 34:18bcf276d3bf 133 return 1;
pspatel321 34:18bcf276d3bf 134 }
pspatel321 34:18bcf276d3bf 135 float soc = strtod(word[1], &next); // Command was "SOC xxx" where xxx is float between 0 and 1
pspatel321 34:18bcf276d3bf 136 if (*next == 0) {
pspatel321 34:18bcf276d3bf 137 if (glvBat.resetToSOC(soc)) return 1;
pspatel321 34:18bcf276d3bf 138 }
pspatel321 34:18bcf276d3bf 139 return -1;
pspatel321 34:18bcf276d3bf 140 }
pspatel321 34:18bcf276d3bf 141 // Artificially update the AmpHours count (linked with SOC)
pspatel321 34:18bcf276d3bf 142 CMP(1, "Ah") {
pspatel321 34:18bcf276d3bf 143 CMP(2, "Reset") { // Command was "Amphours reset", equivalent to "SOC reset"
pspatel321 34:18bcf276d3bf 144 glvBat.resetToSOC(1);
pspatel321 34:18bcf276d3bf 145 return 1;
pspatel321 34:18bcf276d3bf 146 }
pspatel321 34:18bcf276d3bf 147 float ah = strtod(word[1], &next); // Command was "Amphours xxx" where xxx is a float in amphours
pspatel321 34:18bcf276d3bf 148 if (*next == 0) {
pspatel321 34:18bcf276d3bf 149 if (glvBat.resetToAh(ah)) return 1;
pspatel321 34:18bcf276d3bf 150 }
pspatel321 34:18bcf276d3bf 151 return -1;
pspatel321 34:18bcf276d3bf 152 }
pspatel321 34:18bcf276d3bf 153 // Change the battery capacity setting for calculating Amphours
pspatel321 34:18bcf276d3bf 154 CMP(1, "Capacity") {
pspatel321 34:18bcf276d3bf 155 float cap = strtod(word[1], &next); // Command was "SOC xxx" where xxx is float between 0 and 1
pspatel321 34:18bcf276d3bf 156 if (*next == 0) {
pspatel321 34:18bcf276d3bf 157 if (glvBat.changeCapacity(cap)) return 1;
pspatel321 34:18bcf276d3bf 158 }
pspatel321 36:0afc0fc8f86b 159 return -1;
pspatel321 34:18bcf276d3bf 160 }
pspatel321 38:8efacce315ae 161
pspatel321 38:8efacce315ae 162 bool parsed=false;
pspatel321 38:8efacce315ae 163
pspatel321 38:8efacce315ae 164 CHANGE_VAR("GLVchar", chargeCurrent)
pspatel321 38:8efacce315ae 165 CHANGE_VAR("GLVdisch", dischargeCurrent)
pspatel321 38:8efacce315ae 166 CHANGE_VAR("GLVnomCap", nominalCapacity)
pspatel321 38:8efacce315ae 167 CHANGE_VAR("GLVtaps", glvBat_taps)
pspatel321 38:8efacce315ae 168 CHANGE_VAR("dcdcThres", dcdcThreshold)
pspatel321 38:8efacce315ae 169 CHANGE_VAR("dcdcOver", dcdcOverCurrent)
pspatel321 38:8efacce315ae 170 CHANGE_VAR("dcdcStart", dcdcStartDelay)
pspatel321 38:8efacce315ae 171 CHANGE_VAR("dcdcStop", dcdcStopDelay)
pspatel321 38:8efacce315ae 172 CHANGE_VAR("dcdcTaps", dcdc_taps)
pspatel321 38:8efacce315ae 173 CHANGE_VAR("imdStart", imdStartDelay)
pspatel321 38:8efacce315ae 174 CHANGE_VAR("amsStart", amsStartDelay)
pspatel321 38:8efacce315ae 175 CHANGE_VAR("IntOverT", internalOverTemp)
pspatel321 38:8efacce315ae 176 CHANGE_VAR("CANtxSize", CANtxSize)
pspatel321 38:8efacce315ae 177 CHANGE_VAR("CANrxSize", CANrxSize)
pspatel321 38:8efacce315ae 178 CHANGE_VAR("SerialBaud", SerialBaud)
pspatel321 38:8efacce315ae 179 CHANGE_VAR("SerialTx", SerialTxSize)
pspatel321 38:8efacce315ae 180 CHANGE_VAR("CANack", CANnoAck)
pspatel321 38:8efacce315ae 181
pspatel321 38:8efacce315ae 182 if (!parsed) return -1;
pspatel321 38:8efacce315ae 183
pspatel321 38:8efacce315ae 184 CMP(1, "GLVnomCap") return glvBat.changeCapacity(param->nominalCapacity)?1:-1;
pspatel321 38:8efacce315ae 185 CMP(1, "GLVtaps") return glvBat.size(param->glvBat_taps)?1:-1;
pspatel321 38:8efacce315ae 186 CMP(1, "dcdcTaps") return dcdc.size(param->dcdc_taps)?1:-1;
pspatel321 38:8efacce315ae 187 CMP(1, "CANtxSize") return can.txSize(param->CANtxSize)?1:-1;
pspatel321 38:8efacce315ae 188 CMP(1, "CANrxSize") return can.rxSize(param->CANrxSize)?1:-1;
pspatel321 38:8efacce315ae 189 CMP(1, "SerialBaud") pc.baud(param->SerialBaud);
pspatel321 38:8efacce315ae 190 CMP(1, "SerialTx") return (pc.txBufferSetSize(param->SerialTxSize) == 0)?1:-1;
pspatel321 38:8efacce315ae 191
pspatel321 38:8efacce315ae 192 return 1;
pspatel321 34:18bcf276d3bf 193 }
pspatel321 36:0afc0fc8f86b 194 // Three word commands
pspatel321 34:18bcf276d3bf 195 if (pieces == 3) {
pspatel321 34:18bcf276d3bf 196 // Fan Duty
pspatel321 34:18bcf276d3bf 197 CMP(1, "Fan") {
pspatel321 34:18bcf276d3bf 198 float val1 = strtod(word[1], &next);
pspatel321 34:18bcf276d3bf 199 if (*next == 0) {
pspatel321 34:18bcf276d3bf 200 float val2 = strtod(word[2], &next);
pspatel321 34:18bcf276d3bf 201 if (*next == 0) {
pspatel321 38:8efacce315ae 202 op->dcdc.request.fan1 = val1;
pspatel321 38:8efacce315ae 203 op->dcdc.request.fan2 = val2;
pspatel321 34:18bcf276d3bf 204 return 1;
pspatel321 34:18bcf276d3bf 205 }
pspatel321 34:18bcf276d3bf 206 }
pspatel321 34:18bcf276d3bf 207 return -1;
pspatel321 34:18bcf276d3bf 208 }
pspatel321 34:18bcf276d3bf 209
pspatel321 34:18bcf276d3bf 210 // Pump Duty
pspatel321 34:18bcf276d3bf 211 CMP(1, "Pump") {
pspatel321 34:18bcf276d3bf 212 float val1 = strtod(word[1], &next);
pspatel321 34:18bcf276d3bf 213 if (*next == 0) {
pspatel321 34:18bcf276d3bf 214 float val2 = strtod(word[2], &next);
pspatel321 34:18bcf276d3bf 215 if (*next == 0) {
pspatel321 38:8efacce315ae 216 op->dcdc.request.pump1 = val1;
pspatel321 38:8efacce315ae 217 op->dcdc.request.pump2 = val2;
pspatel321 38:8efacce315ae 218 return 1;
pspatel321 38:8efacce315ae 219 }
pspatel321 38:8efacce315ae 220 }
pspatel321 38:8efacce315ae 221 return -1;
pspatel321 38:8efacce315ae 222 }
pspatel321 38:8efacce315ae 223 // Set the system time (RTC)
pspatel321 38:8efacce315ae 224 CMP(1, "Time") {
pspatel321 38:8efacce315ae 225 struct tm t; // Time & date struct
pspatel321 38:8efacce315ae 226 int ret = sscanf(word[1], "%d/%d/%d", &t.tm_mon, &t.tm_mday, &t.tm_year); // Populate date
pspatel321 38:8efacce315ae 227 t.tm_year = t.tm_year - 1900; // Year mod to fix 0 index
pspatel321 38:8efacce315ae 228 t.tm_mon = t.tm_mon - 1; // Month mod to fix 0 index
pspatel321 38:8efacce315ae 229 if (ret == 3) { // All 3 items found
pspatel321 38:8efacce315ae 230 ret = sscanf(word[2], "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); // Populate time
pspatel321 38:8efacce315ae 231 if (ret == 3) { // All 3 items found
pspatel321 38:8efacce315ae 232 set_time(mktime(&t)); // Set the RTC
pspatel321 38:8efacce315ae 233 time_t diff = time(NULL) - op->SysTime; // Get change in time from old to new
pspatel321 38:8efacce315ae 234 op->startTime += diff; // Shift the startTime to new timebase
pspatel321 34:18bcf276d3bf 235 return 1;
pspatel321 34:18bcf276d3bf 236 }
pspatel321 34:18bcf276d3bf 237 }
pspatel321 34:18bcf276d3bf 238 return -1;
pspatel321 34:18bcf276d3bf 239 }
pspatel321 38:8efacce315ae 240
pspatel321 38:8efacce315ae 241 // Profile manipulations between RAM and flash
pspatel321 38:8efacce315ae 242 CMP(1, "Profile") {
pspatel321 38:8efacce315ae 243 // Write, copy RAM to a flash sector
pspatel321 38:8efacce315ae 244 CMP(2, "Write") {
pspatel321 38:8efacce315ae 245 unsigned int index = strtoul(word[2], &next, 10); // Get index from command "profile write xxx"
pspatel321 38:8efacce315ae 246 if (index <= NUM_STORED_PROFILES && index > 0 && *next == 0) { // Check within bounds
pspatel321 38:8efacce315ae 247 bool s = Profile::saveProfile(index); // Write to flash
pspatel321 38:8efacce315ae 248 if (s) { // Successful?
pspatel321 38:8efacce315ae 249 op->profileModded = false; // Mark it as a fresh, unmodified profile
pspatel321 38:8efacce315ae 250 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker
pspatel321 38:8efacce315ae 251 return 1;
pspatel321 38:8efacce315ae 252 }
pspatel321 38:8efacce315ae 253 }
pspatel321 38:8efacce315ae 254 return -1;
pspatel321 38:8efacce315ae 255 }
pspatel321 38:8efacce315ae 256 // Load, read from flash to RAM
pspatel321 38:8efacce315ae 257 CMP(2, "Load") {
pspatel321 38:8efacce315ae 258 CMP(3, "default") { // The hard-coded flash profile (found in FreezeFrame.cpp)
pspatel321 38:8efacce315ae 259 Profile::loadProfile(0); // Copy default to RAM
pspatel321 38:8efacce315ae 260 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker
pspatel321 38:8efacce315ae 261 op->profileModded = false; // Mark it as a fresh, unmodified profile
pspatel321 38:8efacce315ae 262 return 1;
pspatel321 38:8efacce315ae 263 }
pspatel321 38:8efacce315ae 264 CMP(3, "freeze") { // Get the profile portion of the last freeze frame captured
pspatel321 38:8efacce315ae 265 if(Profile::loadProfile(-1)) { // Attemp to retrieve and copy to RAM
pspatel321 38:8efacce315ae 266 op->profileModded = false; // Mark it as a fresh, unmodified profile
pspatel321 38:8efacce315ae 267 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker
pspatel321 38:8efacce315ae 268 return 1;
pspatel321 38:8efacce315ae 269 }
pspatel321 38:8efacce315ae 270 }
pspatel321 38:8efacce315ae 271 int index = strtol(word[2], &next, 10); // Command was "profile load xxx"
pspatel321 38:8efacce315ae 272 if (index <= NUM_STORED_PROFILES && index >= -1 && *next == 0) { // Valid index found?
pspatel321 38:8efacce315ae 273 if (Profile::loadProfile(index)) { // Attempt to retrieve and copy to RAM
pspatel321 38:8efacce315ae 274 op->profileModded = false; // Mark it as a fresh, unmodified profile
pspatel321 38:8efacce315ae 275 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker
pspatel321 38:8efacce315ae 276 return 1;
pspatel321 38:8efacce315ae 277 }
pspatel321 38:8efacce315ae 278 }
pspatel321 38:8efacce315ae 279 return -1;
pspatel321 38:8efacce315ae 280 }
pspatel321 38:8efacce315ae 281 // View the profile only (NOT loaded to RAM, just display changed)
pspatel321 38:8efacce315ae 282 CMP(2, "view") {
pspatel321 38:8efacce315ae 283 CMP(3, "default") { // View the hard-coded flash profile
pspatel321 38:8efacce315ae 284 if (Profile::getProfile(&tempData.viewProfile, 0)) { // Attempt to fetch pointer
pspatel321 38:8efacce315ae 285 tempData.viewProfileNum = 0; // Mark the index of the fetched profile
pspatel321 38:8efacce315ae 286 return 1;
pspatel321 38:8efacce315ae 287 }
pspatel321 38:8efacce315ae 288 }
pspatel321 38:8efacce315ae 289 CMP(3, "freeze") { // View the profile portion only of the last captured freeze frame
pspatel321 38:8efacce315ae 290 if (Profile::getProfile(&tempData.viewProfile, -1)) { // Attempt to fetch pointer
pspatel321 38:8efacce315ae 291 tempData.viewProfileNum = -1; // Mark the index of the fetched profile
pspatel321 38:8efacce315ae 292 return 1;
pspatel321 38:8efacce315ae 293 }
pspatel321 38:8efacce315ae 294 }
pspatel321 38:8efacce315ae 295 CMP(3, "live") { // Revert to normal, live view
pspatel321 38:8efacce315ae 296 tempData.viewProfileNum = -2; // Mark live
pspatel321 38:8efacce315ae 297 tempData.viewProfile = NULL; // Clear the pointer
pspatel321 38:8efacce315ae 298 return 1;
pspatel321 38:8efacce315ae 299 }
pspatel321 38:8efacce315ae 300
pspatel321 38:8efacce315ae 301 int index = strtol(word[2], &next, 10); // Command was "profile view xxx"
pspatel321 38:8efacce315ae 302 if (index <= NUM_STORED_PROFILES && index >= -1 && *next == 0) { // Valid index found?
pspatel321 38:8efacce315ae 303 if (Profile::getProfile(&tempData.viewProfile, index)) { // Attempt to fetch pointer
pspatel321 38:8efacce315ae 304 tempData.viewProfileNum = index; // Mark the index of the fetched profile
pspatel321 38:8efacce315ae 305 return 1;
pspatel321 38:8efacce315ae 306 }
pspatel321 38:8efacce315ae 307 }
pspatel321 38:8efacce315ae 308 return -1;
pspatel321 38:8efacce315ae 309 }
pspatel321 38:8efacce315ae 310 }
pspatel321 34:18bcf276d3bf 311 }
pspatel321 34:18bcf276d3bf 312 return -1;
pspatel321 36:0afc0fc8f86b 313 }
pspatel321 38:8efacce315ae 314 // Called when AMS AIRs Mode message stops coming in
pspatel321 38:8efacce315ae 315 Timeout timer_AIRS_CLOSED;
pspatel321 38:8efacce315ae 316 void timeout_AIRS_CLOSED()
pspatel321 38:8efacce315ae 317 {
pspatel321 38:8efacce315ae 318 op->signals &= ~AIRS_CLOSED;
pspatel321 38:8efacce315ae 319 }
pspatel321 38:8efacce315ae 320
pspatel321 38:8efacce315ae 321 // Called when Charger CAN messages stop coming in
pspatel321 38:8efacce315ae 322 Timeout timer_CHARGER_DET;
pspatel321 38:8efacce315ae 323 void timeout_CHARGER_DET()
pspatel321 38:8efacce315ae 324 {
pspatel321 38:8efacce315ae 325 op->signals &= ~CHARGER_DET;
pspatel321 38:8efacce315ae 326 }
pspatel321 38:8efacce315ae 327
pspatel321 38:8efacce315ae 328 // Called when PCM messages stop coming in
pspatel321 38:8efacce315ae 329 Timeout timer_FANS;
pspatel321 38:8efacce315ae 330 void timeout_FANS()
pspatel321 38:8efacce315ae 331 {
pspatel321 38:8efacce315ae 332 op->dcdc.request.fan1 = 0;
pspatel321 38:8efacce315ae 333 op->dcdc.request.fan2 = 0;
pspatel321 38:8efacce315ae 334 }
pspatel321 38:8efacce315ae 335 Timeout timer_PUMPS;
pspatel321 38:8efacce315ae 336 void timeout_PUMPS()
pspatel321 38:8efacce315ae 337 {
pspatel321 38:8efacce315ae 338 op->dcdc.request.pump1 = 0;
pspatel321 38:8efacce315ae 339 op->dcdc.request.pump2 = 0;
pspatel321 38:8efacce315ae 340 }
pspatel321 38:8efacce315ae 341
pspatel321 38:8efacce315ae 342 #define REFRESH_TIMEOUT(NAME) \
pspatel321 38:8efacce315ae 343 timer_##NAME.detach(); \
pspatel321 38:8efacce315ae 344 timer_##NAME.attach(&timeout_##NAME, CAN_DEVICE_TIMEOUT);
pspatel321 38:8efacce315ae 345
pspatel321 38:8efacce315ae 346 bool serviceCAN(CANMessage* fromXbee)
pspatel321 38:8efacce315ae 347 {
pspatel321 38:8efacce315ae 348 CANMessage msg;
pspatel321 38:8efacce315ae 349 if (fromXbee != NULL) {
pspatel321 38:8efacce315ae 350 memcpy((void*)&msg, (void*)fromXbee, sizeof(CANMessage));
pspatel321 38:8efacce315ae 351 } else {
pspatel321 38:8efacce315ae 352 if (!can.rxRead(msg)) return false;
pspatel321 38:8efacce315ae 353 }
pspatel321 39:ddf38df9699e 354 xbee.receive(msg);
pspatel321 39:ddf38df9699e 355
pspatel321 38:8efacce315ae 356 // Redirect global car reset
pspatel321 38:8efacce315ae 357 if (msg.id == GLOBAL_CAR_RESET_RX_ID) msg.id = RESETCLEAR_RX_ID;
pspatel321 38:8efacce315ae 358
pspatel321 38:8efacce315ae 359 switch (msg.id) {
pspatel321 38:8efacce315ae 360 // Reset microntroller
pspatel321 38:8efacce315ae 361 case (RESET_RX_ID):
pspatel321 38:8efacce315ae 362 if (msg.len == 0) { // Length must = 0
pspatel321 38:8efacce315ae 363 NVIC_SystemReset();
pspatel321 38:8efacce315ae 364 CAN_SUCCESS
pspatel321 38:8efacce315ae 365 }
pspatel321 38:8efacce315ae 366 CAN_FAIL
pspatel321 38:8efacce315ae 367
pspatel321 39:ddf38df9699e 368
pspatel321 39:ddf38df9699e 369 // Clear non-volatile fault flags, then reset microcontroller
pspatel321 38:8efacce315ae 370 case (RESETCLEAR_RX_ID):
pspatel321 38:8efacce315ae 371 if (msg.len == 0) { // Length must = 0
pspatel321 38:8efacce315ae 372 FreezeFrame::clearError();
pspatel321 38:8efacce315ae 373 NVIC_SystemReset();
pspatel321 38:8efacce315ae 374 CAN_SUCCESS
pspatel321 38:8efacce315ae 375 }
pspatel321 38:8efacce315ae 376 CAN_FAIL
pspatel321 39:ddf38df9699e 377
pspatel321 39:ddf38df9699e 378 // Clear fault conditions
pspatel321 38:8efacce315ae 379 case (CLEAR_RX_ID):
pspatel321 39:ddf38df9699e 380 if (msg.len == 0) { // No data byte
pspatel321 39:ddf38df9699e 381 runTime::clearFaults();
pspatel321 39:ddf38df9699e 382 op->faultCode = 0;
pspatel321 39:ddf38df9699e 383 CAN_SUCCESS
pspatel321 38:8efacce315ae 384 }
pspatel321 38:8efacce315ae 385 CAN_FAIL
pspatel321 38:8efacce315ae 386
pspatel321 38:8efacce315ae 387 // Set the time (RTC)
pspatel321 38:8efacce315ae 388 case (TIME_RX_ID):
pspatel321 38:8efacce315ae 389 if (msg.len == 6*sizeof(char)) { // 6 Bytes
pspatel321 38:8efacce315ae 390 struct tm t; // Time & date struct
pspatel321 38:8efacce315ae 391 t.tm_mon = msg.data[0]; // Month in byte[0]
pspatel321 38:8efacce315ae 392 t.tm_mday = msg.data[1]; // Day
pspatel321 38:8efacce315ae 393 t.tm_year = msg.data[2]; // Year (offset from 2000)
pspatel321 38:8efacce315ae 394 t.tm_year = t.tm_year - 1900 + 2000; // Apply year index mod and offset
pspatel321 38:8efacce315ae 395 t.tm_mon = t.tm_mon - 1; // Month index mod
pspatel321 38:8efacce315ae 396 t.tm_hour = msg.data[3]; // Get hour of time in byte[3] (24 hr format)
pspatel321 38:8efacce315ae 397 t.tm_min = msg.data[4]; // Minutes
pspatel321 38:8efacce315ae 398 t.tm_sec = msg.data[5]; // Seconds
pspatel321 38:8efacce315ae 399 set_time(mktime(&t)); // Set RTC
pspatel321 38:8efacce315ae 400 time_t diff = time(NULL) - op->SysTime; // Old time to new time change
pspatel321 38:8efacce315ae 401 op->startTime += diff; // Shift the startTime to new timebase
pspatel321 38:8efacce315ae 402 CAN_SUCCESS
pspatel321 38:8efacce315ae 403 }
pspatel321 38:8efacce315ae 404 CAN_FAIL
pspatel321 38:8efacce315ae 405
pspatel321 38:8efacce315ae 406 // RAM and flash profile manipulations
pspatel321 38:8efacce315ae 407 case (PROFILE_RX_ID):
pspatel321 38:8efacce315ae 408 if (msg.len == 2*sizeof(char)) { // 2 command bytes
pspatel321 39:ddf38df9699e 409 int index=-2;
pspatel321 39:ddf38df9699e 410 for (int i = 0; i < NUM_STORED_PROFILES+1; i++) { // Get the profile number
pspatel321 39:ddf38df9699e 411 if (msg.data[1] == (1<<i)) index=i;
pspatel321 39:ddf38df9699e 412 }
pspatel321 39:ddf38df9699e 413 if (msg.data[1] == 1<<6) index=-1; // Special case for Freeze
pspatel321 39:ddf38df9699e 414 if (index == -2) { // Not matched to anything, fail
pspatel321 39:ddf38df9699e 415 CAN_FAIL
pspatel321 39:ddf38df9699e 416 }
pspatel321 38:8efacce315ae 417 if (msg.data[0] == 0) { // Load profile from a flash location to RAM
pspatel321 38:8efacce315ae 418 if (Profile::loadProfile(index)) { // Attempt to load (copy flash to RAM)
pspatel321 38:8efacce315ae 419 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker
pspatel321 38:8efacce315ae 420 op->profileModded = false; // Mark it as a fresh, unmodified profile
pspatel321 38:8efacce315ae 421 CAN_SUCCESS
pspatel321 38:8efacce315ae 422 }
pspatel321 38:8efacce315ae 423 }
pspatel321 38:8efacce315ae 424 if (msg.data[0] == 1) { // Write profile to flash from RAM
pspatel321 38:8efacce315ae 425 bool s = Profile::saveProfile(index); // Write profile to flash slot
pspatel321 38:8efacce315ae 426 if (s) {
pspatel321 38:8efacce315ae 427 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker
pspatel321 38:8efacce315ae 428 op->profileModded = false; // Mark it as a fresh, unmodified profile
pspatel321 38:8efacce315ae 429 CAN_SUCCESS
pspatel321 38:8efacce315ae 430 }
pspatel321 38:8efacce315ae 431 }
pspatel321 38:8efacce315ae 432 }
pspatel321 38:8efacce315ae 433 CAN_FAIL
pspatel321 38:8efacce315ae 434
pspatel321 39:ddf38df9699e 435 case FAN_CONTROL_RX_ID:
pspatel321 38:8efacce315ae 436 if (msg.len != 2*sizeof(float)) return false;
pspatel321 38:8efacce315ae 437 REFRESH_TIMEOUT(FANS)
pspatel321 38:8efacce315ae 438 op->dcdc.request.fan1 = *((float*)((void*)(&msg.data[0])));
pspatel321 38:8efacce315ae 439 op->dcdc.request.fan2 = *((float*)((void*)(&msg.data[4])));
pspatel321 38:8efacce315ae 440 return true;
pspatel321 38:8efacce315ae 441
pspatel321 39:ddf38df9699e 442 case PUMP_CONTROL_RX_ID:
pspatel321 38:8efacce315ae 443 if (msg.len != 2*sizeof(float)) return false;
pspatel321 38:8efacce315ae 444 REFRESH_TIMEOUT(PUMPS)
pspatel321 38:8efacce315ae 445 op->dcdc.request.pump1 = *((float*)((void*)(&msg.data[0])));
pspatel321 38:8efacce315ae 446 op->dcdc.request.pump2 = *((float*)((void*)(&msg.data[4])));
pspatel321 38:8efacce315ae 447 return true;
pspatel321 38:8efacce315ae 448
pspatel321 39:ddf38df9699e 449 case AMS_MODE_RX_ID:
pspatel321 38:8efacce315ae 450 if (msg.len != sizeof(char)) return false;
pspatel321 38:8efacce315ae 451 REFRESH_TIMEOUT(AIRS_CLOSED)
pspatel321 39:ddf38df9699e 452 if (msg.data[0] & 1<<3) { // AIRs closed?
pspatel321 38:8efacce315ae 453 op->signals |= AIRS_CLOSED;
pspatel321 38:8efacce315ae 454 } else {
pspatel321 38:8efacce315ae 455 op->signals &= ~AIRS_CLOSED;
pspatel321 38:8efacce315ae 456 }
pspatel321 38:8efacce315ae 457 return true;
pspatel321 39:ddf38df9699e 458 case CHARGER_ERR_RX_ID:
pspatel321 38:8efacce315ae 459 REFRESH_TIMEOUT(CHARGER_DET)
pspatel321 38:8efacce315ae 460 op->signals |= CHARGER_DET;
pspatel321 38:8efacce315ae 461 return true;
pspatel321 38:8efacce315ae 462 default:
pspatel321 38:8efacce315ae 463 break;
pspatel321 38:8efacce315ae 464 }
pspatel321 38:8efacce315ae 465 bool parsed=false;
pspatel321 38:8efacce315ae 466
pspatel321 38:8efacce315ae 467 CAN_CHANGE(chargeCurrent, PROFILE_CHARGECURRENT_RX_ID )
pspatel321 38:8efacce315ae 468 CAN_CHANGE(dischargeCurrent, PROFILE_DISCHARGECURRENT_RX_ID )
pspatel321 38:8efacce315ae 469 CAN_CHANGE(nominalCapacity, PROFILE_NOMINALCAPACITY_RX_ID )
pspatel321 38:8efacce315ae 470 CAN_CHANGE(glvBat_taps, PROFILE_GLVBATTAPS_RX_ID )
pspatel321 38:8efacce315ae 471 CAN_CHANGE(dcdcThreshold, PROFILE_DCDCONTHRESHOLD_RX_ID )
pspatel321 38:8efacce315ae 472 CAN_CHANGE(dcdcOverCurrent, PROFILE_DCDCOVERCURRENT_RX_ID )
pspatel321 38:8efacce315ae 473 CAN_CHANGE(dcdcStartDelay, PROFILE_DCDCSTARTDELAY_RX_ID )
pspatel321 38:8efacce315ae 474 CAN_CHANGE(dcdcStopDelay, PROFILE_DCDCSTOPDELAY_RX_ID )
pspatel321 38:8efacce315ae 475 CAN_CHANGE(dcdc_taps, PROFILE_DCDC_TAPS_RX_ID )
pspatel321 38:8efacce315ae 476 CAN_CHANGE(imdStartDelay, PROFILE_IMDSTARTDELAY_RX_ID )
pspatel321 39:ddf38df9699e 477 CAN_CHANGE(amsStartDelay, PROFILE_AMSSTARTDELAY_RX_ID )
pspatel321 38:8efacce315ae 478 CAN_CHANGE(internalOverTemp, PROFILE_INTERNALOVERTEMP_RX_ID )
pspatel321 38:8efacce315ae 479 CAN_CHANGE(CANnoAck, PROFILE_CANNOACK_RX_ID )
pspatel321 38:8efacce315ae 480 CAN_CHANGE(extendedSerial, PROFILE_EXTENDSERIAL_RX_ID )
pspatel321 38:8efacce315ae 481 CAN_CHANGE(CANtxSize, PROFILE_CANTXSIZE_RX_ID )
pspatel321 38:8efacce315ae 482 CAN_CHANGE(CANrxSize, PROFILE_CANRXSIZE_RX_ID )
pspatel321 38:8efacce315ae 483 CAN_CHANGE(SerialBaud, PROFILE_SERIALBAUD_RX_ID )
pspatel321 38:8efacce315ae 484 CAN_CHANGE(SerialTxSize, PROFILE_SERIALTXSIZE_RX_ID )
pspatel321 38:8efacce315ae 485
pspatel321 38:8efacce315ae 486 if (!parsed) return false;
pspatel321 38:8efacce315ae 487
pspatel321 38:8efacce315ae 488 if (msg.id == PROFILE_NOMINALCAPACITY_RX_ID ) return glvBat.changeCapacity(param->nominalCapacity)?1:-1;
pspatel321 38:8efacce315ae 489 if (msg.id == PROFILE_GLVBATTAPS_RX_ID ) return glvBat.size(param->glvBat_taps)?1:-1;
pspatel321 38:8efacce315ae 490 if (msg.id == PROFILE_DCDC_TAPS_RX_ID ) return dcdc.size(param->dcdc_taps)?1:-1;
pspatel321 38:8efacce315ae 491 if (msg.id == PROFILE_CANTXSIZE_RX_ID ) return can.txSize(param->CANtxSize)?1:-1;
pspatel321 38:8efacce315ae 492 if (msg.id == PROFILE_CANRXSIZE_RX_ID ) return can.rxSize(param->CANrxSize)?1:-1;
pspatel321 38:8efacce315ae 493 if (msg.id == PROFILE_SERIALBAUD_RX_ID ) pc.baud(param->SerialBaud);
pspatel321 38:8efacce315ae 494 if (msg.id == PROFILE_SERIALTXSIZE_RX_ID ) return (pc.txBufferSetSize(param->SerialTxSize) == 0)?1:-1;
pspatel321 38:8efacce315ae 495
pspatel321 38:8efacce315ae 496 return true;
pspatel321 38:8efacce315ae 497 }
pspatel321 38:8efacce315ae 498 // Check for incoming messages from the xbees, relay them to the CAN function and send them out on the bus
pspatel321 39:ddf38df9699e 499 /*
pspatel321 38:8efacce315ae 500 bool receiveMsgXbee()
pspatel321 38:8efacce315ae 501 {
pspatel321 38:8efacce315ae 502 CANMessage msg;
pspatel321 38:8efacce315ae 503 if (xbeeRelay.receive(msg)) { // Incoming CAN message string received
pspatel321 38:8efacce315ae 504 if (!can.txWrite(msg)) op->faultCode |= CAN_FAULT; // Send it out on the CAN bus
pspatel321 38:8efacce315ae 505 serviceCAN(&msg); // Send it into the local serviceCAN routine
pspatel321 38:8efacce315ae 506 return true;
pspatel321 38:8efacce315ae 507 } else return false;
pspatel321 39:ddf38df9699e 508 }*/
pspatel321 36:0afc0fc8f86b 509
pspatel321 36:0afc0fc8f86b 510 void inCommands::thread_getInputs(void const* args)
pspatel321 36:0afc0fc8f86b 511 {
pspatel321 36:0afc0fc8f86b 512 while(1) {
pspatel321 38:8efacce315ae 513 serviceCAN(0);
pspatel321 39:ddf38df9699e 514 //receiveMsgXbee();
pspatel321 36:0afc0fc8f86b 515
pspatel321 38:8efacce315ae 516 int ret = serviceSerial();
pspatel321 36:0afc0fc8f86b 517 if (ret == -1) tempData.parseGoodChar = 'x';
pspatel321 36:0afc0fc8f86b 518 if (ret == 1) tempData.parseGoodChar = 251;
pspatel321 36:0afc0fc8f86b 519 osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<2); // Signal watchdog thread
pspatel321 36:0afc0fc8f86b 520 }
pspatel321 30:91af74a299e1 521 }