Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed CANBuffer Watchdog MODSERIAL mbed-rtos xbeeRelay IAP
Fork of SystemManagement by
inCommands.cpp
00001 #include "inCommands.h" 00002 #include "runTime.h" 00003 #include "inMacros.h" 00004 00005 // Compare string to a word in the serial input, shorter to type 00006 #define CMP(w, string) if (!strcasecmp(word[w-1], string)) 00007 00008 // Serial input 00009 int serviceSerial() 00010 { 00011 static int end = 0; // End of string position 00012 00013 int c=0; 00014 if (pc.readable()) c = pc.getc(); 00015 if (c == -1 || c == 0) return 0; 00016 00017 char b = c; // Casted to char type 00018 bool process = false; // Is string complete (ready to parse)? 00019 00020 if (b == '\n' || b == '\r') { // Enter key was pressed, dump for processing 00021 tempData.inputStr[end] = 0; // Null terminate 00022 end = 0; // Reset to start 00023 process = true; // Flag for processing 00024 00025 } else if (b == '\b' || b == 127) { // Backspace or delete 00026 if (end > 0) end--; // Move back one char 00027 tempData.inputStr[end] = 0; // Erase char 00028 00029 } else if (b > 31 && b < 127) { // New valid displayable char 00030 tempData.inputStr[end++] = b; // Add to buffer 00031 tempData.inputStr[end] = 0; // Add null terminator 00032 if (end >= RX_SIZE) { 00033 end = 0; // Reset end location 00034 process = true; // Flag for processing 00035 } 00036 } 00037 // Continue to parsing section only if flagged as complete and string not empty 00038 if (!process || strlen((char*)tempData.inputStr) == 0) return 0; 00039 00040 static char word[3][RX_SIZE+1]; // Hold 3 words 00041 int pieces = sscanf(tempData.inputStr, "%s %s %s", word[0], word[1], word[2]); // Populate words 00042 tempData.inputStr[0] = 0; // Empty the string displayed on screen 00043 char *next; // Used by strtof and strtoul 00044 00045 // One word commands 00046 if (pieces == 1) { 00047 // Reset the microcontroller 00048 CMP(1, "reset") { 00049 NVIC_SystemReset(); 00050 return 1; 00051 } 00052 // Clear non-volatile fault flags, then reset the microcontroller 00053 CMP(1, "resetClear") { 00054 runTime::clearFaults(); 00055 NVIC_SystemReset(); 00056 return 1; 00057 } 00058 return -1; 00059 } 00060 // Two word commands 00061 if (pieces == 2) { 00062 // Change the serial dashboard display mode 00063 CMP(1, "display") { 00064 CMP(2, "compact") { 00065 if (param->change_extendedSerial(0)) { 00066 op->profileModded=true; 00067 return 1; // Change function defined by macro 00068 } 00069 } 00070 CMP(2, "extended") { 00071 if (param->change_extendedSerial(1)) { 00072 op->profileModded=true; 00073 return 1; // Change function defined by macro 00074 } 00075 } 00076 } 00077 // Change ACK setting for CAN (noAck allows testing of CAN without other nodes) 00078 CMP(1, "CANack") { 00079 CMP(2, "noack") { // NoAck test mode 00080 if (param->change_CANnoAck(1)) { 00081 op->profileModded=true; 00082 return 1; 00083 } 00084 } 00085 CMP(2, "ack") { // Normal CAN protocol 00086 if (param->change_CANnoAck(0)) { 00087 op->profileModded=true; 00088 return 1; 00089 } 00090 } 00091 return -1; 00092 } 00093 // Artificially capture a freeze frame, save to flash 00094 CMP(1, "capture") { 00095 CMP(2, "freeze") { 00096 if (!FreezeFrame::getError()) { // Only allow capture if spot available (last error frame was cleared manually) 00097 if (FreezeFrame::writeFrame()) { // Copy RAM frame to freezree sector in flash 00098 return 1; 00099 } 00100 } 00101 } 00102 return -1; 00103 } 00104 // Clear fault conditions 00105 CMP(1, "clear") { 00106 CMP(2, "freeze") { // Clear the freeze frame (mark as read) 00107 FreezeFrame::clearError(); // Clear the non-volatile error marker 00108 return 1; 00109 } 00110 CMP(2, "faults") { // Clear everything 00111 runTime::clearFaults(); 00112 return 1; 00113 } 00114 return -1; 00115 } 00116 // Change the display contents 00117 CMP(1, "view") { 00118 CMP(2, "freeze") { // View the last stored freeze frame 00119 if (FreezeFrame::getFrame(&tempData.freeze)) { // Fetch the pointer from flash 00120 return 1; 00121 } 00122 } 00123 CMP(2, "live") { // View live data from RAM 00124 tempData.freeze = NULL; // Zero the pointer 00125 return 1; 00126 } 00127 return -1; 00128 } 00129 // Artificially update the SOC (battery life %) 00130 CMP(1, "SOC") { 00131 CMP(2, "Reset") { // Command was "SOC reset" - reset to 100%, do this after a full charge 00132 glvBat.resetToSOC(1); 00133 return 1; 00134 } 00135 float soc = strtod(word[1], &next); // Command was "SOC xxx" where xxx is float between 0 and 1 00136 if (*next == 0) { 00137 if (glvBat.resetToSOC(soc)) return 1; 00138 } 00139 return -1; 00140 } 00141 // Artificially update the AmpHours count (linked with SOC) 00142 CMP(1, "Ah") { 00143 CMP(2, "Reset") { // Command was "Amphours reset", equivalent to "SOC reset" 00144 glvBat.resetToSOC(1); 00145 return 1; 00146 } 00147 float ah = strtod(word[1], &next); // Command was "Amphours xxx" where xxx is a float in amphours 00148 if (*next == 0) { 00149 if (glvBat.resetToAh(ah)) return 1; 00150 } 00151 return -1; 00152 } 00153 // Change the battery capacity setting for calculating Amphours 00154 CMP(1, "Capacity") { 00155 float cap = strtod(word[1], &next); // Command was "SOC xxx" where xxx is float between 0 and 1 00156 if (*next == 0) { 00157 if (glvBat.changeCapacity(cap)) return 1; 00158 } 00159 return -1; 00160 } 00161 00162 bool parsed=false; 00163 00164 CHANGE_VAR("GLVchar", chargeCurrent) 00165 CHANGE_VAR("GLVdisch", dischargeCurrent) 00166 CHANGE_VAR("GLVnomCap", nominalCapacity) 00167 CHANGE_VAR("GLVtaps", glvBat_taps) 00168 CHANGE_VAR("dcdcThres", dcdcThreshold) 00169 CHANGE_VAR("dcdcOver", dcdcOverCurrent) 00170 CHANGE_VAR("dcdcStart", dcdcStartDelay) 00171 CHANGE_VAR("dcdcStop", dcdcStopDelay) 00172 CHANGE_VAR("dcdcTaps", dcdc_taps) 00173 CHANGE_VAR("imdStart", imdStartDelay) 00174 CHANGE_VAR("amsStart", amsStartDelay) 00175 CHANGE_VAR("IntOverT", internalOverTemp) 00176 CHANGE_VAR("CANtxSize", CANtxSize) 00177 CHANGE_VAR("CANrxSize", CANrxSize) 00178 CHANGE_VAR("SerialBaud", SerialBaud) 00179 CHANGE_VAR("SerialTx", SerialTxSize) 00180 CHANGE_VAR("CANack", CANnoAck) 00181 00182 if (!parsed) return -1; 00183 00184 CMP(1, "GLVnomCap") return glvBat.changeCapacity(param->nominalCapacity)?1:-1; 00185 CMP(1, "GLVtaps") return glvBat.size(param->glvBat_taps)?1:-1; 00186 CMP(1, "dcdcTaps") return dcdc.size(param->dcdc_taps)?1:-1; 00187 CMP(1, "CANtxSize") return can.txSize(param->CANtxSize)?1:-1; 00188 CMP(1, "CANrxSize") return can.rxSize(param->CANrxSize)?1:-1; 00189 CMP(1, "SerialBaud") pc.baud(param->SerialBaud); 00190 CMP(1, "SerialTx") return (pc.txBufferSetSize(param->SerialTxSize) == 0)?1:-1; 00191 00192 return 1; 00193 } 00194 // Three word commands 00195 if (pieces == 3) { 00196 // Fan Duty 00197 CMP(1, "Fan") { 00198 float val1 = strtod(word[1], &next); 00199 if (*next == 0) { 00200 float val2 = strtod(word[2], &next); 00201 if (*next == 0) { 00202 op->dcdc.request.fan1 = val1; 00203 op->dcdc.request.fan2 = val2; 00204 return 1; 00205 } 00206 } 00207 return -1; 00208 } 00209 00210 // Pump Duty 00211 CMP(1, "Pump") { 00212 float val1 = strtod(word[1], &next); 00213 if (*next == 0) { 00214 float val2 = strtod(word[2], &next); 00215 if (*next == 0) { 00216 op->dcdc.request.pump1 = val1; 00217 op->dcdc.request.pump2 = val2; 00218 return 1; 00219 } 00220 } 00221 return -1; 00222 } 00223 // Set the system time (RTC) 00224 CMP(1, "Time") { 00225 struct tm t; // Time & date struct 00226 int ret = sscanf(word[1], "%d/%d/%d", &t.tm_mon, &t.tm_mday, &t.tm_year); // Populate date 00227 t.tm_year = t.tm_year - 1900; // Year mod to fix 0 index 00228 t.tm_mon = t.tm_mon - 1; // Month mod to fix 0 index 00229 if (ret == 3) { // All 3 items found 00230 ret = sscanf(word[2], "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); // Populate time 00231 if (ret == 3) { // All 3 items found 00232 set_time(mktime(&t)); // Set the RTC 00233 time_t diff = time(NULL) - op->SysTime; // Get change in time from old to new 00234 op->startTime += diff; // Shift the startTime to new timebase 00235 return 1; 00236 } 00237 } 00238 return -1; 00239 } 00240 00241 // Profile manipulations between RAM and flash 00242 CMP(1, "Profile") { 00243 // Write, copy RAM to a flash sector 00244 CMP(2, "Write") { 00245 unsigned int index = strtoul(word[2], &next, 10); // Get index from command "profile write xxx" 00246 if (index <= NUM_STORED_PROFILES && index > 0 && *next == 0) { // Check within bounds 00247 bool s = Profile::saveProfile(index); // Write to flash 00248 if (s) { // Successful? 00249 op->profileModded = false; // Mark it as a fresh, unmodified profile 00250 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker 00251 return 1; 00252 } 00253 } 00254 return -1; 00255 } 00256 // Load, read from flash to RAM 00257 CMP(2, "Load") { 00258 CMP(3, "default") { // The hard-coded flash profile (found in FreezeFrame.cpp) 00259 Profile::loadProfile(0); // Copy default to RAM 00260 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker 00261 op->profileModded = false; // Mark it as a fresh, unmodified profile 00262 return 1; 00263 } 00264 CMP(3, "freeze") { // Get the profile portion of the last freeze frame captured 00265 if(Profile::loadProfile(-1)) { // Attemp to retrieve and copy to RAM 00266 op->profileModded = false; // Mark it as a fresh, unmodified profile 00267 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker 00268 return 1; 00269 } 00270 } 00271 int index = strtol(word[2], &next, 10); // Command was "profile load xxx" 00272 if (index <= NUM_STORED_PROFILES && index >= -1 && *next == 0) { // Valid index found? 00273 if (Profile::loadProfile(index)) { // Attempt to retrieve and copy to RAM 00274 op->profileModded = false; // Mark it as a fresh, unmodified profile 00275 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker 00276 return 1; 00277 } 00278 } 00279 return -1; 00280 } 00281 // View the profile only (NOT loaded to RAM, just display changed) 00282 CMP(2, "view") { 00283 CMP(3, "default") { // View the hard-coded flash profile 00284 if (Profile::getProfile(&tempData.viewProfile, 0)) { // Attempt to fetch pointer 00285 tempData.viewProfileNum = 0; // Mark the index of the fetched profile 00286 return 1; 00287 } 00288 } 00289 CMP(3, "freeze") { // View the profile portion only of the last captured freeze frame 00290 if (Profile::getProfile(&tempData.viewProfile, -1)) { // Attempt to fetch pointer 00291 tempData.viewProfileNum = -1; // Mark the index of the fetched profile 00292 return 1; 00293 } 00294 } 00295 CMP(3, "live") { // Revert to normal, live view 00296 tempData.viewProfileNum = -2; // Mark live 00297 tempData.viewProfile = NULL; // Clear the pointer 00298 return 1; 00299 } 00300 00301 int index = strtol(word[2], &next, 10); // Command was "profile view xxx" 00302 if (index <= NUM_STORED_PROFILES && index >= -1 && *next == 0) { // Valid index found? 00303 if (Profile::getProfile(&tempData.viewProfile, index)) { // Attempt to fetch pointer 00304 tempData.viewProfileNum = index; // Mark the index of the fetched profile 00305 return 1; 00306 } 00307 } 00308 return -1; 00309 } 00310 } 00311 } 00312 return -1; 00313 } 00314 // Called when AMS AIRs Mode message stops coming in 00315 Timeout timer_AIRS_CLOSED; 00316 void timeout_AIRS_CLOSED() 00317 { 00318 op->signals &= ~AIRS_CLOSED; 00319 } 00320 00321 // Called when Charger CAN messages stop coming in 00322 Timeout timer_CHARGER_DET; 00323 void timeout_CHARGER_DET() 00324 { 00325 op->signals &= ~CHARGER_DET; 00326 } 00327 00328 // Called when PCM messages stop coming in 00329 Timeout timer_FANS; 00330 void timeout_FANS() 00331 { 00332 op->dcdc.request.fan1 = 0; 00333 op->dcdc.request.fan2 = 0; 00334 } 00335 Timeout timer_PUMPS; 00336 void timeout_PUMPS() 00337 { 00338 op->dcdc.request.pump1 = 0; 00339 op->dcdc.request.pump2 = 0; 00340 } 00341 00342 #define REFRESH_TIMEOUT(NAME) \ 00343 timer_##NAME.detach(); \ 00344 timer_##NAME.attach(&timeout_##NAME, CAN_DEVICE_TIMEOUT); 00345 00346 bool serviceCAN(CANMessage* fromXbee) 00347 { 00348 CANMessage msg; 00349 if (fromXbee != NULL) { 00350 memcpy((void*)&msg, (void*)fromXbee, sizeof(CANMessage)); 00351 } else { 00352 if (!can.rxRead(msg)) return false; 00353 } 00354 xbee.receive(msg); 00355 00356 // Redirect global car reset 00357 if (msg.id == GLOBAL_CAR_RESET_RX_ID) msg.id = RESETCLEAR_RX_ID; 00358 00359 switch (msg.id) { 00360 // Reset microntroller 00361 case (RESET_RX_ID): 00362 if (msg.len == 0) { // Length must = 0 00363 NVIC_SystemReset(); 00364 CAN_SUCCESS 00365 } 00366 CAN_FAIL 00367 00368 00369 // Clear non-volatile fault flags, then reset microcontroller 00370 case (RESETCLEAR_RX_ID): 00371 if (msg.len == 0) { // Length must = 0 00372 FreezeFrame::clearError(); 00373 NVIC_SystemReset(); 00374 CAN_SUCCESS 00375 } 00376 CAN_FAIL 00377 00378 // Clear fault conditions 00379 case (CLEAR_RX_ID): 00380 if (msg.len == 0) { // No data byte 00381 runTime::clearFaults(); 00382 op->faultCode = 0; 00383 CAN_SUCCESS 00384 } 00385 CAN_FAIL 00386 00387 // Set the time (RTC) 00388 case (TIME_RX_ID): 00389 if (msg.len == 6*sizeof(char)) { // 6 Bytes 00390 struct tm t; // Time & date struct 00391 t.tm_mon = msg.data[0]; // Month in byte[0] 00392 t.tm_mday = msg.data[1]; // Day 00393 t.tm_year = msg.data[2]; // Year (offset from 2000) 00394 t.tm_year = t.tm_year - 1900 + 2000; // Apply year index mod and offset 00395 t.tm_mon = t.tm_mon - 1; // Month index mod 00396 t.tm_hour = msg.data[3]; // Get hour of time in byte[3] (24 hr format) 00397 t.tm_min = msg.data[4]; // Minutes 00398 t.tm_sec = msg.data[5]; // Seconds 00399 set_time(mktime(&t)); // Set RTC 00400 time_t diff = time(NULL) - op->SysTime; // Old time to new time change 00401 op->startTime += diff; // Shift the startTime to new timebase 00402 CAN_SUCCESS 00403 } 00404 CAN_FAIL 00405 00406 // RAM and flash profile manipulations 00407 case (PROFILE_RX_ID): 00408 if (msg.len == 2*sizeof(char)) { // 2 command bytes 00409 int index=-2; 00410 for (int i = 0; i < NUM_STORED_PROFILES+1; i++) { // Get the profile number 00411 if (msg.data[1] == (1<<i)) index=i; 00412 } 00413 if (msg.data[1] == 1<<6) index=-1; // Special case for Freeze 00414 if (index == -2) { // Not matched to anything, fail 00415 CAN_FAIL 00416 } 00417 if (msg.data[0] == 0) { // Load profile from a flash location to RAM 00418 if (Profile::loadProfile(index)) { // Attempt to load (copy flash to RAM) 00419 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker 00420 op->profileModded = false; // Mark it as a fresh, unmodified profile 00421 CAN_SUCCESS 00422 } 00423 } 00424 if (msg.data[0] == 1) { // Write profile to flash from RAM 00425 bool s = Profile::saveProfile(index); // Write profile to flash slot 00426 if (s) { 00427 op->profileIndex = Profile::usingProfile(); // Change the currently loaded profile marker 00428 op->profileModded = false; // Mark it as a fresh, unmodified profile 00429 CAN_SUCCESS 00430 } 00431 } 00432 } 00433 CAN_FAIL 00434 00435 case FAN_CONTROL_RX_ID: 00436 if (msg.len != 2*sizeof(float)) return false; 00437 REFRESH_TIMEOUT(FANS) 00438 op->dcdc.request.fan1 = *((float*)((void*)(&msg.data[0]))); 00439 op->dcdc.request.fan2 = *((float*)((void*)(&msg.data[4]))); 00440 return true; 00441 00442 case PUMP_CONTROL_RX_ID: 00443 if (msg.len != 2*sizeof(float)) return false; 00444 REFRESH_TIMEOUT(PUMPS) 00445 op->dcdc.request.pump1 = *((float*)((void*)(&msg.data[0]))); 00446 op->dcdc.request.pump2 = *((float*)((void*)(&msg.data[4]))); 00447 return true; 00448 00449 case AMS_MODE_RX_ID: 00450 if (msg.len != sizeof(char)) return false; 00451 REFRESH_TIMEOUT(AIRS_CLOSED) 00452 if (msg.data[0] & 1<<3) { // AIRs closed? 00453 op->signals |= AIRS_CLOSED; 00454 } else { 00455 op->signals &= ~AIRS_CLOSED; 00456 } 00457 return true; 00458 case CHARGER_ERR_RX_ID: 00459 REFRESH_TIMEOUT(CHARGER_DET) 00460 op->signals |= CHARGER_DET; 00461 return true; 00462 default: 00463 break; 00464 } 00465 bool parsed=false; 00466 00467 CAN_CHANGE(chargeCurrent, PROFILE_CHARGECURRENT_RX_ID ) 00468 CAN_CHANGE(dischargeCurrent, PROFILE_DISCHARGECURRENT_RX_ID ) 00469 CAN_CHANGE(nominalCapacity, PROFILE_NOMINALCAPACITY_RX_ID ) 00470 CAN_CHANGE(glvBat_taps, PROFILE_GLVBATTAPS_RX_ID ) 00471 CAN_CHANGE(dcdcThreshold, PROFILE_DCDCONTHRESHOLD_RX_ID ) 00472 CAN_CHANGE(dcdcOverCurrent, PROFILE_DCDCOVERCURRENT_RX_ID ) 00473 CAN_CHANGE(dcdcStartDelay, PROFILE_DCDCSTARTDELAY_RX_ID ) 00474 CAN_CHANGE(dcdcStopDelay, PROFILE_DCDCSTOPDELAY_RX_ID ) 00475 CAN_CHANGE(dcdc_taps, PROFILE_DCDC_TAPS_RX_ID ) 00476 CAN_CHANGE(imdStartDelay, PROFILE_IMDSTARTDELAY_RX_ID ) 00477 CAN_CHANGE(amsStartDelay, PROFILE_AMSSTARTDELAY_RX_ID ) 00478 CAN_CHANGE(internalOverTemp, PROFILE_INTERNALOVERTEMP_RX_ID ) 00479 CAN_CHANGE(CANnoAck, PROFILE_CANNOACK_RX_ID ) 00480 CAN_CHANGE(extendedSerial, PROFILE_EXTENDSERIAL_RX_ID ) 00481 CAN_CHANGE(CANtxSize, PROFILE_CANTXSIZE_RX_ID ) 00482 CAN_CHANGE(CANrxSize, PROFILE_CANRXSIZE_RX_ID ) 00483 CAN_CHANGE(SerialBaud, PROFILE_SERIALBAUD_RX_ID ) 00484 CAN_CHANGE(SerialTxSize, PROFILE_SERIALTXSIZE_RX_ID ) 00485 00486 if (!parsed) return false; 00487 00488 if (msg.id == PROFILE_NOMINALCAPACITY_RX_ID ) return glvBat.changeCapacity(param->nominalCapacity)?1:-1; 00489 if (msg.id == PROFILE_GLVBATTAPS_RX_ID ) return glvBat.size(param->glvBat_taps)?1:-1; 00490 if (msg.id == PROFILE_DCDC_TAPS_RX_ID ) return dcdc.size(param->dcdc_taps)?1:-1; 00491 if (msg.id == PROFILE_CANTXSIZE_RX_ID ) return can.txSize(param->CANtxSize)?1:-1; 00492 if (msg.id == PROFILE_CANRXSIZE_RX_ID ) return can.rxSize(param->CANrxSize)?1:-1; 00493 if (msg.id == PROFILE_SERIALBAUD_RX_ID ) pc.baud(param->SerialBaud); 00494 if (msg.id == PROFILE_SERIALTXSIZE_RX_ID ) return (pc.txBufferSetSize(param->SerialTxSize) == 0)?1:-1; 00495 00496 return true; 00497 } 00498 // Check for incoming messages from the xbees, relay them to the CAN function and send them out on the bus 00499 /* 00500 bool receiveMsgXbee() 00501 { 00502 CANMessage msg; 00503 if (xbeeRelay.receive(msg)) { // Incoming CAN message string received 00504 if (!can.txWrite(msg)) op->faultCode |= CAN_FAULT; // Send it out on the CAN bus 00505 serviceCAN(&msg); // Send it into the local serviceCAN routine 00506 return true; 00507 } else return false; 00508 }*/ 00509 00510 void inCommands::thread_getInputs(void const* args) 00511 { 00512 while(1) { 00513 serviceCAN(0); 00514 //receiveMsgXbee(); 00515 00516 int ret = serviceSerial(); 00517 if (ret == -1) tempData.parseGoodChar = 'x'; 00518 if (ret == 1) tempData.parseGoodChar = 251; 00519 osSignalSet((osThreadId)(tempData.wdtThreadId), 1<<2); // Signal watchdog thread 00520 } 00521 }
Generated on Fri Jul 15 2022 06:07:18 by
1.7.2
