From 883bbde7e5412c5d11c77f667d3d42b762aacbf5 Mon Sep 17 00:00:00 2001 From: Michael Balzer Date: Sat, 8 Jul 2017 20:57:45 +0200 Subject: [PATCH] - Added OBD-2 low level access (commands DA & DR) - Changed USB serial speed to 1 Mbaud --- README.md | 22 ++++++++- TwizyCfg/TwizyCfg.ino | 96 ++++++++++++++++++++++++++++++++++++-- TwizyCfg/TwizyCfg_config.h | 7 ++- 3 files changed, 118 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5360a38..2b4f6ff 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ It's a port of my SEVCON core functionality from the [OVMS project](https://gith **V2** now also supports the OVMS/Twizy tuning macro commands (i.e. `power`, `speed`, `recup` etc.) as well as profile management including saving to / loading from the Arduino EEPROM. Assuming this will be used by hardware hackers, the `brakelight` command has been included as well. Still missing from the OVMS command set is the `clear` command, this is planned to get included along with log access and output. Also missing are all dynamic adjustment functions, i.e. auto drive/recuperation power level following and kickdown. +**V2.1** adds support for low level OBD2 diag requests. Look out for DDT2000 XML files for device IDs, requests and data definitions. There is currently no parsing of the results, output is just the hex encoded data. + Read the OVMS user manual and command overview for details on all commands. You may also like to read the SEVCON Gen4 manual for some basic description of registers. The full register set is documented in the SEVCON master dictionary, which is ©SEVCON. It's contained in the SEVCON DVT package. Most registers of interest for normal tuning can be found in the [Twizy SDO list](extras/Twizy-SDO-List.ods). @@ -26,8 +28,9 @@ Most registers of interest for normal tuning can be found in the [Twizy SDO list To download, click the DOWNLOADS button in the top right corner, download the ZIP file. Extract the ZIP, open `TwizyCfg/TwizyCfg.ino` from Arduino IDE. -You will also need this library: +You will also need these libraries: - [MCP_CAN_lib by Cory Fowler](https://github.com/coryjfowler/MCP_CAN_lib) + - [iso-tp by Heiko Krupp](https://github.com/dexterbg/iso-tp) Enter your CAN module configuration in the `TwizyCfg_config.h` tab. @@ -39,7 +42,7 @@ Connect to the OBD2 port, switch on the Twizy, start the sketch & open the seria The Arduino will display a help screen, then wait for your commands: -### Low level commands +### Low level CANopen commands | Function | Command | | --- | --- | @@ -82,6 +85,19 @@ The Arduino will display a help screen, then wait for your commands: - See [Twizy profile converter](https://dexters-web.de/cfgconv) +### Low level OBD-2 commands + +| Function | Command | +| --- | --- | +| Set OBD2 device address | `da ` | +| Send OBD2 request | `dr ` | + + - See [OBD-II PIDs](https://en.wikipedia.org/wiki/OBD-II_PIDs) + - See [Unified Diagnostic Services](https://en.wikipedia.org/wiki/Unified_Diagnostic_Services) + - Look out for DDT2000 (©Renault) XML files for Renault specific device IDs, requests and data structures + - Check [canbushack.com](http://canbushack.com/) for digging deeper + + ### Examples - Get firmware version: `rs 100a 00` (if it's `0712.0003` or higher, the Twizy is locked) @@ -91,6 +107,8 @@ The Arduino will display a help screen, then wait for your commands: - Set and apply a base64 profile: `set 0 3m9wg295ABozAAAAAAAAAAAuOkVbZVNFNRUrRVtlNSMbJGUAAAABAABlZQAAAAAA` (Twizy needs to be on, not in `GO`) - Save current profile to EEPROM slot 1: `save 1` - Reset SEVCON to default configuration: `reset` + - Read DTC from instrument cluster: `da 743 763`, then `dr 2113` + - Read battery health estimation from BMS: `da 79b 7bb`, then `dr 2161` ### Notes diff --git a/TwizyCfg/TwizyCfg.ino b/TwizyCfg/TwizyCfg.ino index 65e2bf1..deb4c05 100644 --- a/TwizyCfg/TwizyCfg.ino +++ b/TwizyCfg/TwizyCfg.ino @@ -10,19 +10,22 @@ * * Libraries used: * - MCP_CAN: https://github.com/coryjfowler/MCP_CAN_lib + * - iso-tp: https://github.com/dexterbg/iso-tp [https://github.com/altelch/iso-tp] * * License: * This is free software under GNU Lesser General Public License (LGPL) * https://www.gnu.org/licenses/lgpl.html * */ -#define TWIZY_CFG_VERSION "V2.0.1 (2017-07-01)" +#define TWIZY_CFG_VERSION "V2.1.0 (2017-07-08)" #include #include #include +#include + #include "utils.h" #include "CANopen.h" #include "Tuning.h" @@ -32,6 +35,10 @@ // CAN interface: MCP_CAN CAN(TWIZY_CAN_CS_PIN); +// ISO-TP: +IsoTp isotp(&CAN, TWIZY_CAN_IRQ_PIN); +struct Message_t tpMsg; + // Output buffers: char net_scratchpad[200]; char net_msg_scratchpad[200]; @@ -48,7 +55,8 @@ enum cfg_command_id { cmdPreOp, cmdOp, cmdSet, cmdReset, cmdGet, cmdInfo, cmdSave, cmdLoad, cmdDrive, cmdRecup, cmdRamps, cmdRampLimits, cmdSmooth, - cmdSpeed, cmdPower, cmdTSMap, cmdBrakelight + cmdSpeed, cmdPower, cmdTSMap, cmdBrakelight, + cmdDiagAddress, cmdDiagRequest }; enum cfg_command_mode { @@ -97,6 +105,9 @@ const cfg_command command_table[] PROGMEM = { { "TSMAP", cmdTSMap, modePreOp }, { "BRAKELIGHT", cmdBrakelight, modePreOp }, + { "DA", cmdDiagAddress, modeOffline }, + { "DR", cmdDiagRequest, modeOffline }, + }; #define COMMAND_COUNT (sizeof(command_table)/sizeof(cfg_command)) @@ -173,6 +184,9 @@ bool exec(char *cmdline) " tsmap -- set torque speed maps\n" " brakelight -- set brakelight accel levels\n" "\n" + " da -- set OBD2 device address\n" + " dr -- send OBD2 request\n" + "\n" "See OVMS manual & command overview for details.\n" "Note: and are hexadecimal, are decimal\n" "Examples:\n" @@ -331,6 +345,82 @@ bool exec(char *cmdline) break; + case cmdDiagAddress: + // DA tx_id_hex rx_id_hex + if (arguments = net_sms_nextarg(arguments)) + arg[0] = (int)axtoul(arguments); + if (arguments = net_sms_nextarg(arguments)) + arg[1] = (int)axtoul(arguments); + + if (!arguments) { + s = stp_rom(s, "ERROR: Too few args"); + } + else { + tpMsg.tx_id = arg[0]; + tpMsg.rx_id = arg[1]; + CAN.init_Filt(1, 0, tpMsg.rx_id << 16); + s = stp_rom(s, "OK"); + } + go_op_onexit = false; + break; + + + case cmdDiagRequest: + // DR hexstring + if (arguments = net_sms_nextarg(arguments)) { + if (strlen(arguments) & 1) { + // input length is odd: + s = stp_rom(s, "ERROR: invalid hex string length"); + } + else { + // parse hexstring into scratchpad: + t = (char *) net_msg_scratchpad; + maps[2] = 0; + while (arguments[0]) { + maps[0] = arguments[0]; + maps[1] = arguments[1]; + *t++ = axtoul(maps); + arguments += 2; + } + } + } + + if (!arguments) { + s = stp_rom(s, "ERROR: Too few args"); + } + else { + // send request: + tpMsg.Buffer = (uint8_t *)net_msg_scratchpad; + tpMsg.len = (t - (char *)net_msg_scratchpad); + if (err = isotp.send(&tpMsg)) { + s = stp_i(s, "ERROR: isotp.send error code ", err); + } + else { + // read response into scratchpad: + tpMsg.Buffer = (uint8_t *)net_msg_scratchpad; + tpMsg.len = 0; + isotp.receive(&tpMsg); + if (tpMsg.tp_state != ISOTP_FINISHED) { + s = stp_i(s, "ERROR: isotp.receive error code ", tpMsg.tp_state); + } + else { + // output response as hexstring: + Serial.print(net_scratchpad); + net_scratchpad[0] = 0; + for (i=0; i