// <stat> guarded encode the message in net_scratchpad and start the send process char net_msg_encode_statputs(char stat, WORD *oldcrc) { WORD newcrc = crc16(net_scratchpad, strlen(net_scratchpad)); switch (stat) { case 0: // Always output net_msg_encode_puts(); *oldcrc = newcrc; break; case 1: // Guarded output, but net_msg_start() has already been sent if (*oldcrc != newcrc) { net_msg_encode_puts(); *oldcrc = newcrc; } break; case 2: // Guarded output, but net_msg_start() has not yet been sent if (*oldcrc != newcrc) { net_msg_start(); net_msg_encode_puts(); *oldcrc = newcrc; stat = 1; } break; } return stat; }
void net_msg_tpms(void) { char k; long p; int b,a; if ((car_tpms_t[0]==0)&&(car_tpms_t[1]==0)&& (car_tpms_t[2]==0)&&(car_tpms_t[3]==0)) return; // No TPMS, no report strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 W"); for (k=0;k<4;k++) { if (car_tpms_t[k]>0) { p = (long)((float)car_tpms_p[k]/0.2755); b = (p / 10); a = (p % 10); sprintf(net_msg_scratchpad, (rom far char*)"%d.%d,%d,", b,a,(int)(car_tpms_t[k]-40)); strcat(net_scratchpad,net_msg_scratchpad); } else { strcatpgm2ram(net_scratchpad, (rom far char*)"0,0,"); } } net_scratchpad[strlen(net_scratchpad)-1] = 0; // Remove trailing ',' net_msg_encode_puts(); }
void net_msg_cmd_do(void) { CHECKPOINT(0x44) delay100(2); // commands 40-49 are special AT commands, thus, disable net_msg here if ((net_msg_cmd_code < 40) || (net_msg_cmd_code > 49)) net_msg_start(); // Execute cmd: ask car module to execute first: if ((vehicle_fn_commandhandler == NULL)|| (! vehicle_fn_commandhandler(TRUE, net_msg_cmd_code,net_msg_cmd_msg))) { // Car module does not feel responsible, fall back to standard: if( !net_msg_cmd_exec() ) { // No standard as well => return "unimplemented" STP_UNIMPLEMENTED(net_scratchpad, net_msg_cmd_code); net_msg_encode_puts(); } } // terminate IPSEND by Ctrl-Z (should this be disabled for commands 40-49 as well?) net_msg_send(); #ifdef OVMS_ACCMODULE acc_handle_msg(TRUE, net_msg_cmd_code, net_msg_cmd_msg); #endif // clear command net_msg_cmd_code = 0; net_msg_cmd_msg[0] = 0; }
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(); }
void net_msg_firmware(void) { // Send firmware version and GSM signal level strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 F"); sprintf(net_msg_scratchpad, (rom far char*)"1.0.8,%s,%d", car_vin, net_sq); strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); }
void net_msg_firmware(void) { // TODO: GSM signal level not reported yet strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 F"); sprintf(net_msg_scratchpad, (rom far char*)"1.0.0,%s,%d", car_vin,0); strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); }
void net_msg_12v_alert(void) { char *s; s = stp_l2f(net_scratchpad, "MP-0 PAALERT!!! 12V BATTERY CRITICAL (", car_12vline, 1); s = stp_l2f(s, "V, ref=", car_12vline_ref, 1); s = stp_rom(s, "V)"); net_msg_encode_puts(); }
// Receive a NET msg from the OVMS server void net_msg_in(char* msg) { int k; if (net_msg_serverok == 0) { if (memcmppgm2ram(msg, (char const rom far*)"MP-S 0 ", 7) == 0) { net_msg_server_welcome(msg+7); } return; // otherwise ignore it } // Ok, we've got an encrypted message waiting for work. // The following is a nasty hack because base64decode doesn't like incoming // messages of length divisible by 4, and is really expecting a CRLF // terminated string, so we give it one... strcatpgm2ram(msg,(char const rom far*)"\r\n"); k = base64decode(msg,net_scratchpad); RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, k); if (memcmppgm2ram(net_scratchpad, (char const rom far*)"MP-0 ", 5) == 0) { msg = net_scratchpad+5; switch (*msg) { case 'A': // PING strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 a"); if (net_msg_sendpending==0) { net_msg_start(); net_msg_encode_puts(); net_msg_send(); } break; case 'Z': // PEER connection if (msg[1] != '0') { net_apps_connected = 1; if (net_msg_sendpending==0) { net_msg_start(); net_msg_stat(); net_msg_gps(); net_msg_tpms(); net_msg_firmware(); net_msg_environment(); net_msg_send(); } } else { net_apps_connected = 0; } break; } } }
void net_msg_valettrunk(void) { char *p; delay100(2); net_msg_start(); strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PATrunk has been opened (valet mode)."); net_msg_encode_puts(); net_msg_send(); }
void net_msg_environment(void) { strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 D"); sprintf(net_msg_scratchpad, (rom far char*)"%d,%d,%d,%d,%d,%d,%d,%lu,%d", car_doors1, car_doors2, car_lockstate, car_tpem, car_tmotor, car_tbattery, car_trip, car_odometer, car_speed); strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); }
void net_msg_gps(void) { strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 L"); format_latlon(car_latitude,net_msg_scratchpad); strcat(net_scratchpad,net_msg_scratchpad); strcatpgm2ram(net_scratchpad,(char const rom far*)","); format_latlon(car_longitude,net_msg_scratchpad); strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); }
void net_msg_alarm(void) { char *p; delay100(2); net_msg_start(); strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PAVehicle alarm is sounding!"); net_msg_encode_puts(); net_msg_send(); }
void net_msg_erroralert(unsigned int errorcode, unsigned long errordata) { char *s; delay100(2); net_msg_start(); s = stp_s(net_scratchpad, "MP-0 PE", car_type); s = stp_ul(s, ",", (unsigned long)errorcode); s = stp_ul(s, ",", (unsigned long)errordata); net_msg_encode_puts(); net_msg_send(); }
void net_msg_alert(void) { char *p; delay100(2); net_msg_start(); strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PA"); switch (car_chargemode) { case 0x00: strcatpgm2ram(net_scratchpad,(char const rom far *)"Standard - "); // Charge Mode Standard break; case 0x01: strcatpgm2ram(net_scratchpad,(char const rom far *)"Storage - "); // Storage break; case 0x03: strcatpgm2ram(net_scratchpad,(char const rom far *)"Range - "); // Range break; case 0x04: strcatpgm2ram(net_scratchpad,(char const rom far *)"Performance - "); // Performance } switch (car_chargestate) { case 0x01: strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging"); // Charge State Charging break; case 0x02: strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging, Topping off"); // Topping off break; case 0x04: strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging Done"); // Done break; default: strcatpgm2ram(net_scratchpad,(char const rom far *)"Charging Stopped"); // Stopped } strcatpgm2ram(net_scratchpad,(char const rom far *)"\rIdeal Range: "); // Ideal Range p = par_get(PARAM_MILESKM); if (*p == 'M') // Kmh or Miles sprintf(net_msg_scratchpad, (rom far char*)"%u mi", car_idealrange); // Miles else sprintf(net_msg_scratchpad, (rom far char*)"%u Km", (unsigned int) ((float) car_idealrange * 1.609)); // Kmh strcat((char*)net_scratchpad,net_msg_scratchpad); strcatpgm2ram(net_scratchpad,(char const rom far *)" SOC: "); sprintf(net_msg_scratchpad, (rom far char*)"%u%%", car_SOC); // 95% strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); net_msg_send(); }
void net_msg_stat(void) { char *p; strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 S"); p = par_get(PARAM_MILESKM); sprintf(net_msg_scratchpad,(rom far char*)"%d,%s,%d,%d,",car_SOC,p,car_linevoltage,car_chargecurrent); strcat(net_scratchpad,net_msg_scratchpad); switch (car_chargestate) { case 0x01: strcatpgm2ram(net_scratchpad,(char const rom far*)"charging,"); // Charge State Charging break; case 0x02: strcatpgm2ram(net_scratchpad,(char const rom far*)"topoff,"); // Topping off break; case 0x04: strcatpgm2ram(net_scratchpad,(char const rom far*)"done,"); // Done break; default: strcatpgm2ram(net_scratchpad,(char const rom far*)"stopped,"); // Stopped } switch (car_chargemode) { case 0x00: strcatpgm2ram(net_scratchpad,(char const rom far*)"standard,"); // Charge Mode Standard break; case 0x01: strcatpgm2ram(net_scratchpad,(char const rom far*)"storage,"); // Storage break; case 0x03: strcatpgm2ram(net_scratchpad,(char const rom far*)"range,"); // Range break; case 0x04: strcatpgm2ram(net_scratchpad,(char const rom far*)"performance,"); // Performance default: strcatpgm2ram(net_scratchpad,(char const rom far*)","); } if (*p == 'M') // Kmh or Miles sprintf(net_msg_scratchpad, (rom far char*)"%u,", car_idealrange); else sprintf(net_msg_scratchpad, (rom far char*)"%u,", (unsigned int) ((float) car_idealrange * 1.609)); strcat(net_scratchpad,net_msg_scratchpad); if (*p == 'M') // Kmh or Miles sprintf(net_msg_scratchpad, (rom far char*)"%u", car_estrange); else sprintf(net_msg_scratchpad, (rom far char*)"%u", (unsigned int) ((float) car_estrange * 1.609)); strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); }
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_12v_alert(void) { char *s; delay100(2); net_msg_start(); if (can_minSOCnotified & CAN_MINSOC_ALERT_12V) s = stp_l2f(net_scratchpad, "MP-0 PAALERT!!! 12V BATTERY CRITICAL (", car_12vline, 1); else s = stp_l2f(net_scratchpad, "MP-0 PA12V BATTERY OK (", car_12vline, 1); s = stp_l2f(s, "V, ref=", car_12vline_ref, 1); s = stp_rom(s, "V)"); net_msg_encode_puts(); net_msg_send(); }
void net_msg_environment(void) { unsigned long park; if (car_parktime == 0) park = 0; else park = car_time - car_parktime; strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 D"); sprintf(net_msg_scratchpad, (rom far char*)"%d,%d,%d,%d,%d,%d,%d,%lu,%d,%lu", car_doors1, car_doors2, car_lockstate, car_tpem, car_tmotor, car_tbattery, car_trip, car_odometer, car_speed, park); strcat(net_scratchpad,net_msg_scratchpad); net_msg_encode_puts(); }
void net_msg_forward_sms(char *caller, char *SMS) { //Server not ready, stop sending //TODO: store this message inside buffer, resend it when server is connected if ((net_msg_serverok == 0)||(net_msg_sendpending)>0) return; delay100(2); net_msg_start(); strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 PA"); strcatpgm2ram(net_scratchpad,(char const rom far*)"SMS FROM: "); strcat(net_scratchpad, caller); strcatpgm2ram(net_scratchpad,(char const rom far*)" - MSG: "); SMS[70]=0; // Hacky limit on the max size of an SMS forwarded strcat(net_scratchpad, SMS); net_msg_encode_puts(); net_msg_send(); }
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(); }
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; }
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; }
// Receive a NET msg from the OVMS server void net_msg_in(char* msg) { int k; char s; if (net_msg_serverok == 0) { if (memcmppgm2ram(msg, (char const rom far*)"MP-S 0 ", 7) == 0) { net_msg_server_welcome(msg+7); net_granular_tick = 3590; // Nasty hack to force a status transmission in 10 seconds } return; // otherwise ignore it } // Ok, we've got an encrypted message waiting for work. // The following is a nasty hack because base64decode doesn't like incoming // messages of length divisible by 4, and is really expecting a CRLF // terminated string, so we give it one... CHECKPOINT(0x40) if (((strlen(msg)*4)/3) >= (NET_BUF_MAX-3)) { // Quick exit to reset link if incoming message is too big net_state_enter(NET_STATE_DONETINIT); return; } strcatpgm2ram(msg,(char const rom far*)"\r\n"); k = base64decode(msg,net_scratchpad); CHECKPOINT(0x41) RC4_crypt(&rx_crypto1, &rx_crypto2, net_scratchpad, k); if (memcmppgm2ram(net_scratchpad, (char const rom far*)"MP-0 ", 5) != 0) { net_state_enter(NET_STATE_DONETINIT); return; } msg = net_scratchpad+5; if ((*msg == 'E')&&(msg[1]=='M')) { // A paranoid-mode message from the server (or, more specifically, app) // The following is a nasty hack because base64decode doesn't like incoming // messages of length divisible by 4, and is really expecting a CRLF // terminated string, so we give it one... msg += 2; // Now pointing to the code just before encrypted paranoid message strcatpgm2ram(msg,(char const rom far*)"\r\n"); k = base64decode(msg+1,net_msg_scratchpad+1); RC4_setup(&pm_crypto1, &pm_crypto2, pdigest, MD5_SIZE); for (k=0;k<1024;k++) { net_scratchpad[0] = 0; RC4_crypt(&pm_crypto1, &pm_crypto2, net_scratchpad, 1); } RC4_crypt(&pm_crypto1, &pm_crypto2, net_msg_scratchpad+1, k); net_msg_scratchpad[0] = *msg; // The code // The message is now out of paranoid mode... msg = net_msg_scratchpad; } CHECKPOINT(0x42) switch (*msg) { case 'A': // PING strcpypgm2ram(net_scratchpad,(char const rom far*)"MP-0 a"); if (net_msg_sendpending==0) { net_msg_start(); net_msg_encode_puts(); net_msg_send(); } break; case 'Z': // PEER connection if (msg[1] != '0') { net_apps_connected = 1; if (net_msg_sendpending==0) { net_msg_start(); net_msgp_stat(0); net_msgp_gps(0); net_msgp_tpms(0); net_msgp_firmware(0); net_msgp_environment(0); net_msg_send(); } } else { net_apps_connected = 0; } break; case 'h': // Historical data acknowledgement #ifdef OVMS_LOGGINGMODULE logging_ack(atoi(msg+1)); #endif // #ifdef OVMS_LOGGINGMODULE break; case 'C': // COMMAND net_msg_cmd_in(msg+1); if (net_msg_sendpending==0) net_msg_cmd_do(); break; } }
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 }
void net_msg_server_welcome(char *msg) { // The server has sent a welcome (token <space> base64digest) char *d,*p; int k; 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_NETPASS1); 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_REGPASS); hmac_md5(ptoken, strlen(ptoken), p, strlen(p), pdigest); } else { ptokenmade = 0; // This disables paranoid mode } }