From fe485dc049e2ce94d92441018af6bb0b3297fb19 Mon Sep 17 00:00:00 2001 From: Carsten Schmiemann Date: Sat, 19 Nov 2022 01:40:39 +0100 Subject: [PATCH] Add command for manual ISO TP Std poll --- .../src/ph2_commands.cpp | 124 ++++++++++++++++++ .../src/vehicle_renaultzoe_ph2_can.h | 6 + 2 files changed, 130 insertions(+) diff --git a/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/ph2_commands.cpp b/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/ph2_commands.cpp index 8126e14..765a1f6 100644 --- a/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/ph2_commands.cpp +++ b/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/ph2_commands.cpp @@ -39,6 +39,130 @@ #include "vehicle_renaultzoe_ph2_can.h" +void OvmsVehicleRenaultZoePh2CAN::CanInit() +{ + OvmsCommand* cmd; + OvmsCommand* obd; + obd = cmd_xrt->RegisterCommand("can", "CAN tools"); + cmd = obd->RegisterCommand("request", "Send ISO-TP request, output response"); + cmd->RegisterCommand("device", "Send ISO-TP request to a ECU", shell_can_request, " ", 3, 3); + cmd->RegisterCommand("broadcast", "Send ISO-TP request as broadcast", shell_can_request, "", 1, 1); +} + +void OvmsVehicleRenaultZoePh2CAN::shell_obd_request(int verbosity, OvmsWriter* writer, OvmsCommand* cmd, int argc, const char* const* argv) +{ + uint16_t txid = 0, rxid = 0; + string request; + string response; + + // parse args: + string device = cmd->GetName(); + if (device == "device") { + if (argc < 3) { + writer->puts("ERROR: too few args, need: txid rxid request"); + return; + } + txid = strtol(argv[0], NULL, 16); + rxid = strtol(argv[1], NULL, 16); + request = hexdecode(argv[2]); + } else { + if (argc < 1) { + writer->puts("ERROR: too few args, need: request"); + return; + } + request = hexdecode(argv[0]); + // "broadcast" + txid = 0x7df; + rxid = 0; + } + + // validate request: + if (request.size() == 0) { + writer->puts("ERROR: no request"); + return; + } else { + uint8_t type = request.at(0); + if ((POLL_TYPE_HAS_16BIT_PID(type) && request.size() < 3) || + (POLL_TYPE_HAS_8BIT_PID(type) && request.size() < 2)) { + writer->printf("ERROR: request too short for type %02X\n", type); + return; + } + } + + // execute request: + int err = OvmsVehicleRenaultZoePh2CAN->CanRequest(txid, rxid, request, response); + if (err == -1) { + writer->puts("ERROR: timeout waiting for response"); + return; + } else if (err) { + writer->printf("ERROR: request failed with response error code %02X\n", err); + return; + } + + // output response as hex dump: + writer->puts("Response:"); + char *buf = NULL; + size_t rlen = response.size(), offset = 0; + do { + rlen = FormatHexDump(&buf, response.data() + offset, rlen, 16); + offset += 16; + writer->puts(buf ? buf : "-"); + } while (rlen); + if (buf) + free(buf); +} + +int OvmsVehicleRenaultZoePh2CAN::CanRequest(uint16_t txid, uint16_t rxid, string request, string& response, int timeout_ms /*=3000*/) +{ + OvmsMutexLock lock(&zoe_can1_request); + + // prepare single poll: + OvmsVehicle::poll_pid_t poll[] = { + { txid, rxid, 0, 0, { 1, 1, 1 }, 0, ISOTP_STD }, + POLL_LIST_END + }; + + assert(request.size() > 0); + poll[0].type = request[0]; + + if (POLL_TYPE_HAS_16BIT_PID(poll[0].type)) { + assert(request.size() >= 3); + poll[0].args.pid = request[1] << 8 | request[2]; + poll[0].args.datalen = LIMIT_MAX(request.size()-3, sizeof(poll[0].args.data)); + memcpy(poll[0].args.data, request.data()+3, poll[0].args.datalen); + } + else if (POLL_TYPE_HAS_8BIT_PID(poll[0].type)) { + assert(request.size() >= 2); + poll[0].args.pid = request.at(1); + poll[0].args.datalen = LIMIT_MAX(request.size()-2, sizeof(poll[0].args.data)); + memcpy(poll[0].args.data, request.data()+2, poll[0].args.datalen); + } + else { + poll[0].args.pid = 0; + poll[0].args.datalen = LIMIT_MAX(request.size()-1, sizeof(poll[0].args.data)); + memcpy(poll[0].args.data, request.data()+1, poll[0].args.datalen); + } + + // stop default polling: + PollSetPidList(m_can1, NULL); + vTaskDelay(pdMS_TO_TICKS(100)); + + // clear rx semaphore, start single poll: + zoe_can1_rxwait.Take(0); + PollSetPidList(m_can1, poll); + + // wait for response: + bool rxok = zoe_can1_rxwait.Take(pdMS_TO_TICKS(timeout_ms)); + if (rxok == pdTRUE) + response = zoe_can1_rxbuf; + + // restore default polling: + zoe_can1_rxwait.Give(); + PollSetPidList(m_can1, renault_zoe_polls); + + return (rxok == pdFALSE) ? -1 : (int)zoe_can1_rxerr; +} + OvmsVehicle::vehicle_command_t OvmsVehicleRenaultZoePh2CAN::CommandPreHeat(bool climatecontrolon) { //ToDo: Sniff TCU packets for preheat/cool, OVMS is connected on TCU port return NotImplemented; diff --git a/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/vehicle_renaultzoe_ph2_can.h b/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/vehicle_renaultzoe_ph2_can.h index 9d66a11..58c3f70 100644 --- a/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/vehicle_renaultzoe_ph2_can.h +++ b/OVMS.V3/components/vehicle_renaultzoe_ph2_can/src/vehicle_renaultzoe_ph2_can.h @@ -99,6 +99,12 @@ class OvmsVehicleRenaultZoePh2CAN : public OvmsVehicle { virtual void Ticker10(uint32_t ticker);//Handle charge, energy statistics virtual void Ticker1(uint32_t ticker); //Handle trip counter + protected: + OvmsSemaphore zoe_can1_rxwait; + uint16_t zoe_can1_rxerr; + string zoe_can1_rxbuf; + OvmsMutex zoe_can1_request; + private: unsigned int m_can1_activity_timer;