char net_msgp_tpms(char stat) { char k, *s; long p; #if 0 if ((car_tpms_t[0] == 0) && (car_tpms_t[1] == 0) && (car_tpms_t[2] == 0) && (car_tpms_t[3] == 0)) return stat; // No TPMS, no report // ...new stat fn: No TMPS = one report with stale=-1 #endif s = stp_rom(net_scratchpad, "MP-0 W"); for (k = 0; k < 4; k++) { if (car_tpms_t[k] > 0) { p = (long) ((float) car_tpms_p[k] / 0.2755); s = stp_l2f(s, NULL, p, 1); s = stp_i(s, ",", car_tpms_t[k] - 40); s = stp_rom(s, ","); } else { s = stp_rom(s, "0,0,"); } } s = stp_i(s, NULL, car_stale_tpms); return net_msg_encode_statputs(stat, &crc_tpms); }
char net_msgp_gps(char stat) { char *s; s = stp_latlon(net_scratchpad, "MP-0 L", car_latitude); s = stp_latlon(s, ",", car_longitude); s = stp_i(s, ",", car_direction); s = stp_i(s, ",", car_altitude); s = stp_i(s, ",", car_gpslock); s = stp_i(s, ",", car_stale_gps); return net_msg_encode_statputs(stat, &crc_gps); }
BOOL net_sms_handle_diag(char *caller, char *command, char *arguments) { char *s; if (sys_features[FEATURE_CARBITS] & FEATURE_CB_SOUT_SMS) return FALSE; net_send_sms_start(caller); s = stp_rom(net_scratchpad, "DIAG:"); s = stp_i(s, "\n RED Led:", led_code[OVMS_LED_RED]); s = stp_i(s, "\n GRN Led:", led_code[OVMS_LED_GRN]); s = stp_x(s, "\n NET State:0x", net_state); if (car_12vline > 0) { s = stp_l2f(s, "\n 12V Line:", car_12vline, 1); s = stp_l2f(s, " ref=", car_12vline_ref, 1); } #ifndef OVMS_NO_CRASHDEBUG /* DEBUG / QA stats: output crash counter and decode last reason: */ s = stp_i(s, "\n Crashes:", debug_crashcnt); if (debug_crashreason) { s = stp_rom(s, "\n ..last:"); if (debug_crashreason & 0x01) s = stp_rom(s, " BOR"); // Brown Out Reset if (debug_crashreason & 0x02) s = stp_rom(s, " POR"); // Power On Reset if (debug_crashreason & 0x04) s = stp_rom(s, " PD"); // Power-Down Detection if (debug_crashreason & 0x08) s = stp_rom(s, " TO"); // Watchdog Timeout if (debug_crashreason & 0x10) s = stp_rom(s, " RI"); // Reset Instruction if (debug_crashreason & 0x20) s = stp_rom(s, " STKFUL"); // Stack overflow if (debug_crashreason & 0x40) s = stp_rom(s, " STKUNF"); // Stack underflow s = stp_i(s, " - ", debug_checkpoint); } #endif // OVMS_NO_CRASHDEBUG net_puts_ram(net_scratchpad); return TRUE; }
BOOL net_sms_handle_paramsq(char *caller, char *command, char *arguments) { unsigned char k, splen, msglen; char *p, *s; if (sys_features[FEATURE_CARBITS]&FEATURE_CB_SOUT_SMS) return FALSE; net_send_sms_start(caller); net_puts_rom("Params:"); msglen=7; for (k=0; k<PARAM_MAX; k++) { p = par_get(k); if (*p != 0) { s = stp_i(net_scratchpad, "\n", k); s = stp_s(s, ":", p); splen = s - net_scratchpad; if((msglen+splen) > 160) { // SMS becomes too long, finish & start next: net_send_sms_finish(); delay100(20); net_send_sms_start(caller); net_puts_rom("Params:"); msglen=7+splen; } net_puts_ram(net_scratchpad); } } return TRUE; }
BOOL net_sms_handle_temps(char *caller, char *command, char *arguments) { char *s; s = stp_i(net_scratchpad, "Temperatures:\r\n Ambient: ", car_ambient_temp); s = stp_i(s, "C\r\n PEM: ", car_tpem); s = stp_i(s, "C\r\n Motor: ", car_tmotor); s = stp_i(s, "C\r\n Battery: ", car_tbattery); s = stp_rom(s, "C"); if ((car_stale_ambient==0)||(car_stale_temps==0)) s = stp_rom(s, "\r\n (stale)"); net_send_sms_start(caller); net_puts_ram(net_scratchpad); return TRUE; }
void net_msg_socalert(void) { char *s; s = stp_i(net_scratchpad, "MP-0 PAALERT!!! CRITICAL SOC LEVEL APPROACHED (", car_SOC); // 95% s = stp_rom(s, "% SOC)"); net_msg_encode_puts(); }
BOOL net_sms_handle_version(char *caller, char *command, char *arguments) { unsigned char hwv = 1; char *s; #ifdef OVMS_HW_V2 hwv = 2; #endif s = stp_i(net_scratchpad, "OVMS Firmware version: ", ovms_firmware[0]); s = stp_i(s, ".", ovms_firmware[1]); s = stp_i(s, ".", ovms_firmware[2]); s = stp_s(s, "/", par_get(PARAM_VEHICLETYPE)); if (vehicle_version) s = stp_rom(s, vehicle_version); s = stp_i(s, "/V", hwv); net_send_sms_start(caller); net_puts_ram(net_scratchpad); return TRUE; }
BOOL net_sms_handle_featuresq(char *caller, char *command, char *arguments) { unsigned char k; char *s; if (sys_features[FEATURE_CARBITS]&FEATURE_CB_SOUT_SMS) return FALSE; net_send_sms_start(caller); net_puts_rom("Features:"); for (k=0; k<FEATURES_MAX; k++) { if (sys_features[k] != 0) { s = stp_i(net_scratchpad, "\r\n ", k); s = stp_i(s, ":", sys_features[k]); net_puts_ram(net_scratchpad); } } return TRUE; }
void net_sms_socalert(char* number) { char *s; delay100(10); net_send_sms_start(number); s = stp_i(net_scratchpad, "ALERT!!! CRITICAL SOC LEVEL APPROACHED (", car_SOC); // 95% s = stp_rom(s, "% SOC)"); net_puts_ram(net_scratchpad); net_send_sms_finish(); delay100(5); }
void net_msg_reply_ussd(char *buf, unsigned char buflen) { // called from net_state_activity() // buf contains a "+CUSD:" USSD command result // parse and return as command reply: char *s, *t = NULL; // Server not ready? abort // TODO: store, resend when server is connected if ((!net_msg_serverok) || (!buf) || (!buflen)) return; // isolate USSD reply text if (t = memchr((void *) buf, '"', buflen)) { ++t; buflen -= (t - buf); buf = t; // start of USSD string while ((*t) && (*t != '"') && ((t - buf) < buflen)) { if (*t == ',') // "escape" comma for MP-0 *t = '.'; t++; } *t = 0; // end of USSD string } // format reply: s = stp_i(net_scratchpad, "MP-0 c", CMD_SendUSSD); if (t) s = stp_s(s, ",0,", buf); else s = stp_rom(s, ",1,Invalid USSD result"); // send reply: if (net_msg_sendpending > 0) { delay100(20); // HACK... should buffer & retry later... but RAM is precious s = NULL; // flag } net_msg_start(); net_msg_encode_puts(); net_msg_send(); if (!s) delay100(20); // HACK: give modem additional time if there was sendpending>0 }
void net_msg_reply_ussd(char *buf) { // called from net_state_activity() // buf contains a "+CUSD:" USSD command result // parse and return as command reply: char *s, *t = NULL; // Server not ready? abort // TODO: store, resend when server is connected if ((!net_msg_serverok) || (!buf)) return; // isolate USSD reply text if (t = strchr(buf, '"')) { buf = ++t; // start of USSD string while ((*t) && (*t != '"')) { if (*t == ',') // replace comma *t = '.'; t++; } *t = 0; // end of USSD string } // format reply: s = stp_i(net_scratchpad, "MP-0 c", CMD_SendUSSD); if (t) s = stp_s(s, ",0,", buf); else s = stp_rom(s, ",1,Invalid USSD result"); // send reply: if (net_msg_sendpending > 0) delay100(20); // HACK... should abort, buffer & retry later... net_msg_start(); net_msg_encode_puts(); net_msg_send(); }
char net_msgp_group(char stat, char groupnumber, char *groupname) { char *s; s = stp_s(net_scratchpad, "MP-0 g", groupname); s = stp_i(s, ",", car_SOC); s = stp_i(s, ",", car_speed); s = stp_i(s, ",", car_direction); s = stp_i(s, ",", car_altitude); s = stp_i(s, ",", car_gpslock); s = stp_i(s, ",", car_stale_gps); s = stp_latlon(s, ",", car_latitude); s = stp_latlon(s, ",", car_longitude); if (groupnumber == 1) return net_msg_encode_statputs(stat, &crc_group1); else return net_msg_encode_statputs(stat, &crc_group2); }
char net_msgp_firmware(char stat) { // Send firmware version and GSM signal level char *s; unsigned char hwv = 1; #ifdef OVMS_HW_V2 hwv = 2; #endif s = stp_i(net_scratchpad, "MP-0 F", ovms_firmware[0]); s = stp_i(s, ".", ovms_firmware[1]); s = stp_i(s, ".", ovms_firmware[2]); s = stp_s(s, "/", par_get(PARAM_VEHICLETYPE)); s = stp_i(s, "/V", hwv); s = stp_s(s, ",", car_vin); s = stp_i(s, ",", net_sq); s = stp_i(s, ",", sys_features[FEATURE_CANWRITE]); s = stp_s(s, ",", car_type); s = stp_s(s, ",", car_gsmcops); return net_msg_encode_statputs(stat, &crc_firmware); }
char net_msgp_environment(char stat) { char *s; unsigned long park; if (car_parktime == 0) park = 0; else park = car_time - car_parktime; s = stp_i(net_scratchpad, "MP-0 D", car_doors1); s = stp_i(s, ",", car_doors2); s = stp_i(s, ",", car_lockstate); s = stp_i(s, ",", car_tpem); s = stp_i(s, ",", car_tmotor); s = stp_i(s, ",", car_tbattery); s = stp_i(s, ",", car_trip); s = stp_ul(s, ",", car_odometer); s = stp_i(s, ",", car_speed); s = stp_ul(s, ",", park); s = stp_i(s, ",", car_ambient_temp); s = stp_i(s, ",", car_doors3); s = stp_i(s, ",", car_stale_temps); s = stp_i(s, ",", car_stale_ambient); s = stp_l2f(s, ",", car_12vline, 1); s = stp_i(s, ",", car_doors4); s = stp_l2f(s, ",", car_12vline_ref, 1); s = stp_i(s, ",", car_doors5); return net_msg_encode_statputs(stat, &crc_environment); }
char net_msgp_stat(char stat) { char *p, *s; p = par_get(PARAM_MILESKM); s = stp_i(net_scratchpad, "MP-0 S", car_SOC); s = stp_s(s, ",", p); s = stp_i(s, ",", car_linevoltage); s = stp_i(s, ",", car_chargecurrent); switch (car_chargestate) { case 0x01: s = stp_rom(s, ",charging"); break; case 0x02: s = stp_rom(s, ",topoff"); break; case 0x04: s = stp_rom(s, ",done"); break; case 0x0d: s = stp_rom(s, ",prepare"); break; case 0x0f: s = stp_rom(s, ",heating"); break; default: s = stp_rom(s, ",stopped"); } switch (car_chargemode) { case 0x00: s = stp_rom(s, ",standard"); break; case 0x01: s = stp_rom(s, ",storage"); break; case 0x03: s = stp_rom(s, ",range"); break; case 0x04: s = stp_rom(s, ",performance"); break; default: s = stp_rom(s, ","); } if (*p == 'M') // Kmh or Miles { s = stp_i(s, ",", car_idealrange); s = stp_i(s, ",", car_estrange); } else { s = stp_i(s, ",", MI2KM(car_idealrange)); s = stp_i(s, ",", MI2KM(car_estrange)); } s = stp_i(s, ",", car_chargelimit); s = stp_i(s, ",", car_chargeduration); s = stp_i(s, ",", car_charge_b4); s = stp_i(s, ",", car_chargekwh); s = stp_i(s, ",", car_chargesubstate); s = stp_i(s, ",", car_chargestate); s = stp_i(s, ",", car_chargemode); s = stp_i(s, ",", car_timermode); s = stp_i(s, ",", car_timerstart); s = stp_i(s, ",", car_stale_timer); return net_msg_encode_statputs(stat, &crc_stat); }
char net_msgp_stat(char stat) { char *p, *s; p = par_get(PARAM_MILESKM); s = stp_i(net_scratchpad, "MP-0 S", car_SOC); s = stp_s(s, ",", p); s = stp_i(s, ",", car_linevoltage); s = stp_i(s, ",", car_chargecurrent); switch (car_chargestate) { case 0x01: s = stp_rom(s, ",charging"); break; case 0x02: s = stp_rom(s, ",topoff"); break; case 0x04: s = stp_rom(s, ",done"); break; case 0x0d: s = stp_rom(s, ",prepare"); break; case 0x0f: s = stp_rom(s, ",heating"); break; default: s = stp_rom(s, ",stopped"); } switch (car_chargemode) { case 0x00: s = stp_rom(s, ",standard"); break; case 0x01: s = stp_rom(s, ",storage"); break; case 0x03: s = stp_rom(s, ",range"); break; case 0x04: s = stp_rom(s, ",performance"); break; default: s = stp_rom(s, ","); } if (*p == 'M') // Kmh or Miles { s = stp_i(s, ",", car_idealrange); s = stp_i(s, ",", car_estrange); } else { s = stp_i(s, ",", KmFromMi(car_idealrange)); s = stp_i(s, ",", KmFromMi(car_estrange)); } s = stp_i(s, ",", car_chargelimit); s = stp_i(s, ",", car_chargeduration); s = stp_i(s, ",", car_charge_b4); s = stp_i(s, ",", car_chargekwh); s = stp_i(s, ",", car_chargesubstate); s = stp_i(s, ",", car_chargestate); s = stp_i(s, ",", car_chargemode); s = stp_i(s, ",", car_timermode); s = stp_i(s, ",", car_timerstart); s = stp_i(s, ",", car_stale_timer); s = stp_l2f(s, ",", (unsigned long)car_cac100, 2); s = stp_i(s, ",", car_chargefull_minsremaining); s = stp_i(s, ",", car_chargelimit_minsremaining); s = stp_i(s, ",", car_chargelimit_rangelimit); s = stp_i(s, ",", car_chargelimit_soclimit); s = stp_i(s, ",", car_coolingdown); s = stp_i(s, ",", car_cooldown_tbattery); s = stp_i(s, ",", car_cooldown_timelimit); s = stp_i(s, ",", car_chargeestimate); return net_msg_encode_statputs(stat, &crc_stat); }
char *net_prep_stat(char *s) { if (car_doors1bits.ChargePort) { // Charge port door is open, we are charging switch (car_chargemode) { case 0x00: s = stp_rom(s, "Standard - "); // Charge Mode Standard break; case 0x01: s = stp_rom(s, "Storage - "); // Storage break; case 0x03: s = stp_rom(s, "Range - "); // Range break; case 0x04: s = stp_rom(s, "Performance - "); // Performance } switch (car_chargestate) { case 0x01: s = stp_rom(s, "Charging"); // Charge State Charging break; case 0x02: s = stp_rom(s, "Charging, Topping off"); // Topping off break; case 0x04: s = stp_rom(s, "Charging Done"); // Done break; case 0x0d: s = stp_rom(s, "Preparing"); // Preparing break; case 0x0f: s = stp_rom(s, "Charging, Heating"); // Heating break; default: s = stp_rom(s, "Charging Stopped"); // Stopped } } else { s = stp_rom(s, "Not charging"); } if (can_mileskm == 'M') { s = stp_i(s, "\r Range: ", car_estrange); s = stp_i(s, " - ", car_idealrange); s = stp_rom(s, " mi"); } else { s = stp_i(s, "\r Range: ", MI2KM(car_estrange)); s = stp_i(s, " - ", MI2KM(car_idealrange)); s = stp_rom(s, " km"); } s = stp_i(s, "\r SOC: ", car_SOC); s = stp_rom(s, "%"); if (can_mileskm == 'M') { s = stp_ul(s, "\r ODO: ", car_odometer / 10); s = stp_rom(s, " mi"); } else { s = stp_ul(s, "\r ODO: ", MI2KM(car_odometer / 10)); s = stp_rom(s, " km"); } return s; }
void net_msg_server_welcome(char *msg) { // The server has sent a welcome (token <space> base64digest) char *d,*p,*s; int k; unsigned char hwv = 1; #ifdef OVMS_HW_V2 hwv = 2; #endif if( !msg ) return; for (d=msg;(*d != 0)&&(*d != ' ');d++) ; if (*d != ' ') return; *d++ = 0; // At this point, <msg> is token, and <x> is base64digest // (both null-terminated) // Check for token-replay attack if (strcmp(token,msg)==0) return; // Server is using our token! // Validate server token p = par_get(PARAM_SERVERPASS); hmac_md5(msg, strlen(msg), p, strlen(p), digest); base64encode(digest, MD5_SIZE, net_scratchpad); if (strcmp(d,net_scratchpad)!=0) return; // Invalid server digest // Ok, at this point, our token is ok strcpy(net_scratchpad,msg); strcat(net_scratchpad,token); hmac_md5(net_scratchpad,strlen(net_scratchpad),p,strlen(p),digest); // Setup, and prime the rx and tx cryptos RC4_setup(&rx_crypto1, &rx_crypto2, digest, MD5_SIZE); for (k=0;k<1024;k++) { net_scratchpad[0] = 0; RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, 1); } RC4_setup(&tx_crypto1, &tx_crypto2, digest, MD5_SIZE); for (k=0;k<1024;k++) { net_scratchpad[0] = 0; RC4_crypt(&tx_crypto1, &tx_crypto2, net_scratchpad, 1); } net_msg_serverok = 1; p = par_get(PARAM_PARANOID); if (*p == 'P') { // Paranoid mode initialisation if (ptokenmade==0) { // We need to make the ptoken for (k=0;k<TOKEN_SIZE;k++) { ptoken[k] = cb64[rand()%64]; } ptoken[TOKEN_SIZE] = 0; } // To be truly paranoid, we must send the paranoid token to the server ;-) ptokenmade=0; // Leave it off for the MP-0 ET message strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 ET"); strcat(net_scratchpad,ptoken); net_msg_start(); net_msg_encode_puts(); net_msg_send(); ptokenmade=1; // And enable paranoid mode from now on... // And calculate the pdigest for future use p = par_get(PARAM_MODULEPASS); hmac_md5(ptoken, strlen(ptoken), p, strlen(p), pdigest); } else { ptokenmade = 0; // This disables paranoid mode } /* DEBUG / QA stats: Send crash counter and last reason: * * MP-0 H*-OVM-DebugCrash,0,2592000 * ,<firmware_version>/<vehicle_type><vehicle_version>/V<hardware_version> * ,<crashcnt>,<crashreason>,<checkpoint> */ if (debug_crashreason & 0x80) { debug_crashreason &= ~0x80; // clear checkpoint hold bit s = stp_i(net_scratchpad, "MP-0 H*-OVM-DebugCrash,0,2592000,", ovms_firmware[0]); s = stp_i(s, ".", ovms_firmware[1]); s = stp_i(s, ".", ovms_firmware[2]); s = stp_s(s, "/", par_get(PARAM_VEHICLETYPE)); if (vehicle_version) s = stp_rom(s, vehicle_version); s = stp_i(s, "/V", hwv); s = stp_i(s, ",", debug_crashcnt); s = stp_x(s, ",", debug_crashreason); s = stp_i(s, ",", debug_checkpoint); delay100(20); net_msg_start(); net_msg_encode_puts(); net_msg_send(); } #ifdef OVMS_LOGGINGMODULE logging_serverconnect(); #endif // #ifdef OVMS_LOGGINGMODULE }
BOOL net_msg_cmd_exec(void) { int k; char *p, *s; delay100(2); CHECKPOINT(0x43) switch (net_msg_cmd_code) { case 1: // Request feature list (params unused) for (k=0;k<FEATURES_MAX;k++) { s = stp_i(net_scratchpad, "MP-0 c1,0,", k); s = stp_i(s, ",", FEATURES_MAX); s = stp_i(s, ",", sys_features[k]); net_msg_encode_puts(); } break; case 2: // Set feature (params: feature number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<FEATURES_MAX)) { sys_features[k] = atoi(p); if (k>=FEATURES_MAP_PARAM) // Top N features are persistent par_set(PARAM_FEATURE_S+(k-FEATURES_MAP_PARAM), p); if (k == FEATURE_CANWRITE) vehicle_initialise(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 3: // Request parameter list (params unused) for (k=0;k<PARAM_MAX;k++) { p = par_get(k); if (k==PARAM_SERVERPASS) *p=0; // Don't show netpass1 s = stp_i(net_scratchpad, "MP-0 c3,0,", k); s = stp_i(s, ",", PARAM_MAX); s = stp_s(s, ",", p); net_msg_encode_puts(); } break; case 4: // Set parameter (params: param number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<PARAM_FEATURE_S)) { par_set(k, p); STP_OK(net_scratchpad, net_msg_cmd_code); if ((k==PARAM_MILESKM) || (k==PARAM_VEHICLETYPE)) vehicle_initialise(); } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 5: // Reboot (params unused) STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); net_state_enter(NET_STATE_HARDSTOP); break; case 6: // CHARGE ALERT (params unused) net_msg_alert(); net_msg_encode_puts(); break; case 40: // Send SMS (params: phone number, SMS message) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the phone number, and <p> to the SMS message net_send_sms_start(net_msg_cmd_msg); net_puts_ram(p); net_puts_rom("\x1a"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { net_msg_start(); STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); delay100(2); break; case 41: // Send MMI/USSD Codes (param: USSD_CODE) net_puts_rom("AT+CUSD=1,\""); net_puts_ram(net_msg_cmd_msg); net_puts_rom("\",15\r"); // cmd reply #1 to acknowledge command: delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); // cmd reply #2 sent on USSD response, see net_msg_reply_ussd() break; case 49: // Send raw AT command (param: raw AT command) net_puts_ram(net_msg_cmd_msg); net_puts_rom("\r"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); break; default: return FALSE; } return TRUE; }
char *net_prep_ctp(char *s, char *argument) { int imStart = car_idealrange; int imTarget = 0; int pctTarget = 0; int cac100 = car_cac100; int volts = car_linevoltage; int amps = car_chargelimit; int degAmbient = car_ambient_temp; int chargemode = car_chargemode; int watts = 0; int imExpect; int minRemain; if (vehicle_fn_minutestocharge == NULL) { return stp_rom(s, "CTP not available"); } // CTP 90s 150e 70% 16800w 160a 24d [S|R|P] while (argument != NULL) { int cch = strlen(argument); strupr(argument); // Convert argument to upper case if (cch > 0) { int val; char chType = argument[cch-1]; argument[cch-1] = 0; if (cch > 1) { val = atoi(argument); switch (chType) { case 'S': imStart = val; break; case 'E': imTarget = val; break; case '%': pctTarget = val; break; case 'W': watts = val; break; case 'V': volts = val; break; case 'A': amps = val; break; case 'C': cac100 = val*100; break; case 'D': degAmbient = val; break; } } else { switch (chType) { case 'S': chargemode = 0; break; case 'R': chargemode = 3; break; case 'P': chargemode = 4; break; } } argument[cch-1] = chType; } argument = net_sms_nextarg(argument); } if (volts > 0 && amps > 0) watts = volts * amps; if (watts < 1000) { s = stp_rom(s, "no power level specified"); return s; } minRemain = vehicle_fn_minutestocharge(chargemode, watts, imStart, imTarget, pctTarget, cac100, degAmbient, &imExpect); s = stp_i(s, NULL, imStart); s = stp_i(s, " to ", imExpect); s = stp_rom(s, " ideal mi\r"); if (minRemain >= 0) { s = stp_i(s, NULL, minRemain/60); s = stp_ulp(s, ":", minRemain % 60, 2, '0'); } else if (minRemain == -3) { s = stp_rom(s, "target reached"); } else { s = stp_i(s, "error: ", minRemain); } return s; }
char *net_prep_stat(char *s) { // convert distance values as needed unsigned int estrange = car_estrange; unsigned int idealrange = car_idealrange; unsigned long odometer = car_odometer; const rom char *unit = " mi"; if (can_mileskm == 'K') { estrange = KmFromMi(estrange); idealrange = KmFromMi(idealrange); odometer = KmFromMi(odometer); unit = " km"; } if (car_time != 0) { char *p = par_get(PARAM_TIMEZONE); s = stp_time(s, NULL, car_time + timestring_to_mins(p)*60L); s = stp_rom(s, "\r "); } if (car_coolingdown>=0) { s = stp_i(s, "Cooldown: ", car_tbattery); s = stp_i(s, "C/",car_cooldown_tbattery); s = stp_i(s, "C (",car_coolingdown); s = stp_i(s, "cycles, ",car_cooldown_timelimit); s = stp_rom(s, "mins remain)"); } if (car_doors1bits.ChargePort) { char fShowVA = TRUE; // Charge port door is open, we are charging switch (car_chargemode) { case 0x00: s = stp_rom(s, "Standard - "); // Charge Mode Standard break; case 0x01: s = stp_rom(s, "Storage - "); // Storage break; case 0x03: s = stp_rom(s, "Range - "); // Range break; case 0x04: s = stp_rom(s, "Performance - "); // Performance } switch (car_chargestate) { case 0x01: s = stp_rom(s, "Charging"); // Charge State Charging break; case 0x02: s = stp_rom(s, "Charging, Topping off"); // Topping off break; case 0x04: s = stp_rom(s, "Charging Done"); // Done fShowVA = FALSE; break; case 0x0d: s = stp_rom(s, "Preparing"); // Preparing break; case 0x0f: s = stp_rom(s, "Charging, Heating"); // Heating break; default: s = stp_rom(s, "Charging Stopped"); // Stopped fShowVA = FALSE; break; } // this causes ACC to think the charge port door has been closed and opened, // which then causes it to do something that makes the coolant pump come on // car_doors1bits.ChargePort = 0; // MJ Close ChargePort, will open next CAN Reading if (fShowVA) { s = stp_i(s, "\r ", car_linevoltage); s = stp_i(s, "V/", car_chargecurrent); s = stp_rom(s, "A"); if (car_chargefull_minsremaining >= 0) { s = stp_i(s,"\r Full: ",car_chargefull_minsremaining); s = stp_rom(s," mins"); } if (car_chargelimit_soclimit > 0) { s = stp_i(s, "\r ", car_chargelimit_soclimit); s = stp_i(s,"%: ",car_chargelimit_minsremaining); s = stp_rom(s," mins"); } if (car_chargelimit_rangelimit > 0) { s = stp_i(s, "\r ", (can_mileskm == 'K')?KmFromMi(car_chargelimit_rangelimit):car_chargelimit_rangelimit); s = stp_rom(s, unit); s = stp_i(s,": ",car_chargelimit_minsremaining); s = stp_rom(s," mins"); } } } else { s = stp_rom(s, "Not charging"); } s = stp_i(s, "\r SOC: ", car_SOC); s = stp_rom(s, "%"); if (idealrange != 0) { s = stp_i(s, "\r Ideal Range: ", idealrange); s = stp_rom(s, unit); } if (estrange != 0) { s = stp_i(s, "\r Est. Range: ", estrange); s = stp_rom(s, unit); } if (odometer != 0) { s = stp_l2f_h(s, "\r ODO: ", odometer, 1); s = stp_rom(s, unit); } if (car_cac100 != 0) { s = stp_l2f_h(s, "\r CAC: ", (unsigned long)car_cac100, 2); } return s; }
BOOL net_msg_cmd_exec(void) { int k; char *p, *s; delay100(2); CHECKPOINT(0x43) switch (net_msg_cmd_code) { case 1: // Request feature list (params unused) for (k=0;k<FEATURES_MAX;k++) { s = stp_i(net_scratchpad, "MP-0 c1,0,", k); s = stp_i(s, ",", FEATURES_MAX); s = stp_i(s, ",", sys_features[k]); net_msg_encode_puts(); } break; case 2: // Set feature (params: feature number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<FEATURES_MAX)) { sys_features[k] = atoi(p); if (k>=FEATURES_MAP_PARAM) // Top N features are persistent par_set(PARAM_FEATURE_S+(k-FEATURES_MAP_PARAM), p); if (k == FEATURE_CANWRITE) vehicle_initialise(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 3: // Request parameter list (params unused) for (k=0;k<PARAM_MAX;k++) { p = par_get(k); if (k==PARAM_SERVERPASS) *p=0; // Don't show netpass1 s = stp_i(net_scratchpad, "MP-0 c3,0,", k); s = stp_i(s, ",", PARAM_MAX); s = stp_s(s, ",", p); net_msg_encode_puts(); } break; case 4: // Set parameter (params: param number, value) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the command, and <p> to the param value k = atoi(net_msg_cmd_msg); if ((k>=0)&&(k<PARAM_FEATURE_S)) { par_set(k, p); STP_OK(net_scratchpad, net_msg_cmd_code); if ((k==PARAM_MILESKM) || (k==PARAM_VEHICLETYPE)) vehicle_initialise(); #ifdef OVMS_ACCMODULE // Reset the ACC state it an ACC parameter is changed if ((k>=PARAM_ACC_S)&&(k<(PARAM_ACC_S+PARAM_ACC_COUNT))) acc_state_enter(ACC_STATE_FIRSTRUN); #endif } else { STP_INVALIDRANGE(net_scratchpad, net_msg_cmd_code); } } else { STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); break; case 5: // Reboot (params unused) STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); net_state_enter(NET_STATE_HARDSTOP); break; case 6: // CHARGE ALERT (params unused) net_msg_alert(); net_msg_encode_puts(); break; case 7: // SMS command wrapper // process command: net_msg_bufpos = net_msg_scratchpad; k = net_sms_in(par_get(PARAM_REGPHONE), net_msg_cmd_msg); net_msg_bufpos = NULL; // output is now in net_msg_scratchpad // create return string: s = stp_i(net_scratchpad, NET_MSG_CMDRESP, net_msg_cmd_code); s = stp_i(s, ",", 1-k); // 0=ok 1=error if (k) { *s++ = ','; for (p = net_msg_scratchpad; *p; p++) { if (*p == '\n') *s++ = '\r'; // translate LF to CR else if (*p == ',') *s++ = ';'; // translate , to ; else *s++ = *p; } *s = 0; } // send return string: net_msg_encode_puts(); break; case 40: // Send SMS (params: phone number, SMS message) for (p=net_msg_cmd_msg;(*p != 0)&&(*p != ',');p++) ; // check if a value exists and is separated by a comma if (*p == ',') { *p++ = 0; // At this point, <net_msg_cmd_msg> points to the phone number, and <p> to the SMS message net_send_sms_start(net_msg_cmd_msg); net_puts_ram(p); net_puts_rom("\x1a"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); } else { net_msg_start(); STP_INVALIDSYNTAX(net_scratchpad, net_msg_cmd_code); } net_msg_encode_puts(); delay100(2); break; case 41: // Send MMI/USSD Codes (param: USSD_CODE) net_puts_rom("AT+CUSD=1,\""); net_puts_ram(net_msg_cmd_msg); net_puts_rom("\",15\r"); // cmd reply #1 to acknowledge command: delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); // cmd reply #2 sent on USSD response, see net_msg_reply_ussd() break; case 49: // Send raw AT command (param: raw AT command) net_puts_ram(net_msg_cmd_msg); net_puts_rom("\r"); delay100(5); net_msg_start(); STP_OK(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); delay100(2); break; default: return FALSE; } return TRUE; }