2015-07-10 06:01:56 -07:00
|
|
|
/*
|
|
|
|
* @file obd2.cpp
|
|
|
|
*
|
|
|
|
* ISO 15765-4
|
|
|
|
* http://en.wikipedia.org/wiki/OBD-II_PIDs
|
|
|
|
*
|
|
|
|
* @date Jun 9, 2015
|
2020-01-13 18:57:43 -08:00
|
|
|
* @author Andrey Belomutskiy, (c) 2012-2020
|
2015-07-10 06:01:56 -07:00
|
|
|
*
|
|
|
|
* This file is part of rusEfi - see http://rusefi.com
|
|
|
|
*
|
|
|
|
* rusEfi is free software; you can redistribute it and/or modify it under the terms of
|
|
|
|
* the GNU General Public License as published by the Free Software Foundation; either
|
|
|
|
* version 3 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* rusEfi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
|
|
|
|
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with this program.
|
|
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2018-09-16 19:26:57 -07:00
|
|
|
#include "global.h"
|
2018-10-30 05:21:50 -07:00
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if EFI_CAN_SUPPORT
|
2019-07-03 18:01:48 -07:00
|
|
|
#include "os_access.h"
|
2017-12-17 18:10:02 -08:00
|
|
|
#include "engine.h"
|
2015-07-10 06:01:56 -07:00
|
|
|
#include "obd2.h"
|
2020-03-18 19:07:41 -07:00
|
|
|
#include "can_msg_tx.h"
|
2017-12-17 18:10:02 -08:00
|
|
|
#include "vehicle_speed.h"
|
|
|
|
#include "map.h"
|
|
|
|
#include "maf.h"
|
2020-04-03 16:59:08 -07:00
|
|
|
#include "sensor.h"
|
2017-12-17 18:10:02 -08:00
|
|
|
#include "engine_math.h"
|
|
|
|
#include "fuel_math.h"
|
2019-10-13 06:59:06 -07:00
|
|
|
#include "thermistors.h"
|
2020-07-29 02:54:47 -07:00
|
|
|
#include "ego.h"
|
2017-12-17 18:10:02 -08:00
|
|
|
|
2020-03-29 16:06:03 -07:00
|
|
|
EXTERN_ENGINE;
|
2017-12-17 18:10:02 -08:00
|
|
|
|
|
|
|
static const int16_t supportedPids0120[] = {
|
|
|
|
PID_MONITOR_STATUS,
|
|
|
|
PID_FUEL_SYSTEM_STATUS,
|
|
|
|
PID_ENGINE_LOAD,
|
|
|
|
PID_COOLANT_TEMP,
|
2020-07-29 12:15:01 -07:00
|
|
|
PID_STFT_BANK1,
|
2017-12-17 18:10:02 -08:00
|
|
|
PID_INTAKE_MAP,
|
|
|
|
PID_RPM,
|
|
|
|
PID_SPEED,
|
|
|
|
PID_TIMING_ADVANCE,
|
|
|
|
PID_INTAKE_TEMP,
|
|
|
|
PID_THROTTLE,
|
|
|
|
-1
|
|
|
|
};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
static const int16_t supportedPids2140[] = {
|
2020-07-29 12:17:11 -07:00
|
|
|
PID_FUEL_AIR_RATIO_1,
|
2017-12-17 18:10:02 -08:00
|
|
|
-1
|
|
|
|
};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
static const int16_t supportedPids4160[] = {
|
|
|
|
PID_FUEL_RATE,
|
|
|
|
-1
|
|
|
|
};
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
static void obdSendPacket(int mode, int PID, int numBytes, uint32_t iValue) {
|
2020-03-18 19:07:41 -07:00
|
|
|
CanTxMessage resp(OBD_TEST_RESPONSE);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
// write number of bytes
|
2020-03-18 19:07:41 -07:00
|
|
|
resp[0] = (uint8_t)(2 + numBytes);
|
2017-12-17 18:10:02 -08:00
|
|
|
// write 2 bytes of header
|
2020-03-18 19:07:41 -07:00
|
|
|
resp[1] = (uint8_t)(0x40 + mode);
|
|
|
|
resp[2] = (uint8_t)PID;
|
2017-12-17 18:10:02 -08:00
|
|
|
// write N data bytes
|
|
|
|
for (int i = 8 * (numBytes - 1), j = 3; i >= 0; i -= 8, j++) {
|
2020-03-18 19:07:41 -07:00
|
|
|
resp[j] = (uint8_t)((iValue >> i) & 0xff);
|
2017-12-17 18:10:02 -08:00
|
|
|
}
|
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
static void obdSendValue(int mode, int PID, int numBytes, float value) {
|
2018-07-25 20:03:04 -07:00
|
|
|
efiAssertVoid(CUSTOM_ERR_6662, numBytes <= 2, "invalid numBytes");
|
2017-12-17 18:10:02 -08:00
|
|
|
int iValue = (int)efiRound(value, 1.0f);
|
|
|
|
// clamp to uint8_t (0..255) or uint16_t (0..65535)
|
|
|
|
iValue = maxI(minI(iValue, (numBytes == 1) ? 255 : 65535), 0);
|
|
|
|
obdSendPacket(mode, PID, numBytes, iValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//#define MOCK_SUPPORTED_PIDS 0xffffffff
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
static void obdWriteSupportedPids(int PID, int bitOffset, const int16_t *supportedPids) {
|
|
|
|
uint32_t value = 0;
|
|
|
|
// gather all 32 bit fields
|
|
|
|
for (int i = 0; i < 32 && supportedPids[i] > 0; i++)
|
|
|
|
value |= 1 << (31 + bitOffset - supportedPids[i]);
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
#ifdef MOCK_SUPPORTED_PIDS
|
|
|
|
// for OBD debug
|
|
|
|
value = MOCK_SUPPORTED_PIDS;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
obdSendPacket(1, PID, 4, value);
|
|
|
|
}
|
|
|
|
|
2020-03-19 05:43:37 -07:00
|
|
|
static void handleGetDataRequest(const CANRxFrame& rx) {
|
|
|
|
int pid = rx.data8[2];
|
2017-12-17 18:10:02 -08:00
|
|
|
switch (pid) {
|
|
|
|
case PID_SUPPORTED_PIDS_REQUEST_01_20:
|
|
|
|
obdWriteSupportedPids(pid, 1, supportedPids0120);
|
|
|
|
break;
|
|
|
|
case PID_SUPPORTED_PIDS_REQUEST_21_40:
|
|
|
|
obdWriteSupportedPids(pid, 21, supportedPids2140);
|
|
|
|
break;
|
|
|
|
case PID_SUPPORTED_PIDS_REQUEST_41_60:
|
|
|
|
obdWriteSupportedPids(pid, 41, supportedPids4160);
|
|
|
|
break;
|
|
|
|
case PID_MONITOR_STATUS:
|
|
|
|
obdSendPacket(1, pid, 4, 0); // todo: add statuses
|
|
|
|
break;
|
|
|
|
case PID_FUEL_SYSTEM_STATUS:
|
|
|
|
// todo: add statuses
|
|
|
|
obdSendValue(1, pid, 2, (2<<8)|(0)); // 2 = "Closed loop, using oxygen sensor feedback to determine fuel mix"
|
|
|
|
break;
|
|
|
|
case PID_ENGINE_LOAD:
|
2020-07-28 12:13:55 -07:00
|
|
|
obdSendValue(1, pid, 1, getFuelingLoad(PASS_ENGINE_PARAMETER_SIGNATURE) * 2.55f);
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
|
|
|
case PID_COOLANT_TEMP:
|
2020-04-18 12:53:04 -07:00
|
|
|
obdSendValue(1, pid, 1, Sensor::get(SensorType::Clt).value_or(0) + 40.0f);
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
2020-07-29 12:15:01 -07:00
|
|
|
case PID_STFT_BANK1:
|
2020-07-29 14:27:57 -07:00
|
|
|
obdSendValue(1, pid, 1, 128 * ENGINE(engineState.running.pidCorrection));
|
2020-07-29 12:15:01 -07:00
|
|
|
break;
|
2017-12-17 18:10:02 -08:00
|
|
|
case PID_INTAKE_MAP:
|
2019-05-27 12:56:12 -07:00
|
|
|
obdSendValue(1, pid, 1, getMap(PASS_ENGINE_PARAMETER_SIGNATURE));
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
|
|
|
case PID_RPM:
|
2019-01-21 18:48:58 -08:00
|
|
|
obdSendValue(1, pid, 2, GET_RPM() * 4.0f); // rotation/min. (A*256+B)/4
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
|
|
|
case PID_SPEED:
|
|
|
|
obdSendValue(1, pid, 1, getVehicleSpeed());
|
|
|
|
break;
|
|
|
|
case PID_TIMING_ADVANCE: {
|
|
|
|
float timing = engine->engineState.timingAdvance;
|
|
|
|
timing = (timing > 360.0f) ? (timing - 720.0f) : timing;
|
|
|
|
obdSendValue(1, pid, 1, (timing + 64.0f) * 2.0f); // angle before TDC. (A/2)-64
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PID_INTAKE_TEMP:
|
2020-04-18 12:53:04 -07:00
|
|
|
obdSendValue(1, pid, 1, Sensor::get(SensorType::Iat).value_or(0) + 40.0f);
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
|
|
|
case PID_INTAKE_MAF:
|
2019-07-09 23:14:47 -07:00
|
|
|
obdSendValue(1, pid, 2, getRealMaf(PASS_ENGINE_PARAMETER_SIGNATURE) * 100.0f); // grams/sec (A*256+B)/100
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
|
|
|
case PID_THROTTLE:
|
2020-04-03 16:59:08 -07:00
|
|
|
obdSendValue(1, pid, 1, Sensor::get(SensorType::Tps1).value_or(0) * 2.55f); // (A*100/255)
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
2020-07-29 02:54:47 -07:00
|
|
|
case PID_FUEL_AIR_RATIO_1: {
|
|
|
|
float afr = getAfr(PASS_ENGINE_PARAMETER_SIGNATURE);
|
|
|
|
// phi = 1 / lambda
|
|
|
|
float phi = clampF(0, 14.7f / afr, 1.99f);
|
|
|
|
|
|
|
|
uint16_t scaled = phi * 32768;
|
|
|
|
|
|
|
|
obdSendPacket(1, pid, 4, scaled << 16);
|
|
|
|
break;
|
|
|
|
} case PID_FUEL_RATE:
|
2017-12-31 16:25:59 -08:00
|
|
|
obdSendValue(1, pid, 2, engine->engineState.fuelConsumption.perSecondConsumption * 20.0f); // L/h. (A*256+B)/20
|
2017-12-17 18:10:02 -08:00
|
|
|
break;
|
|
|
|
default:
|
2020-07-05 21:20:27 -07:00
|
|
|
// ignore unhandled PIDs
|
|
|
|
break;
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
2017-12-17 18:10:02 -08:00
|
|
|
}
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2017-12-17 18:10:02 -08:00
|
|
|
static void handleDtcRequest(int numCodes, int *dtcCode) {
|
2020-03-18 19:07:41 -07:00
|
|
|
// TODO: this appears to be unfinished?
|
2020-04-12 06:39:14 -07:00
|
|
|
UNUSED(numCodes);
|
|
|
|
UNUSED(dtcCode);
|
|
|
|
|
2020-03-18 19:07:41 -07:00
|
|
|
// int numBytes = numCodes * 2;
|
|
|
|
// // write CAN-TP Single Frame header?
|
|
|
|
// txmsg.data8[0] = (uint8_t)((0 << 4) | numBytes);
|
|
|
|
// for (int i = 0, j = 1; i < numCodes; i++) {
|
|
|
|
// txmsg.data8[j++] = (uint8_t)((dtcCode[i] >> 8) & 0xff);
|
|
|
|
// txmsg.data8[j++] = (uint8_t)(dtcCode[i] & 0xff);
|
|
|
|
// }
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
|
2019-04-12 19:07:03 -07:00
|
|
|
#if HAL_USE_CAN
|
2020-03-19 05:43:37 -07:00
|
|
|
void obdOnCanPacketRx(const CANRxFrame& rx) {
|
|
|
|
if (rx.SID != OBD_TEST_REQUEST) {
|
2015-07-10 06:01:56 -07:00
|
|
|
return;
|
|
|
|
}
|
2020-07-05 21:20:27 -07:00
|
|
|
|
2020-08-31 19:00:03 -07:00
|
|
|
if (rx.data8[0] == _OBD_2 && rx.data8[1] == OBD_CURRENT_DATA) {
|
2015-07-10 06:01:56 -07:00
|
|
|
handleGetDataRequest(rx);
|
2020-03-19 05:43:37 -07:00
|
|
|
} else if (rx.data8[0] == 1 && rx.data8[1] == OBD_STORED_DIAGNOSTIC_TROUBLE_CODES) {
|
2017-12-17 18:10:02 -08:00
|
|
|
// todo: implement stored/pending difference?
|
2019-01-11 06:58:48 -08:00
|
|
|
handleDtcRequest(1, &engine->engineState.warnings.lastErrorCode);
|
2020-03-19 05:43:37 -07:00
|
|
|
} else if (rx.data8[0] == 1 && rx.data8[1] == OBD_PENDING_DIAGNOSTIC_TROUBLE_CODES) {
|
2017-12-17 18:10:02 -08:00
|
|
|
// todo: implement stored/pending difference?
|
2019-01-11 06:58:48 -08:00
|
|
|
handleDtcRequest(1, &engine->engineState.warnings.lastErrorCode);
|
2015-07-10 06:01:56 -07:00
|
|
|
}
|
|
|
|
}
|
2018-11-16 04:40:06 -08:00
|
|
|
#endif /* HAL_USE_CAN */
|
2015-07-10 06:01:56 -07:00
|
|
|
|
2018-10-30 05:21:50 -07:00
|
|
|
#endif /* EFI_CAN_SUPPORT */
|