Separate old OBD display project from vendor demo folder
- Move user sketches to 10-OBD-Display-2024/, one folder per sketch - Keep 2-Program Example/Demo_Arduino vendor-only, single docs/ copy - Remove duplicate screenshots/instructions and ELMulator zip - Archive broken LVGL 9 attempt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9ee85bfd86
commit
9cefb9ba75
102 files changed
+32
-51
No files matched your search
@@ -0,0 +1,162 @@
|
||||
#include "ATCommands.h"
|
||||
#include "definitions.h"
|
||||
|
||||
#if USE_WIFI
|
||||
ATCommands::ATCommands(OBDWiFiComm *connection) {
|
||||
this->connection = connection;
|
||||
}
|
||||
#else
|
||||
ATCommands::ATCommands(OBDSerialComm *connection) {
|
||||
this->connection = connection;
|
||||
}
|
||||
#endif
|
||||
|
||||
ATCommands::~ATCommands() {
|
||||
operator delete(this->connection);
|
||||
}
|
||||
|
||||
|
||||
bool ATCommands::process(const String& command) {
|
||||
bool processed = false;
|
||||
if (isATCommand(command)) {
|
||||
processed = true;
|
||||
processCommand(command);
|
||||
DEBUG("RX AT: " + command);
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
void ATCommands::processCommand(const String& command) {
|
||||
|
||||
// if space is enabled (ex: AT H[charPosition])
|
||||
uint8_t offset = 2;
|
||||
if (command.charAt(2) == 0x20) {
|
||||
offset = 3;
|
||||
}
|
||||
|
||||
// refer to ELM327 specs
|
||||
String specificCommand = command.substring(offset, command.length());
|
||||
if (specificCommand.startsWith("D",offset)) {
|
||||
ATCommands::ATD();
|
||||
} else if (specificCommand.startsWith("Z")) {
|
||||
ATCommands::ATZ();
|
||||
} else if (specificCommand.startsWith("I")) {
|
||||
ATCommands::ATI();
|
||||
} else if (specificCommand.startsWith("E")) {
|
||||
ATCommands::ATEx(specificCommand);
|
||||
} else if (specificCommand.startsWith("L")) {
|
||||
ATCommands::ATLx(specificCommand);
|
||||
} else if (specificCommand.startsWith("M")) {
|
||||
ATCommands::ATMx(specificCommand);
|
||||
} else if (specificCommand.startsWith("S")) {
|
||||
if (specificCommand.startsWith("SP")) {
|
||||
ATCommands::ATSPx(specificCommand);
|
||||
} else {
|
||||
ATCommands::ATSx(specificCommand);
|
||||
}
|
||||
} else if (specificCommand.startsWith("H")) {
|
||||
ATCommands::ATHx(specificCommand);
|
||||
} else if (specificCommand.startsWith("AT")) {
|
||||
ATCommands::ATATx(specificCommand);
|
||||
} else if (specificCommand.startsWith("DPN")) {
|
||||
ATCommands::ATDPN();
|
||||
} else if (specificCommand.startsWith("DESC") || specificCommand.startsWith("@1")) {
|
||||
ATCommands::ATDESC();
|
||||
} else if (specificCommand.startsWith("PC")) {
|
||||
ATCommands::ATPC();
|
||||
} else if (specificCommand.startsWith("RV")){
|
||||
ATCommands::ATRV();
|
||||
} else {
|
||||
|
||||
// lets assume we process any at command
|
||||
connection->writeEndOK();
|
||||
}
|
||||
}
|
||||
|
||||
// set all to defaults
|
||||
void ATCommands::ATD() {
|
||||
connection->setToDefaults();
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// reset all
|
||||
void ATCommands::ATZ() {
|
||||
connection->setToDefaults();
|
||||
connection->writeTo(ID);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// Print the version ID
|
||||
void ATCommands::ATI() {
|
||||
connection->writeTo(ID);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// send description
|
||||
void ATCommands::ATDESC() {
|
||||
connection->writeTo(DESC);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// set echoEnable 0=off 1=on
|
||||
void ATCommands::ATEx(String& cmd) {
|
||||
connection->setEcho(cmd.equals("E0") ? false : true);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// set memory off=0 on=1
|
||||
void ATCommands::ATMx(String& cmd) {
|
||||
connection->setMemory(cmd.equals("M0") ? false : true);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// line feeds off=0 on=1
|
||||
void ATCommands::ATLx(String& cmd) {
|
||||
connection->setLineFeeds(cmd.equals("L0") ? false : true);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// ATSx printing spaces off=0 on=1
|
||||
void ATCommands::ATSx(String& cmd) {
|
||||
connection->setWhiteSpaces(cmd.equals("S0") ? false : true);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// Headers off=0 on=1
|
||||
void ATCommands::ATHx(String& cmd) {
|
||||
connection->setHeaders(cmd.equals("H0") ? false : true);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// ATSPx Define protocol 0=auto
|
||||
void ATCommands::ATSPx(String& cmd) {
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// set protocol
|
||||
void ATCommands::ATDPN() {
|
||||
connection->writeTo(PROTOCOL);
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// AT AT2 adaptative time control
|
||||
void ATCommands::ATATx(String& cmd) {
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
// Terminates current diagnostic session. Protocol close
|
||||
void ATCommands::ATPC() {
|
||||
connection->writeEndOK();
|
||||
}
|
||||
|
||||
void ATCommands::ATRV() {
|
||||
connection->writeTo("AT RV\r13.5V");
|
||||
connection->writeEnd();
|
||||
}
|
||||
|
||||
// return true ir connectionand is AT
|
||||
bool ATCommands::isATCommand(const String& command) {
|
||||
toUpperCase(command.charAt(0));
|
||||
return command.startsWith("AT") ? true : false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#ifndef ELMulator_ATCommands_h
|
||||
#define ELMulator_ATCommands_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "definitions.h"
|
||||
#if USE_WIFI
|
||||
#include "OBDWiFiComm.h"
|
||||
#else
|
||||
#include "OBDSerialComm.h"
|
||||
#endif
|
||||
|
||||
class ATCommands
|
||||
{
|
||||
|
||||
public:
|
||||
#if USE_WIFI
|
||||
ATCommands(OBDWiFiComm *connection);
|
||||
#else
|
||||
ATCommands(OBDSerialComm *connection);
|
||||
#endif
|
||||
~ATCommands();
|
||||
|
||||
bool process(const String &string);
|
||||
|
||||
private:
|
||||
// Variables
|
||||
#if USE_WIFI
|
||||
OBDWiFiComm *connection;
|
||||
#else
|
||||
OBDSerialComm *connection;
|
||||
#endif
|
||||
void ATD();
|
||||
|
||||
void ATZ();
|
||||
|
||||
void ATI();
|
||||
|
||||
void ATEx(String &x);
|
||||
|
||||
void ATMx(String &x);
|
||||
|
||||
void ATLx(String &x);
|
||||
|
||||
void ATSx(String &x);
|
||||
|
||||
void ATHx(String &x);
|
||||
|
||||
void ATSPx(String &x);
|
||||
|
||||
void ATATx(String &cmd);
|
||||
|
||||
void ATPC();
|
||||
|
||||
void ATDPN();
|
||||
|
||||
void ATDESC();
|
||||
|
||||
void ATRV();
|
||||
|
||||
void processCommand(const String &command);
|
||||
|
||||
bool isATCommand(const String &command);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,218 @@
|
||||
#include "ELMulator.h"
|
||||
|
||||
#if USE_WIFI
|
||||
ELMulator::ELMulator()
|
||||
{
|
||||
_connection = new OBDWiFiComm();
|
||||
_atProcessor = new ATCommands(_connection);
|
||||
_pidProcessor = new PidProcessor(_connection);
|
||||
_lastCommand = "";
|
||||
elmRequest.reserve(MAX_REQUEST_SIZE);
|
||||
elmRequest = "";
|
||||
}
|
||||
#else
|
||||
ELMulator::ELMulator()
|
||||
{
|
||||
_connection = new OBDSerialComm();
|
||||
_atProcessor = new ATCommands(_connection);
|
||||
_pidProcessor = new PidProcessor(_connection);
|
||||
_lastCommand = "";
|
||||
elmRequest.reserve(MAX_REQUEST_SIZE);
|
||||
elmRequest = "";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
ELMulator::~ELMulator() {}
|
||||
|
||||
void ELMulator::init(const String &deviceName, bool registerPids)
|
||||
{
|
||||
_connection->init(deviceName);
|
||||
if (registerPids)
|
||||
{
|
||||
registerAllMode01Pids();
|
||||
}
|
||||
}
|
||||
|
||||
void ELMulator::registerAllMode01Pids()
|
||||
{
|
||||
// Set up PIDs 0x00 to 0x65
|
||||
// Will be provided a response with mock data value if no special handling is performed.
|
||||
// Requests for PID > 0x65 are not currently supported - will return "NO DATA"
|
||||
for (int i = 0; i < 0x66; i++)
|
||||
{
|
||||
_pidProcessor->registerMode01Pid(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool ELMulator::readELMRequest()
|
||||
{
|
||||
do
|
||||
{
|
||||
elmRequest.clear(); // clear buffer from previous requests
|
||||
_connection->readData(elmRequest);
|
||||
elmRequest.toUpperCase();
|
||||
// TODO ignore spaces, and all control chars (tab, etc)
|
||||
// TODO accept single carriage return as repeat last command at or pid
|
||||
// ignore null i.e 00
|
||||
} while (processRequest(elmRequest)); // processRequest handles all non PID requests (AT commands, errors etc)
|
||||
return true; // We have received a valid PID request we need to respond to
|
||||
}
|
||||
|
||||
void ELMulator::sendELMResponse()
|
||||
{
|
||||
// Respond to any mode 01 request with a mock sensor value
|
||||
if (isMode01(elmRequest))
|
||||
{
|
||||
uint8_t pidCode = getPidCode(elmRequest);
|
||||
writePidResponse(elmRequest, responseBytes[pidCode], getMockSensorValue());
|
||||
return;
|
||||
}
|
||||
// Not a mode 01 PID request. Report it as not supported (ie, "NO DATA");
|
||||
else
|
||||
{
|
||||
writePidNotSupported();
|
||||
}
|
||||
}
|
||||
|
||||
void ELMulator::begin()
|
||||
{
|
||||
while (readELMRequest())
|
||||
{
|
||||
sendELMResponse();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ELMulator::getPidCode(const String &request)
|
||||
{
|
||||
return _pidProcessor->getPidCodeFromRequest(request);
|
||||
}
|
||||
|
||||
bool ELMulator::registerMode01Pid(uint32_t pid)
|
||||
{
|
||||
return _pidProcessor->registerMode01Pid(pid);
|
||||
}
|
||||
|
||||
bool ELMulator::registerMode01MILResponse(const String &response)
|
||||
{
|
||||
return _pidProcessor->registerMode01MILResponse(response);
|
||||
}
|
||||
|
||||
bool ELMulator::registerMode03Response(const String &response)
|
||||
{
|
||||
return _pidProcessor->registerMode03Response(response);
|
||||
}
|
||||
|
||||
void ELMulator::writePidNotSupported()
|
||||
{
|
||||
_connection->writeEndNoData();
|
||||
}
|
||||
|
||||
void ELMulator::writePidResponse(const String &requestPid, uint8_t numberOfBytes, uint32_t value)
|
||||
{
|
||||
_pidProcessor->writePidResponse(requestPid, numberOfBytes, value);
|
||||
}
|
||||
|
||||
void ELMulator::writeResponse(const String &response)
|
||||
{
|
||||
_connection->writeTo(response.c_str());
|
||||
_connection->writeEnd();
|
||||
}
|
||||
|
||||
bool ELMulator::processRequest(String &command)
|
||||
{
|
||||
|
||||
// TODO: check for no 0X0D char in command, return ? and >
|
||||
// TODO: receive only <cr>, repeat last command
|
||||
|
||||
// carriage return, means repeat last command
|
||||
if (command == "\n")
|
||||
{
|
||||
command = _lastCommand;
|
||||
}
|
||||
|
||||
// empty command, do not send to user
|
||||
if (command.length() == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for AT command
|
||||
if (_atProcessor->process(command))
|
||||
{
|
||||
_lastCommand = command;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for a valid hex string, return error if false
|
||||
if (!isValidHex(command.c_str()))
|
||||
{
|
||||
_connection->writeEndUnknown();
|
||||
DEBUG("Invalid HEX command: " + command);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for a valid PID request
|
||||
if (_pidProcessor->process(command))
|
||||
{
|
||||
_lastCommand = command;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ELMulator::isValidHex(const char *pid)
|
||||
{
|
||||
return (pid[strspn(pid, "0123456789abcdefABCDEF")] == 0);
|
||||
}
|
||||
|
||||
bool ELMulator::isMode01(const String &command)
|
||||
{
|
||||
return _pidProcessor->isMode01(command);
|
||||
}
|
||||
|
||||
bool ELMulator::isMode22(const String &command)
|
||||
{
|
||||
return _pidProcessor->isMode22(command);
|
||||
}
|
||||
|
||||
bool ELMulator::isMode03(const String &command)
|
||||
{
|
||||
return _pidProcessor->isMode03(command);
|
||||
}
|
||||
|
||||
bool ELMulator::isMode01MIL(const String &command)
|
||||
{
|
||||
return _pidProcessor->isMode01MIL(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fake some data
|
||||
* start counter = 0
|
||||
* every call to getFakeSensorData, will increment the counter to a max of 255 (0xff)
|
||||
* When 0xff is reached the cycle is reverted
|
||||
* and the counter will decrement by one until 0 is reached
|
||||
*/
|
||||
uint32_t ELMulator::getMockSensorValue()
|
||||
{
|
||||
if (isCycleUp)
|
||||
{
|
||||
cycle++;
|
||||
if (cycle == 0xff)
|
||||
{
|
||||
isCycleUp = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cycle--;
|
||||
if (cycle == 0)
|
||||
{
|
||||
isCycleUp = true;
|
||||
}
|
||||
}
|
||||
|
||||
return cycle;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
#ifndef ELMulator_ELMulator_h
|
||||
#define ELMulator_ELMulator_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "definitions.h"
|
||||
|
||||
#if USE_WIFI
|
||||
#include "OBDWiFiComm.h"
|
||||
#else
|
||||
#include "OBDSerialComm.h"
|
||||
#endif
|
||||
|
||||
#include "ATCommands.h"
|
||||
#include "PidProcessor.h"
|
||||
#include "definitions.h"
|
||||
|
||||
class ELMulator
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* When creating a new instance of ELMulator with an attached
|
||||
* BT module, we need to set the Bluetooth serial parameters
|
||||
*
|
||||
* @param baudRate - rate for bluetooth serial port (normally 9600)
|
||||
* @param rxPin - the Arduino RX pin for the Bluetooth module (serial port)
|
||||
* @param txPin - the Arduino TX pin for the Bluetooth module (serial port)
|
||||
* @return
|
||||
*/
|
||||
ELMulator(uint32_t baudRate, uint8_t rxPin, uint8_t txPin);
|
||||
|
||||
ELMulator();
|
||||
|
||||
~ELMulator();
|
||||
|
||||
void init(const String &deviceName, const bool registerPids = false);
|
||||
|
||||
/**
|
||||
* Waits and Reads a request from OBD client software (example: torque)
|
||||
*
|
||||
* It will only return if the OBD client software
|
||||
* request's one of the previous registred PID (see: registerMode01Pid())
|
||||
*
|
||||
* Any other request will be automaticly handle or it will be rejected.
|
||||
*
|
||||
* ELMulator lib will automaticly handle:
|
||||
* - any AT command
|
||||
* - PID's support request like 0100, 0120, 0140, 0160, ...
|
||||
*
|
||||
* @return the request PID (Vehicle speed ex: 010D )
|
||||
*/
|
||||
bool readELMRequest();
|
||||
void sendELMResponse();
|
||||
void begin();
|
||||
|
||||
/**
|
||||
* Registry the PID's (sensors) your arduino will support.
|
||||
* Currently ELMulator lib only supports MODE 01 PID's
|
||||
*
|
||||
* In OBDII MODE 01 PID's, are request
|
||||
* to Show current data for a given sensor identified by a PID
|
||||
*
|
||||
* List of MODE 01 PID's: https://en.wikipedia.org/wiki/OBD-II_PIDs#Mode_01
|
||||
*
|
||||
* Example, for Vehicle speed, where OBDII PID code is 0D:
|
||||
*
|
||||
* registerMode01Pid(0x0D)
|
||||
*
|
||||
* @param pidHexId
|
||||
* @return returns true if the entered ID is in the valide range [0x00, 0xFF]
|
||||
*/
|
||||
bool registerMode01Pid(uint32_t pidHexId);
|
||||
|
||||
bool registerMode01MILResponse(const String &response);
|
||||
|
||||
bool registerMode03Response(const String &response);
|
||||
|
||||
uint8_t getPidCodeOnly(uint16_t hexCommand);
|
||||
|
||||
/**
|
||||
* Used to informe the OBD client that the PID,
|
||||
* it has requested is not supported
|
||||
*
|
||||
* In normal conditions, you will only receive,
|
||||
* request for the PID you have registred
|
||||
* All other request is automaticly handle by GTTuboEcu lib
|
||||
*/
|
||||
void writePidNotSupported();
|
||||
|
||||
/**
|
||||
* Respond to a given PID request from OBDII client (ex: torque)
|
||||
*
|
||||
* @param requestPid - the received pid
|
||||
* @param numberOfBytes - number of bytes this PID response VALUE is supposed to have
|
||||
* @param value - sensor value for this PID,
|
||||
* lib will convert it to HEX
|
||||
* with the appropriated number of HEX chars (numberOfChars)
|
||||
*/
|
||||
void writePidResponse(const String &requestPid, uint8_t numberOfBytes, uint32_t value);
|
||||
|
||||
// Write the response back to the requestor without PID formatting, etc
|
||||
// Just pass the response string on. Useful for testing with a specific response
|
||||
// that has been pre-configured.
|
||||
void writeResponse(const String &response);
|
||||
|
||||
bool isMode01(const String &command);
|
||||
bool isMode03(const String &command);
|
||||
bool isMode01MIL(const String &command);
|
||||
bool isMode22(const String &command);
|
||||
|
||||
uint8_t getPidCode(const String &request);
|
||||
void registerAllMode01Pids();
|
||||
uint32_t getMockSensorValue();
|
||||
|
||||
String elmRequest;
|
||||
|
||||
private:
|
||||
#if USE_WIFI
|
||||
OBDWiFiComm *_connection;
|
||||
#else
|
||||
OBDSerialComm *_connection;
|
||||
#endif
|
||||
ATCommands *_atProcessor;
|
||||
|
||||
PidProcessor *_pidProcessor;
|
||||
|
||||
String _lastCommand;
|
||||
|
||||
bool isCycleUp = true;
|
||||
|
||||
uint32_t cycle = 0;
|
||||
|
||||
bool processRequest(String &command);
|
||||
|
||||
bool isValidHex(const char *pid);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <Arduino.h>
|
||||
#include <ELMulator.h>
|
||||
#include <definitions.h>
|
||||
|
||||
void handlePIDRequest(const String& pidRequest);
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
#include "ESP32_Custom_ELMulator.h"
|
||||
|
||||
const String deviceName = "ELMULATOR"; // Bluetooth device name to use (no pin)
|
||||
|
||||
// Set up hardcoded responses to non-standard PID requests for MIL, DTC, ODO data
|
||||
const String milResponse = "4101830000"; // MIL response code indicating 3 current DTC
|
||||
const String dtcResponse = "43010341\r\n43010123\r\n43010420"; // DTC response returning 3 DTC codes (multiline response)
|
||||
const uint32_t odoResponse = 1234567; // Hardcode an odometer reading of 1234567
|
||||
const String ethPercentResponse = "620052C6";
|
||||
const String dpfCloggingResponse = "6218E4C6";
|
||||
|
||||
ELMulator ELMulator;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println("Starting ELMulator...");
|
||||
ELMulator.init(deviceName);
|
||||
|
||||
// Register the specific PIDs we are going to handle.
|
||||
// ELMulator will respond to SUPPORTED_PIDS request ("0101") with the appropriate value
|
||||
// indicating which PIDs it can respond to.
|
||||
ELMulator.registerMode01Pid(ODOMETER);
|
||||
ELMulator.registerMode01Pid(ENGINE_COOLANT_TEMP);
|
||||
ELMulator.registerMode01Pid(ENGINE_RPM);
|
||||
ELMulator.registerMode01Pid(MONITOR_STATUS_SINCE_DTC_CLEARED);
|
||||
ELMulator.registerMode01Pid(INTAKE_MANIFOLD_ABS_PRESSURE);
|
||||
ELMulator.registerMode01Pid(ENGINE_LOAD);
|
||||
ELMulator.registerMode01Pid(VEHICLE_SPEED);
|
||||
ELMulator.registerMode01Pid(INTAKE_AIR_TEMP);
|
||||
ELMulator.registerMode01Pid(THROTTLE_POSITION);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
/**
|
||||
* Waits for a new request from an ELM client and does some pre-processing to validate the PID and request.
|
||||
* Non-PID requests like AT commands and SUPPORTED_PIDS queries will be handled by ELMulator automatically.
|
||||
* PID requests will be verified as supported (registered); unsupported PIDs responded to with NO DATA response.
|
||||
* Returns true if the request is for one of the PIDS we have registered above so we can respond to it.
|
||||
*/
|
||||
if (ELMulator.readELMRequest())
|
||||
{
|
||||
handlePIDRequest(ELMulator.elmRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* After receiving a supported PID(sensor) request, we prepare the response here.
|
||||
* Response can come from a hardcoded value, a real hardware sensor, or a mock value.
|
||||
* Default response is a mock value if no other handling is provided.
|
||||
*/
|
||||
void handlePIDRequest(const String &request)
|
||||
{
|
||||
// Handle special case requests like MIL and DTC checks
|
||||
if (ELMulator.isMode03(request)) // Mode 03 request == Returns (hardcoded) list current DTC codes
|
||||
{
|
||||
if (dtcResponse.length())
|
||||
{
|
||||
ELMulator.writeResponse(dtcResponse);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG("DTC response is empty.");
|
||||
ELMulator.writePidNotSupported();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if (ELMulator.isMode01MIL(request)) // Mode 0101 MIL request == Returns (hardcoded) number of current DTC codes
|
||||
{
|
||||
if (milResponse.length())
|
||||
{
|
||||
ELMulator.writeResponse(milResponse);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG("MIL response is empty.");
|
||||
ELMulator.writePidNotSupported();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
else if (ELMulator.isMode22(request)) // Mode 0x22 (extended info) service - Mfg-dependent and not defined in OBDII spec
|
||||
{
|
||||
|
||||
Serial.print("Mode 22 PID: "); Serial.println(request.substring(2));
|
||||
|
||||
if (request.substring(2).compareTo("52") == 0) // Ethanol percent
|
||||
{
|
||||
if (ethPercentResponse.length())
|
||||
{
|
||||
ELMulator.writeResponse(ethPercentResponse);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG("ETH % response is empty.");
|
||||
ELMulator.writePidNotSupported();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (request.substring(2).compareTo("18E4") == 0) // DPF Clogging A-R Giulia
|
||||
{
|
||||
if (dpfCloggingResponse.length())
|
||||
{
|
||||
ELMulator.writeResponse(dpfCloggingResponse);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG("DPF Clogging response is empty.");
|
||||
ELMulator.writePidNotSupported();
|
||||
return;
|
||||
}
|
||||
}
|
||||
ELMulator.writePidNotSupported();
|
||||
return;
|
||||
}
|
||||
else // Handle any other supported PID request
|
||||
{
|
||||
uint8_t pidCode = ELMulator.getPidCode(request); // Extract the specific PID code from the request
|
||||
|
||||
// Example response for 0x05 (Engine Coolant Temp) - returning a mock data value
|
||||
if (pidCode == ENGINE_COOLANT_TEMP)
|
||||
{
|
||||
uint32_t sensorValue = ELMulator.getMockSensorValue();
|
||||
|
||||
/**
|
||||
* Response parameters:
|
||||
* request - specifies the original PID request being responded to.
|
||||
* numberOfBytes - the number of bytes this PID value returns (per OBDII spec), using lookup table responseBytes.
|
||||
* sensorValue - the value to return in our response; a mock value in this example.
|
||||
*/
|
||||
ELMulator.writePidResponse(request, responseBytes[pidCode], sensorValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Example response for PID 0x0C (Engine RPM) - returns a modified mock sensor value
|
||||
else if (pidCode == ENGINE_RPM)
|
||||
{
|
||||
uint16_t rpmValue = ELMulator.getMockSensorValue() * 100; // Here we multiply the mock value provided, for a more realistic RPM number
|
||||
ELMulator.writePidResponse(request, responseBytes[pidCode], rpmValue);
|
||||
return;
|
||||
}
|
||||
|
||||
// Example response for PID 0xA6 (Odometer) - returns our hardcoded odometer response string
|
||||
else if (pidCode == ODOMETER)
|
||||
{
|
||||
ELMulator.writePidResponse(request, responseBytes[pidCode], odoResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
// // Example response for PID 0xOD (Vehicle speed) - returns a value from external GPS
|
||||
// else if (pidCode == VEHICLE_SPEED)
|
||||
// {
|
||||
// uint32_t gpsSpeed = myGPS.speed();
|
||||
// ELMulator.writePidResponse(request, responseBytes[pidCode], gpsSpeed);
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Default response for any other supported PID request - returns an unmodified mock sensor value
|
||||
else
|
||||
{
|
||||
ELMulator.writePidResponse(request, responseBytes[pidCode], ELMulator.getMockSensorValue());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "OBDSerialComm.h"
|
||||
#include "definitions.h"
|
||||
|
||||
|
||||
OBDSerialComm::OBDSerialComm() {
|
||||
|
||||
}
|
||||
|
||||
OBDSerialComm::~OBDSerialComm() {
|
||||
operator delete(serial);
|
||||
}
|
||||
|
||||
void OBDSerialComm::init(const String& deviceName) {
|
||||
Serial.println("Starting BT . . .");
|
||||
serial = new BluetoothSerial();
|
||||
//delay(2000);
|
||||
serial->begin(deviceName, false);
|
||||
setToDefaults();
|
||||
|
||||
}
|
||||
|
||||
void OBDSerialComm::writeEnd() {
|
||||
|
||||
// 1 - write carriage return
|
||||
writeTo("\r");
|
||||
|
||||
// 2- (optional ) write linefeed
|
||||
if (lineFeedEnable) {
|
||||
writeTo("\n");
|
||||
}
|
||||
|
||||
// 3 - Write prompt
|
||||
writeTo(">");
|
||||
|
||||
serial->flush();
|
||||
};
|
||||
|
||||
|
||||
void OBDSerialComm::writeEndOK() {
|
||||
writeTo("OK");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDSerialComm::writeEndERROR() {
|
||||
writeTo("ERROR");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDSerialComm::writeEndNoData() {
|
||||
writeTo("NO DATA");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDSerialComm::writeEndUnknown() {
|
||||
writeTo("?");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDSerialComm::setToDefaults() {
|
||||
setEcho(true);
|
||||
setStatus(READY);
|
||||
setWhiteSpaces(true);
|
||||
setHeaders(false);
|
||||
setLineFeeds(true);
|
||||
setMemory(false);
|
||||
}
|
||||
|
||||
void OBDSerialComm::writeTo(char const *response) {
|
||||
serial->print(response);
|
||||
}
|
||||
|
||||
|
||||
void OBDSerialComm::writeTo(uint8_t cChar) {
|
||||
serial->print(cChar);
|
||||
}
|
||||
|
||||
void OBDSerialComm::writeEndPidTo(char const *response) {
|
||||
if (whiteSpacesEnabled) {
|
||||
uint8_t len = strlen(response);
|
||||
char spacedResponse[len + len / 2 + 1];
|
||||
addSpacesToResponse(response, spacedResponse);
|
||||
writeTo(spacedResponse);
|
||||
} else {
|
||||
writeTo(response);
|
||||
}
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDSerialComm::readData(String& rxData) {
|
||||
serial->flush(); // temp remove this
|
||||
rxData = serial->readStringUntil(SERIAL_END_CHAR);
|
||||
if (isEchoEnable()) {
|
||||
writeTo(rxData.c_str());
|
||||
}
|
||||
//return rxData;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setBaudRate(uint32_t rate) {
|
||||
this->baudRate = rate;
|
||||
}
|
||||
|
||||
long OBDSerialComm::getBaudRate() {
|
||||
return this->baudRate;
|
||||
}
|
||||
|
||||
bool OBDSerialComm::isEchoEnable() {
|
||||
return this->echoEnable;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setEcho(bool echo) {
|
||||
this->echoEnable = echo;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setStatus(STATUS status) {
|
||||
this->status = status;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setLineFeeds(bool status) {
|
||||
this->lineFeedEnable = status;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setMemory(bool status) {
|
||||
this->memoryEnabled = status;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setWhiteSpaces(bool status) {
|
||||
this->whiteSpacesEnabled = status;
|
||||
}
|
||||
|
||||
void OBDSerialComm::setHeaders(bool status) {
|
||||
this->headersEnabled = status;
|
||||
}
|
||||
|
||||
void OBDSerialComm::addSpacesToResponse(const char *response, char spacedRes[]) {
|
||||
uint8_t len = strlen(response);
|
||||
int j = 0;
|
||||
for (int i = 0; i < len;) {
|
||||
*(spacedRes + j++) = *(response + i++);
|
||||
*(spacedRes + j++) = *(response + i++);
|
||||
if (i < len) {
|
||||
*(spacedRes + j++) = 0x20;
|
||||
}
|
||||
}
|
||||
*(spacedRes + j) = '\0';
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef ELMulator_OBDSerialComm_h
|
||||
#define ELMulator_OBDSerialComm_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "definitions.h"
|
||||
|
||||
#include <BluetoothSerial.h>
|
||||
|
||||
|
||||
class OBDSerialComm
|
||||
{
|
||||
public:
|
||||
enum STATUS
|
||||
{
|
||||
IDLE = 0,
|
||||
READY = 1
|
||||
};
|
||||
|
||||
// // Bluetooth is not built in, we are using a BT module via GPIO
|
||||
// OBDSerialComm(uint32_t baudRate, uint8_t rxPin, uint8_t txPin);
|
||||
|
||||
OBDSerialComm();
|
||||
|
||||
~OBDSerialComm();
|
||||
|
||||
void init(const String &deviceName);
|
||||
|
||||
void writeEndOK();
|
||||
|
||||
void writeEndERROR();
|
||||
|
||||
/**
|
||||
* Response for unsupported PID command or missing sensor, respond "NO DATA".
|
||||
*/
|
||||
void writeEndNoData();
|
||||
|
||||
/**
|
||||
* Response for invalid AT command, or invalid PID or other bad input, respond "?"
|
||||
*/
|
||||
void writeEndUnknown();
|
||||
|
||||
void setToDefaults();
|
||||
|
||||
void readData(String &rxData);
|
||||
|
||||
void writeTo(uint8_t cChar);
|
||||
|
||||
void writeTo(char const *string);
|
||||
|
||||
void setEcho(bool echo);
|
||||
|
||||
void writeEnd();
|
||||
|
||||
bool isEchoEnable();
|
||||
|
||||
void setLineFeeds(bool status);
|
||||
|
||||
void setMemory(bool status);
|
||||
|
||||
void setWhiteSpaces(bool status);
|
||||
|
||||
void setHeaders(bool status);
|
||||
|
||||
void setStatus(STATUS status);
|
||||
|
||||
void writeEndPidTo(char const *string);
|
||||
|
||||
private:
|
||||
uint32_t baudRate; // Serial Baud Rate
|
||||
STATUS status; // Operation status
|
||||
bool echoEnable; // echoEnable command after received
|
||||
bool lineFeedEnable;
|
||||
bool memoryEnabled;
|
||||
bool whiteSpacesEnabled;
|
||||
bool headersEnabled;
|
||||
|
||||
void setBaudRate(uint32_t rate);
|
||||
|
||||
long getBaudRate();
|
||||
|
||||
void addSpacesToResponse(const char *response, char string[]);
|
||||
|
||||
#ifndef BLUETOOTH_BUILTIN
|
||||
HardwareSerial *serial; // lib to communicate with bluetooth
|
||||
#else
|
||||
BluetoothSerial *serial;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,151 @@
|
||||
#include "OBDWiFiComm.h"
|
||||
#include "definitions.h"
|
||||
|
||||
WiFiServer server(35000);
|
||||
IPAddress localIP = IPAddress(192, 168, 0, 10);
|
||||
IPAddress gateway = IPAddress(192, 168, 0, 10);
|
||||
IPAddress subnet = IPAddress(255,255,255,0);
|
||||
|
||||
OBDWiFiComm::OBDWiFiComm() {
|
||||
|
||||
}
|
||||
|
||||
OBDWiFiComm::~OBDWiFiComm() {
|
||||
}
|
||||
|
||||
void OBDWiFiComm::init(const String& deviceName) {
|
||||
Serial.println("Starting AP . . .");
|
||||
|
||||
WiFi.softAPConfig(localIP, gateway, subnet);
|
||||
WiFi.softAP(deviceName);
|
||||
|
||||
IPAddress myIP = WiFi.softAPIP();
|
||||
Serial.print("AP IP address: ");
|
||||
Serial.println(myIP);
|
||||
Serial.print("AP SSID: ");
|
||||
Serial.println(deviceName);
|
||||
server.begin();
|
||||
setToDefaults();
|
||||
}
|
||||
|
||||
void OBDWiFiComm::writeEnd() {
|
||||
|
||||
// 1 - write carriage return
|
||||
writeTo("\r");
|
||||
|
||||
// 2- (optional ) write linefeed
|
||||
if (lineFeedEnable) {
|
||||
writeTo("\n");
|
||||
}
|
||||
|
||||
// 3 - Write prompt
|
||||
writeTo(">");
|
||||
};
|
||||
|
||||
|
||||
void OBDWiFiComm::writeEndOK() {
|
||||
writeTo("OK");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDWiFiComm::writeEndERROR() {
|
||||
writeTo("ERROR");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDWiFiComm::writeEndNoData() {
|
||||
writeTo("NO DATA");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDWiFiComm::writeEndUnknown() {
|
||||
writeTo("?");
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setToDefaults() {
|
||||
setEcho(true);
|
||||
setStatus(READY);
|
||||
setWhiteSpaces(true);
|
||||
setHeaders(false);
|
||||
setLineFeeds(true);
|
||||
setMemory(false);
|
||||
}
|
||||
|
||||
void OBDWiFiComm::writeTo(char const *response) {
|
||||
client.print(response);
|
||||
}
|
||||
|
||||
|
||||
void OBDWiFiComm::writeTo(uint8_t cChar) {
|
||||
client.print(cChar);
|
||||
}
|
||||
|
||||
void OBDWiFiComm::writeEndPidTo(char const *response) {
|
||||
if (this->whiteSpacesEnabled) {
|
||||
uint8_t len = strlen(response);
|
||||
char spacedResponse[len + len / 2 + 1];
|
||||
addSpacesToResponse(response, spacedResponse);
|
||||
writeTo(spacedResponse);
|
||||
} else {
|
||||
writeTo(response);
|
||||
}
|
||||
writeEnd();
|
||||
}
|
||||
|
||||
void OBDWiFiComm::readData(String& rxData) {
|
||||
if (!client.connected()) {
|
||||
client = server.available();
|
||||
}
|
||||
|
||||
if(client)
|
||||
{
|
||||
rxData
|
||||
= client.readStringUntil(SERIAL_END_CHAR);
|
||||
if (isEchoEnable())
|
||||
{
|
||||
writeTo(rxData.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool OBDWiFiComm::isEchoEnable() {
|
||||
return this->echoEnable;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setEcho(bool echo) {
|
||||
this->echoEnable = echo;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setStatus(STATUS status) {
|
||||
this->status = status;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setLineFeeds(bool status) {
|
||||
this->lineFeedEnable = status;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setMemory(bool status) {
|
||||
this->memoryEnabled = status;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setWhiteSpaces(bool status) {
|
||||
this->whiteSpacesEnabled = status;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::setHeaders(bool status) {
|
||||
this->headersEnabled = status;
|
||||
}
|
||||
|
||||
void OBDWiFiComm::addSpacesToResponse(const char *response, char spacedRes[]) {
|
||||
uint8_t len = strlen(response);
|
||||
int j = 0;
|
||||
for (int i = 0; i < len;) {
|
||||
*(spacedRes + j++) = *(response + i++);
|
||||
*(spacedRes + j++) = *(response + i++);
|
||||
if (i < len) {
|
||||
*(spacedRes + j++) = 0x20;
|
||||
}
|
||||
}
|
||||
*(spacedRes + j) = '\0';
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#ifndef ELMulator_OBDWiFiComm_h
|
||||
#define ELMulator_OBDWiFiComm_h
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <WiFi.h>
|
||||
#include <WiFiServer.h>
|
||||
#include "definitions.h"
|
||||
|
||||
|
||||
class OBDWiFiComm
|
||||
{
|
||||
public:
|
||||
enum STATUS
|
||||
{
|
||||
IDLE = 0,
|
||||
READY = 1
|
||||
};
|
||||
|
||||
OBDWiFiComm();
|
||||
|
||||
~OBDWiFiComm();
|
||||
|
||||
void init(const String &deviceName);
|
||||
|
||||
void writeEndOK();
|
||||
|
||||
void writeEndERROR();
|
||||
|
||||
/**
|
||||
* Response for unsupported PID command or missing sensor, respond "NO DATA".
|
||||
*/
|
||||
void writeEndNoData();
|
||||
|
||||
/**
|
||||
* Response for invalid AT command, or invalid PID or other bad input, respond "?"
|
||||
*/
|
||||
void writeEndUnknown();
|
||||
|
||||
void setToDefaults();
|
||||
|
||||
void readData(String &rxData);
|
||||
|
||||
void writeTo(uint8_t cChar);
|
||||
|
||||
void writeTo(char const *string);
|
||||
|
||||
void setEcho(bool echo);
|
||||
|
||||
void writeEnd();
|
||||
|
||||
bool isEchoEnable();
|
||||
|
||||
void setLineFeeds(bool status);
|
||||
|
||||
void setMemory(bool status);
|
||||
|
||||
void setWhiteSpaces(bool status);
|
||||
|
||||
void setHeaders(bool status);
|
||||
|
||||
void setStatus(STATUS status);
|
||||
|
||||
void writeEndPidTo(char const *string);
|
||||
|
||||
private:
|
||||
STATUS status; // Operation status
|
||||
bool echoEnable; // echoEnable command after received
|
||||
bool lineFeedEnable;
|
||||
bool memoryEnabled;
|
||||
bool whiteSpacesEnabled;
|
||||
bool headersEnabled;
|
||||
|
||||
void addSpacesToResponse(const char *response, char string[]);
|
||||
|
||||
WiFiClient client;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,195 @@
|
||||
#include "PidProcessor.h"
|
||||
|
||||
#if USE_WIFI
|
||||
PidProcessor::PidProcessor(OBDWiFiComm *connection) {
|
||||
_connection = connection;
|
||||
resetPidMode01Array();
|
||||
};
|
||||
#else
|
||||
PidProcessor::PidProcessor(OBDSerialComm *connection) {
|
||||
_connection = connection;
|
||||
resetPidMode01Array();
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
bool PidProcessor::process(String& command) {
|
||||
bool processed = false;
|
||||
|
||||
if (command.length() > 4)
|
||||
{
|
||||
command = command.substring(0, 4); // remove num_responses value if present; lib only handles single responses
|
||||
}
|
||||
|
||||
if (!isMode01(command) & !isMode22(command))
|
||||
{
|
||||
_connection->writeEndNoData();
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t hexCommand = strtoul(command.c_str(), NULL, HEX);
|
||||
uint8_t pid = getPidCodeFromHex(hexCommand);
|
||||
if (isSupportedPidRequest(pid)) { //reqeust to return a list of valid PIDs we can respond to
|
||||
processed = true;
|
||||
uint32_t supportedPids = getSupportedPids(pid);
|
||||
writePidResponse(command, 4, supportedPids);
|
||||
}
|
||||
return processed;
|
||||
}
|
||||
|
||||
void PidProcessor::writePidResponse(const String& requestPid, uint8_t numberOfBytes, uint32_t value) {
|
||||
uint8_t nHexChars = PID_N_BYTES * N_CHARS_IN_BYTE + numberOfBytes * N_CHARS_IN_BYTE ;
|
||||
char responseArray[nHexChars + 1]; // one more for termination char
|
||||
getFormattedResponse(responseArray, nHexChars, requestPid, value);
|
||||
_connection->writeEndPidTo(responseArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a supported pid, so it can answer to pid support request, ex 0100, 0120, ...
|
||||
*/
|
||||
bool PidProcessor::registerMode01Pid(uint32_t pid) {
|
||||
// pid must be off type 01
|
||||
if (pid > 0x00 && pid < 0x0200) {
|
||||
// remove PidMode, only use pid code
|
||||
pid = getPidCodeFromHex(pid);
|
||||
setPidBit(pid);
|
||||
|
||||
char buffer[4];
|
||||
sprintf(buffer, "%02X", pid);
|
||||
DEBUG("Registered PID: " + String(buffer ));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PidProcessor::isMode01(const String& command)
|
||||
{
|
||||
return command.startsWith("01") ? true : false;
|
||||
}
|
||||
|
||||
bool PidProcessor::isMode01MIL(const String& command)
|
||||
{
|
||||
return command.startsWith("0101") ? true : false;
|
||||
}
|
||||
|
||||
bool PidProcessor::isMode03(const String& command)
|
||||
{
|
||||
return command.startsWith("03") ? true : false;
|
||||
}
|
||||
|
||||
bool PidProcessor::isMode22(const String& command)
|
||||
{
|
||||
return command.startsWith("22") ? true : false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* return true if:
|
||||
* - 1000
|
||||
* - 1020
|
||||
* - 1040
|
||||
* - 1060
|
||||
* ....
|
||||
*/
|
||||
bool PidProcessor::isSupportedPidRequest(uint8_t pid) {
|
||||
return pid == getPidIntervalId(pid);
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the interval RANGEID for the given pid (ex: 00, 20, 40, ...)
|
||||
*/
|
||||
uint8_t PidProcessor::getPidIntervalId(uint8_t pidcode) {
|
||||
return getPidIntervalIndex(pidcode) * PID_INTERVAL_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns the interval INDEX for the given pid (0,1,2,3,4,...)
|
||||
*/
|
||||
uint8_t PidProcessor::getPidIntervalIndex(uint8_t pidcode) {
|
||||
return pidcode / PID_INTERVAL_OFFSET;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a mode pid ex 010C ,
|
||||
* returns only the pid ex 0C
|
||||
*/
|
||||
uint8_t PidProcessor::getPidCodeFromHex(uint16_t hexCommand) {
|
||||
|
||||
if (hexCommand >= 0x0100) {
|
||||
hexCommand -= 0x100;
|
||||
}
|
||||
return (uint8_t) hexCommand; // return only the lower 8 bits (trim off num_messages or other extra bytes if present)
|
||||
}
|
||||
|
||||
/**
|
||||
* Receives a complete PID request,
|
||||
* returns only the pid ex 0C
|
||||
*/
|
||||
uint8_t PidProcessor::getPidCodeFromRequest(const String& request) {
|
||||
uint16_t hexCommand = strtoul(request.c_str(), NULL, HEX);
|
||||
return getPidCodeFromHex(hexCommand);
|
||||
}
|
||||
|
||||
|
||||
void PidProcessor::setPidBit(uint8_t pid) {
|
||||
uint8_t arrayIndex = getPidIntervalIndex(pid);
|
||||
if(isSupportedPidRequest(pid)) {
|
||||
arrayIndex -= 1;
|
||||
}
|
||||
|
||||
uint8_t bitPosition = getPidBitPosition(pid);
|
||||
bitWrite(pidMode01Supported[arrayIndex], bitPosition, 1);
|
||||
|
||||
// mark available intervals
|
||||
for (int i = 0; i < arrayIndex; i++) {
|
||||
bitWrite(pidMode01Supported[i], 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t PidProcessor::getPidBitPosition(uint8_t pid) {
|
||||
uint8_t intervalId = getPidIntervalId(pid) ;
|
||||
if(isSupportedPidRequest(pid)) {
|
||||
intervalId -= PID_INTERVAL_OFFSET;
|
||||
}
|
||||
|
||||
uint16_t pos = pid - intervalId;
|
||||
pos = PID_INTERVAL_OFFSET - pos;
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
uint32_t PidProcessor:: getSupportedPids(uint8_t pid) {
|
||||
uint8_t index = getPidIntervalIndex(pid);
|
||||
return pidMode01Supported[index];
|
||||
}
|
||||
|
||||
void PidProcessor::getFormattedResponse(char *response, uint8_t totalNumberOfChars, const String& pid, uint32_t value) {
|
||||
uint8_t nValueChars = totalNumberOfChars - PID_N_BYTES * N_CHARS_IN_BYTE;
|
||||
char cValue[3] = {0};
|
||||
itoa(nValueChars, cValue, DEC);
|
||||
String mask = "%s%0";
|
||||
mask.concat(cValue);
|
||||
mask.concat("lX\0");
|
||||
String pidResponse = convertToPidResponse(pid);
|
||||
sprintf(response, mask.c_str(), pidResponse.c_str(), value);
|
||||
|
||||
DEBUG("RX PID: " + pid + " - TX: " + String(response));
|
||||
}
|
||||
|
||||
String PidProcessor::convertToPidResponse(String pid) {
|
||||
String x = "4";
|
||||
x.concat(pid.substring(1, pid.length()));
|
||||
return x;
|
||||
}
|
||||
|
||||
void PidProcessor::resetPidMode01Array() {
|
||||
for(uint8_t i = 0; i < N_MODE01_INTERVALS; i++ ) {
|
||||
pidMode01Supported[i] = 0x0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
#ifndef ELMulator_PIDPROCESSOR_H
|
||||
#define ELMulator_PIDPROCESSOR_H
|
||||
|
||||
#include "definitions.h"
|
||||
#include <Arduino.h>
|
||||
#include <WString.h>
|
||||
#include <Print.h>
|
||||
#include "OBDWiFiComm.h"
|
||||
#include "OBDSerialComm.h"
|
||||
|
||||
class PidProcessor
|
||||
{
|
||||
|
||||
public:
|
||||
PidProcessor(OBDWiFiComm *connection);
|
||||
PidProcessor(OBDSerialComm *connection);
|
||||
bool process(String &string);
|
||||
|
||||
bool registerMode01Pid(uint32_t pid);
|
||||
|
||||
bool registerMode01MILResponse(const String &response);
|
||||
|
||||
bool registerMode03Response(const String &response);
|
||||
|
||||
void writePidResponse(const String &requestPid, uint8_t numberOfBytes, uint32_t value);
|
||||
|
||||
uint8_t getPidCodeFromHex(uint16_t hexCommand);
|
||||
uint8_t getPidCodeFromRequest(const String &command);
|
||||
|
||||
bool isMode01(const String &command);
|
||||
bool isMode01MIL(const String &command);
|
||||
bool isMode03(const String &command);
|
||||
bool isMode22(const String &command);
|
||||
|
||||
private:
|
||||
#if USE_WIFI
|
||||
OBDWiFiComm *_connection;
|
||||
#else
|
||||
OBDSerialComm *_connection;
|
||||
#endif
|
||||
uint32_t pidMode01Supported[N_MODE01_INTERVALS];
|
||||
|
||||
bool isSupportedPidRequest(uint8_t pid);
|
||||
|
||||
uint32_t getSupportedPids(uint8_t pidcode);
|
||||
|
||||
uint8_t getPidIntervalId(uint8_t pidcode);
|
||||
|
||||
uint8_t getPidIntervalIndex(uint8_t pidcode);
|
||||
|
||||
void setPidBit(uint8_t pid);
|
||||
|
||||
uint8_t getPidBitPosition(uint8_t pidcode);
|
||||
|
||||
String convertToPidResponse(String pid);
|
||||
|
||||
void getFormattedResponse(char *response, uint8_t totalNumberOfChars, const String &pid, uint32_t value);
|
||||
|
||||
void resetPidMode01Array();
|
||||
};
|
||||
|
||||
#endif // ELMulator_PIDPROCESSOR_H
|
||||
@@ -0,0 +1,294 @@
|
||||
#ifndef ELMulator_DEFINITIONS_H
|
||||
#define ELMulator_DEFINITIONS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// true == We are running on hardware that has builtin Bluetooth
|
||||
// false == We are using hardware that has BT module attached via GPIO pins
|
||||
#define BLUETOOTH_BUILTIN true
|
||||
|
||||
#define USE_WIFI false
|
||||
|
||||
#define DO_DEBUG true
|
||||
#define DEBUG(x) do {if (DO_DEBUG) { Serial.println(x); } } while (0)
|
||||
|
||||
#define xtoc(x) ((x < 10) ? ('0' + x) : ('A' - 10 + x))
|
||||
#define getNumOfHexChars(nBytes) (nBytes * 2)
|
||||
|
||||
#define PID_N_BYTES 2
|
||||
#define N_CHARS_IN_BYTE 2
|
||||
|
||||
// Device ID
|
||||
#define ID "ELM327 / ELMulator V1.3.0"
|
||||
#define DESC "ELMulator OBD2 Arduino library, based on ELM327 protocol"
|
||||
#define PROTOCOL "6" // canbus 500k 11 bit protocol id for elm.
|
||||
|
||||
// Char representing end of serial string
|
||||
#define SERIAL_END_CHAR 0x0D
|
||||
#define SERIAL_READ_TIMEOUT 20000L
|
||||
|
||||
#define WIFI_END_CHAR 0x0A
|
||||
|
||||
const uint8_t maxPid = 0xFF;
|
||||
const uint8_t N_MODE01_INTERVALS = 7;
|
||||
const uint8_t PID_INTERVAL_OFFSET = 0x20;
|
||||
const uint8_t MAX_REQUEST_SIZE = 40;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------//
|
||||
// Protocol IDs
|
||||
//-------------------------------------------------------------------------------------//
|
||||
const char AUTOMATIC = '0';
|
||||
const char SAE_J1850_PWM_41_KBAUD = '1';
|
||||
const char SAE_J1850_PWM_10_KBAUD = '2';
|
||||
const char ISO_9141_5_BAUD_INIT = '3';
|
||||
const char ISO_14230_5_BAUD_INIT = '4';
|
||||
const char ISO_14230_FAST_INIT = '5';
|
||||
const char ISO_15765_11_BIT_500_KBAUD = '6';
|
||||
const char ISO_15765_29_BIT_500_KBAUD = '7';
|
||||
const char ISO_15765_11_BIT_250_KBAUD = '8';
|
||||
const char ISO_15765_29_BIT_250_KBAUD = '9';
|
||||
const char SAE_J1939_29_BIT_250_KBAUD = 'A';
|
||||
const char USER_1_CAN = 'B';
|
||||
const char USER_2_CAN = 'C';
|
||||
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------//
|
||||
// PIDs (https://en.wikipedia.org/wiki/OBD-II_PIDs)
|
||||
//-------------------------------------------------------------------------------------//
|
||||
const uint8_t SUPPORTED_PIDS_1_20 = 0; // 0x00 - bit encoded
|
||||
const uint8_t MONITOR_STATUS_SINCE_DTC_CLEARED = 1; // 0x01 - bit encoded
|
||||
const uint8_t FREEZE_DTC = 2; // 0x02 -
|
||||
const uint8_t FUEL_SYSTEM_STATUS = 3; // 0x03 - bit encoded
|
||||
const uint8_t ENGINE_LOAD = 4; // 0x04 - %
|
||||
const uint8_t ENGINE_COOLANT_TEMP = 5; // 0x05 - °C
|
||||
const uint8_t SHORT_TERM_FUEL_TRIM_BANK_1 = 6; // 0x06 - %
|
||||
const uint8_t LONG_TERM_FUEL_TRIM_BANK_1 = 7; // 0x07 - %
|
||||
const uint8_t SHORT_TERM_FUEL_TRIM_BANK_2 = 8; // 0x08 - %
|
||||
const uint8_t LONG_TERM_FUEL_TRIM_BANK_2 = 9; // 0x09 - %
|
||||
const uint8_t FUEL_PRESSURE = 10; // 0x0A - kPa
|
||||
const uint8_t INTAKE_MANIFOLD_ABS_PRESSURE = 11; // 0x0B - kPa
|
||||
const uint8_t ENGINE_RPM = 12; // 0x0C - rpm
|
||||
const uint8_t VEHICLE_SPEED = 13; // 0x0D - km/h
|
||||
const uint8_t TIMING_ADVANCE = 14; // 0x0E - ° before TDC
|
||||
const uint8_t INTAKE_AIR_TEMP = 15; // 0x0F - °C
|
||||
const uint8_t MAF_FLOW_RATE = 16; // 0x10 - g/s
|
||||
const uint8_t THROTTLE_POSITION = 17; // 0x11 - %
|
||||
const uint8_t COMMANDED_SECONDARY_AIR_STATUS = 18; // 0x12 - bit encoded
|
||||
const uint8_t OXYGEN_SENSORS_PRESENT_2_BANKS = 19; // 0x13 - bit encoded
|
||||
const uint8_t OXYGEN_SENSOR_1_A = 20; // 0x14 - V %
|
||||
const uint8_t OXYGEN_SENSOR_2_A = 21; // 0x15 - V %
|
||||
const uint8_t OXYGEN_SENSOR_3_A = 22; // 0x16 - V %
|
||||
const uint8_t OXYGEN_SENSOR_4_A = 23; // 0x17 - V %
|
||||
const uint8_t OXYGEN_SENSOR_5_A = 24; // 0x18 - V %
|
||||
const uint8_t OXYGEN_SENSOR_6_A = 25; // 0x19 - V %
|
||||
const uint8_t OXYGEN_SENSOR_7_A = 26; // 0x1A - V %
|
||||
const uint8_t OXYGEN_SENSOR_8_A = 27; // 0x1B - V %
|
||||
const uint8_t OBD_STANDARDS = 28; // 0x1C - bit encoded
|
||||
const uint8_t OXYGEN_SENSORS_PRESENT_4_BANKS = 29; // 0x1D - bit encoded
|
||||
const uint8_t AUX_INPUT_STATUS = 30; // 0x1E - bit encoded
|
||||
const uint8_t RUN_TIME_SINCE_ENGINE_START = 31; // 0x1F - sec
|
||||
|
||||
const uint8_t SUPPORTED_PIDS_21_40 = 32; // 0x20 - bit encoded
|
||||
const uint8_t DISTANCE_TRAVELED_WITH_MIL_ON = 33; // 0x21 - km
|
||||
const uint8_t FUEL_RAIL_PRESSURE = 34; // 0x22 - kPa
|
||||
const uint8_t FUEL_RAIL_GUAGE_PRESSURE = 35; // 0x23 - kPa
|
||||
const uint8_t OXYGEN_SENSOR_1_B = 36; // 0x24 - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_2_B = 37; // 0x25 - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_3_B = 38; // 0x26 - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_4_B = 39; // 0x27 - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_5_B = 40; // 0x28 - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_6_B = 41; // 0x29 - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_7_B = 42; // 0x2A - ratio V
|
||||
const uint8_t OXYGEN_SENSOR_8_B = 43; // 0x2B - ratio V
|
||||
const uint8_t COMMANDED_EGR = 44; // 0x2C - %
|
||||
const uint8_t EGR_ERROR = 45; // 0x2D - %
|
||||
const uint8_t COMMANDED_EVAPORATIVE_PURGE = 46; // 0x2E - %
|
||||
const uint8_t FUEL_TANK_LEVEL_INPUT = 47; // 0x2F - %
|
||||
const uint8_t WARM_UPS_SINCE_CODES_CLEARED = 48; // 0x30 - count
|
||||
const uint8_t DIST_TRAV_SINCE_CODES_CLEARED = 49; // 0x31 - km
|
||||
const uint8_t EVAP_SYSTEM_VAPOR_PRESSURE = 50; // 0x32 - Pa
|
||||
const uint8_t ABS_BAROMETRIC_PRESSURE = 51; // 0x33 - kPa
|
||||
const uint8_t OXYGEN_SENSOR_1_C = 52; // 0x34 - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_2_C = 53; // 0x35 - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_3_C = 54; // 0x36 - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_4_C = 55; // 0x37 - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_5_C = 56; // 0x38 - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_6_C = 57; // 0x39 - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_7_C = 58; // 0x3A - ratio mA
|
||||
const uint8_t OXYGEN_SENSOR_8_C = 59; // 0x3B - ratio mA
|
||||
const uint8_t CATALYST_TEMP_BANK_1_SENSOR_1 = 60; // 0x3C - °C
|
||||
const uint8_t CATALYST_TEMP_BANK_2_SENSOR_1 = 61; // 0x3D - °C
|
||||
const uint8_t CATALYST_TEMP_BANK_1_SENSOR_2 = 62; // 0x3E - °C
|
||||
const uint8_t CATALYST_TEMP_BANK_2_SENSOR_2 = 63; // 0x3F - °C
|
||||
|
||||
const uint8_t SUPPORTED_PIDS_41_60 = 64; // 0x40 - bit encoded
|
||||
const uint8_t MONITOR_STATUS_THIS_DRIVE_CYCLE = 65; // 0x41 - bit encoded
|
||||
const uint8_t CONTROL_MODULE_VOLTAGE = 66; // 0x42 - V
|
||||
const uint8_t ABS_LOAD_VALUE = 67; // 0x43 - %
|
||||
const uint8_t FUEL_AIR_COMMANDED_EQUIV_RATIO = 68; // 0x44 - ratio
|
||||
const uint8_t RELATIVE_THROTTLE_POSITION = 69; // 0x45 - %
|
||||
const uint8_t AMBIENT_AIR_TEMP = 70; // 0x46 - °C
|
||||
const uint8_t ABS_THROTTLE_POSITION_B = 71; // 0x47 - %
|
||||
const uint8_t ABS_THROTTLE_POSITION_C = 72; // 0x48 - %
|
||||
const uint8_t ABS_THROTTLE_POSITION_D = 73; // 0x49 - %
|
||||
const uint8_t ABS_THROTTLE_POSITION_E = 74; // 0x4A - %
|
||||
const uint8_t ABS_THROTTLE_POSITION_F = 75; // 0x4B - %
|
||||
const uint8_t COMMANDED_THROTTLE_ACTUATOR = 76; // 0x4C - %
|
||||
const uint8_t TIME_RUN_WITH_MIL_ON = 77; // 0x4D - min
|
||||
const uint8_t TIME_SINCE_CODES_CLEARED = 78; // 0x4E - min
|
||||
const uint8_t MAX_VALUES_EQUIV_V_I_PRESSURE = 79; // 0x4F - ratio V mA kPa
|
||||
const uint8_t MAX_MAF_RATE = 80; // 0x50 - g/s
|
||||
const uint8_t FUEL_TYPE = 81; // 0x51 - ref table
|
||||
const uint8_t ETHANOL_FUEL_PERCENT = 82; // 0x52 - %
|
||||
const uint8_t ABS_EVAP_SYS_VAPOR_PRESSURE = 83; // 0x53 - kPa
|
||||
const uint8_t EVAP_SYS_VAPOR_PRESSURE = 84; // 0x54 - Pa
|
||||
const uint8_t SHORT_TERM_SEC_OXY_SENS_TRIM_1_3 = 85; // 0x55 - %
|
||||
const uint8_t LONG_TERM_SEC_OXY_SENS_TRIM_1_3 = 86; // 0x56 - %
|
||||
const uint8_t SHORT_TERM_SEC_OXY_SENS_TRIM_2_4 = 87; // 0x57 - %
|
||||
const uint8_t LONG_TERM_SEC_OXY_SENS_TRIM_2_4 = 88; // 0x58 - %
|
||||
const uint8_t FUEL_RAIL_ABS_PRESSURE = 89; // 0x59 - kPa
|
||||
const uint8_t RELATIVE_ACCELERATOR_PEDAL_POS = 90; // 0x5A - %
|
||||
const uint8_t HYBRID_BATTERY_REMAINING_LIFE = 91; // 0x5B - %
|
||||
const uint8_t ENGINE_OIL_TEMP = 92; // 0x5C - °C
|
||||
const uint8_t FUEL_INJECTION_TIMING = 93; // 0x5D - °
|
||||
const uint8_t ENGINE_FUEL_RATE = 94; // 0x5E - L/h
|
||||
const uint8_t EMISSION_REQUIREMENTS = 95; // 0x5F - bit encoded
|
||||
|
||||
const uint8_t SUPPORTED_PIDS_61_80 = 96; // 0x60 - bit encoded
|
||||
const uint8_t DEMANDED_ENGINE_PERCENT_TORQUE = 97; // 0x61 - %
|
||||
const uint8_t ACTUAL_ENGINE_TORQUE = 98; // 0x62 - %
|
||||
const uint8_t ENGINE_REFERENCE_TORQUE = 99; // 0x63 - Nm
|
||||
const uint8_t ENGINE_PERCENT_TORQUE_DATA = 100; // 0x64 - %
|
||||
const uint8_t AUX_INPUT_OUTPUT_SUPPORTED = 101; // 0x65 - bit encoded
|
||||
|
||||
const uint8_t ODOMETER = 166; // 0xA6 - km * 10
|
||||
|
||||
const uint8_t SERVICE_01 = 1;
|
||||
const uint8_t SERVICE_02 = 2;
|
||||
const uint8_t SERVICE_03 = 3;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------//
|
||||
// AT commands (https://www.sparkfun.com/datasheets/Widgets/ELM327_AT_Commands.pdf)
|
||||
//-------------------------------------------------------------------------------------//
|
||||
const char * const DISP_DEVICE_DESCRIPT = "AT @1"; // General
|
||||
const char * const DISP_DEVICE_ID = "AT @2"; // General
|
||||
const char * const STORE_DEVICE_ID = "AT @3 %s"; // General
|
||||
const char * const REPEAT_LAST_COMMAND = "AT \r"; // General
|
||||
const char * const ALLOW_LONG_MESSAGES = "AT AL"; // General
|
||||
const char * const AUTOMATIC_RECEIVE = "AT AR"; // OBD
|
||||
const char * const ADAPTIVE_TIMING_OFF = "AT AT0"; // OBD
|
||||
const char * const ADAPTIVE_TIMING_AUTO_1 = "AT AT1"; // OBD
|
||||
const char * const ADAPTIVE_TIMING_AUTO_2 = "AT AT2"; // OBD
|
||||
const char * const DUMP_BUFFER = "AT BD"; // OBD
|
||||
const char * const BYPASS_INIT_SEQUENCE = "AT BI"; // OBD
|
||||
const char * const TRY_BAUD_DIVISOR = "AT BRD %02d"; // General
|
||||
const char * const SET_HANDSHAKE_TIMEOUT = "AT BRT %02d"; // General
|
||||
const char * const CAN_AUTO_FORMAT_OFF = "AT CAF0"; // CAN
|
||||
const char * const CAN_AUTO_FORMAT_ON = "AT CAF1"; // CAN
|
||||
const char * const CAN_EXTENDED_ADDRESS_OFF = "AT CEA"; // CAN
|
||||
const char * const USE_CAN_EXTENDED_ADDRESS = "AT CEA %02d"; // CAN
|
||||
const char * const SET_ID_FILTER = "AT CF %s"; // CAN
|
||||
const char * const CAN_FLOW_CONTROL_OFF = "AT CFC0"; // CAN
|
||||
const char * const CAN_FLOW_CONTROL_ON = "AT CFC1"; // CAN
|
||||
const char * const SET_ID_MASK = "AT CM %s"; // CAN
|
||||
const char * const SET_CAN_PRIORITY = "AT CP %02d"; // CAN
|
||||
const char * const SHOW_CAN_STATUS = "AT CS"; // CAN
|
||||
const char * const CAN_SILENT_MODE_OFF = "AT CSM0"; // CAN
|
||||
const char * const CAN_SILENT_MODE_ON = "AT CSM1"; // CAN
|
||||
const char * const CALIBRATE_VOLTAGE_CUSTOM = "AT CV %04d"; // Volts
|
||||
const char * const RESTORE_CV_TO_FACTORY = "AT CV 0000"; // Volts
|
||||
const char * const SET_ALL_TO_DEFAULTS = "AT D"; // General
|
||||
const char * const DISP_DLC_OFF = "AT D0"; // CAN
|
||||
const char * const DISP_DLC_ON = "AT D1"; // CAN
|
||||
const char * const MONITOR_FOR_DM1_MESSAGES = "AT DM1"; // J1939
|
||||
const char * const DISP_CURRENT_PROTOCOL = "AT DP"; // OBD
|
||||
const char * const DISP_CURRENT_PROTOCOL_NUM = "AT DPN"; // OBD
|
||||
const char * const ECHO_OFF = "AT E0"; // General
|
||||
const char * const ECHO_ON = "AT E1"; // General
|
||||
const char * const FLOW_CONTROL_SET_DATA_TO = "AT FC SD %s"; // CAN
|
||||
const char * const FLOW_CONTROL_SET_HEAD_TO = "AT FC SH %s"; // CAN
|
||||
const char * const FLOW_CONTROL_SET_MODE_TO = "AT FC SM %c"; // CAN
|
||||
const char * const FORGE_EVENTS = "AT FE"; // General
|
||||
const char * const PERFORM_FAST_INIT = "AT FI"; // ISO
|
||||
const char * const HEADERS_OFF = "AT H0"; // OBD
|
||||
const char * const HEADERS_ON = "AT H1"; // OBD
|
||||
const char * const DISP_ID = "AT I"; // General
|
||||
const char * const SET_ISO_BAUD_10400 = "AT IB 10"; // ISO
|
||||
const char * const SET_ISO_BAUD_4800 = "AT IB 48"; // ISO
|
||||
const char * const SET_ISO_BAUD_9600 = "AT IB 96"; // ISO
|
||||
const char * const IFR_VAL_FROM_HEADER = "AT IFR H"; // J1850
|
||||
const char * const IFR_VAL_FROM_SOURCE = "AT IFR S"; // J1850
|
||||
const char * const IFRS_OFF = "AT IFR0"; // J1850
|
||||
const char * const IFRS_AUTO = "AT IFR1"; // J1850
|
||||
const char * const IFRS_ON = "AT IFR2"; // J1850
|
||||
const char * const IREAD_IGNMON_INPUT_LEVEL = "AT IGN"; // Other
|
||||
const char * const SET_ISO_SLOW_INIT_ADDRESS = "AT IIA %02d"; // ISO
|
||||
const char * const USE_J1939_ELM_DATA_FORMAT = "AT JE"; // J1850
|
||||
const char * const J1939_HEAD_FORMAT_OFF = "AT JHF0"; // J1850
|
||||
const char * const J1939_HEAD_FORMAT_ON = "AT JHF1"; // J1850
|
||||
const char * const USE_J1939_SAE_DATA_FORMAT = "AT JS"; // J1850
|
||||
const char * const SET_J1939_TIMER_X_TO_1X = "AT JTM1"; // J1850
|
||||
const char * const SET_J1939_TIMER_X_TO_5X = "AT JTM5"; // J1850
|
||||
const char * const DISP_KEY_WORDS = "AT KW"; // ISO
|
||||
const char * const KEY_WORD_CHECKING_OFF = "AT KW0"; // ISO
|
||||
const char * const KEY_WORD_CHECKING_ON = "AT KW1"; // ISO
|
||||
const char * const LINEFEEDS_OFF = "AT L0"; // General
|
||||
const char * const LINEFEEDS_ON = "AT L1"; // General
|
||||
const char * const LOW_POWER_MODE = "AT LP"; // General
|
||||
const char * const MEMORY_OFF = "AT M0"; // General
|
||||
const char * const MEMORY_ON = "AT M1"; // General
|
||||
const char * const MONITOR_ALL = "AT MA"; // OBD
|
||||
const char * const MONITOR_FOR_PGN = "AT MP %s"; // J1939
|
||||
const char * const MONITOR_FOR_RECEIVER = "AT MR %02d"; // OBD
|
||||
const char * const MONITOR_FOR_TRANSMITTER = "AT MT %02d"; // OBD
|
||||
const char * const NORMAL_LENGTH_MESSAGES = "AT NL"; // OBD
|
||||
const char * const SET_PROTO_OPTIONS_AND_BAUD = "AT PB %s"; // OBD
|
||||
const char * const PROTOCOL_CLOSE = "AT PC"; // OBD
|
||||
const char * const ALL_PROG_PARAMS_OFF = "AT PP FF OFF";// PPs
|
||||
const char * const ALL_PROG_PARAMS_ON = "AT PP FF ON"; // PPs
|
||||
const char * const SET_PROG_PARAM_OFF = "AT PP %s OFF";// PPs
|
||||
const char * const SET_PROG_PARAM_ON = "AT PP %s ON"; // PPs
|
||||
const char * const SET_PROG_PARAM_VAL = "AT PP %s SV %s"; // PPs
|
||||
const char * const DISP_PP_SUMMARY = "AT PPS"; // PPs
|
||||
const char * const RESPONSES_OFF = "AT R0"; // OBD
|
||||
const char * const RESPONSES_ON = "AT R1"; // OBD
|
||||
const char * const SET_RECEIVE_ADDRESS_TO = "AT RA %02d"; // OBD
|
||||
const char * const READ_STORED_DATA = "AT RD"; // General
|
||||
const char * const SEND_RTR_MESSAGE = "AT RTR"; // CAN
|
||||
const char * const READ_VOLTAGE = "AT RV"; // Volts
|
||||
const char * const PRINTING_SPACES_OFF = "AT S0"; // OBD
|
||||
const char * const PRINTING_SPACES_ON = "AT S1"; // OBD
|
||||
const char * const STORE_DATA_BYTE = "AT SD "; // General
|
||||
const char * const SET_HEADER = "AT SH %s"; // OBD
|
||||
const char * const PERFORM_SLOW_INIT = "AT SI"; // ISO
|
||||
const char * const SET_PROTOCOL_TO_AUTO_H_SAVE = "AT SP A%c"; // OBD
|
||||
const char * const SET_PROTOCOL_TO_H_SAVE = "AT SP %c"; // OBD
|
||||
const char * const SET_PROTOCOL_TO_AUTO_SAVE = "AT SP 00"; // OBD
|
||||
const char * const SET_REC_ADDRESS = "AT SR %02d"; // OBD
|
||||
const char * const SET_STANDARD_SEARCH_ORDER = "AT SS"; // OBD
|
||||
const char * const SET_TIMEOUT_TO_H_X_4MS = "AT ST %02d"; // OBD
|
||||
const char * const SET_WAKEUP_TO_H_X_20MS = "AT SW %02d"; // ISO
|
||||
const char * const SET_TESTER_ADDRESS_TO = "AT TA %02d"; // OBD
|
||||
const char * const TRY_PROT_H_AUTO_SEARCH = "AT TP A%c"; // OBD
|
||||
const char * const TRY_PROT_H = "AT TP %c"; // OBD
|
||||
const char * const VARIABLE_DLC_OFF = "AT V0"; // CAN
|
||||
const char * const VARIABLE_DLC_ON = "AT V1"; // CAN
|
||||
const char * const SET_WAKEUP_MESSAGE = "AT WM"; // ISO
|
||||
const char * const WARM_START = "AT WS"; // General
|
||||
const char * const RESET_ALL = "AT Z"; // General
|
||||
|
||||
|
||||
const uint8_t responseBytes[0xA9] =
|
||||
{
|
||||
4, 4, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2,
|
||||
4, 2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 2, 2, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2,
|
||||
4, 4, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 4, 4, 1, 1, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 2, 2, 1,
|
||||
4, 1, 1, 2, 5, 2, 5, 3, 3, 7, 5, 5, 5, 11, 9, 3, 10, 6, 5, 5, 5, 7, 7, 5, 9, 9, 7, 7, 9, 1, 1, 13,
|
||||
4, 41, 41, 9, 1, 10, 5, 5, 13, 41, 41, 7, 17, 1, 1, 7, 3, 5, 2, 3, 12, 9, 9, 6, 4, 17, 4, 2, 9
|
||||
};
|
||||
|
||||
#endif //ELMulator_DEFINITIONS_H
|
||||
Reference in new issue
Block a user