概要
elm327を調べてみた。
arduinoでエミュレータ書いてみた。
サンプルコード
bool headerInfo = false;
bool spaces = true;
bool lineFeed = true;
bool echo = false;
bool memory = false;
bool EcuConnected = false;
char elmVersion[11] = {
'E',
'L',
'M',
'3',
'2',
'7',
' ',
'v',
'1',
'.',
'5'
};
char cmds[6];
int counter = 0;
bool CheckAT() {
bool ok = false;
if (counter >= 2)
if (cmds[0] == 'A' && cmds[1] == 'T')
{
switch(cmds[2])
{
case 'A':
if (cmds[3] == 'T')
{
ok = true;
}
break;
case 'D':
if (cmds[3] == 'P' && cmds[4] == 'N')
{
Serial.print(5);
ok = false;
}
else if (cmds[3] == 'P')
{
Serial.print("ISO 14230-4 KWP");
ok = false;
}
else
{
headerInfo = false;
spaces = false;
lineFeed = false;
echo = false;
memory = false;
ok = true;
}
break;
case 'Z': //Reset
delay(500);
Serial.print(elmVersion);
break;
case 'H': //Header
headerInfo = cmds[3] == '1';
ok = true;
break;
case 'I': //Device Info
Serial.print("ELM327 v1.5");
ok = false;
break;
case 'S': //Space
if (cmds[3] == 'P')
{
ok = true;
}
else
{
spaces = cmds[3] == '1';
ok = true;
}
break;
case 'L': //lineFeed
lineFeed = cmds[3] == '1';
ok = true;
break;
case 'E': //Echo
echo = cmds[3] == '1';
ok = true;
break;
case 'M': //Memory
memory = cmds[3] == '1';
ok = true;
break;
case 'P': //ProtocolClose
if (cmds[3] == 'C')
{
ok = true;
}
break;
case 'W': //WarmStart
if (cmds[3] == 'S')
{
Serial.print(elmVersion);
ok = false;
}
break;
case ' ':
if (cmds[3] == 'A' && cmds[4] == 'T')
{
ok = true;
}
if (cmds[3] == 'H')
{
headerInfo = cmds[4] == '1';
ok = true;
}
break;
case '@':
switch(cmds[3])
{
case '1': //Device Description
Serial.print("test Reader");
ok = false;
break;
case '2': //Device Identifier
Serial.print("ELM327");
ok = false;
break;
case '3': //Set Device Identifiier (Nope :P )
ok = true;
break;
}
break;
default:
Serial.print("?");
ok = false;
break;
}
SendEcho();
ClearBuffer();
if (ok)
SendOK();
SendNewLine();
SendPrompt();
return true;
}
return false;
}
bool CheckService() {
if (cmds[0] == '0' && cmds[1] == '6' && cmds[2] == '0')
{
}
else
{
return false;
}
SendEcho();
uint8_t elmResponse[12];
int responseCounter = 0;
if (headerInfo)
{
elmResponse[responseCounter++] = 0x80;
elmResponse[responseCounter++] = 0xF1;
elmResponse[responseCounter++] = 0x11;
elmResponse[responseCounter++] = 0x06;
}
elmResponse[responseCounter++] = 0x41;
return true;
}
void SendNewLine() {
Serial.write(0x0D);
if (lineFeed)
Serial.write(0x0A);
}
void SendPrompt() {
Serial.write(0x3E);
}
void SendSpace() {
if (spaces)
Serial.write(0x20);
}
void SendOK() {
Serial.print("OK");
}
void SendEcho() {
if (echo)
{
for (int j = 0; j < counter; j++)
{
if (cmds[j] == 0x00)
break;
Serial.write(cmds[j]);
}
SendNewLine();
}
}
void ClearBuffer() {
counter = 0;
memset(cmds, 0, sizeof(cmds));
}
byte getVal(char c) {
if (c >= '0' && c <= '9')
return (byte)(c - '0');
else
return (byte)(c - 'A' + 10);
}
byte GetByteFromHexString(String hexValue) {
return getVal(hexValue[1]) + (getVal(hexValue[0]) << 4);
}
void PrintHex(uint8_t data) {
if (data < 0x10)
Serial.print("0");
String str = String(data, HEX);
str.toUpperCase();
Serial.print(str);
}
uint8_t calcChecksum(uint8_t * data, uint8_t len) {
uint8_t crc = 0;
for (uint8_t i = 0; i < len; i++)
{
crc = crc + data[i];
}
return crc;
}
bool CheckPID() {
if (counter >= 3)
if (cmds[0] == '0' && cmds[1] == '1')
{
uint8_t request;
String response;
String value = String(cmds[2]) + String(cmds[3]);
value.toUpperCase();
uint8_t pid = GetByteFromHexString(value);
switch(pid)
{
case 0x04: //Engine Load
request = 0x00;
response = "52";
break;
case 0x05: //Engine Coolant Temperature
request = 0x06;
response = "92";
break;
case 0x10: //MAF
request = 0x00;
response = "D9C8";
break;
case 0x11: //Throttle Position
request = 0x04;
response = "DE";
break;
case 0x0B: //Intake Air Pressure
request = 0x05;
response = "7B";
break;
case 0x0C: //Engine RPM
request = 0x09;
response = "0500";
break;
case 0x0D: //Speed
request = 0x0C;
response = "50";
break;
case 0x0F: //Intake Air Temperature
request = 0x07;
response = "3E";
break;
case 0x45: //Relative Throttle Position
request = 0x00;
response = "48";
break;
case 0x4F: //Maximum values
request = 0x00;
response = "00000000";
break;
case 0x50: //Maximum values Air flow rate
request = 0x00;
response = "00000000";
break;
default:
request = 0x00;
break;
}
if (response == "")
{
Serial.write("NO DATA");
}
else
{
//if (headerInfo)
// Serial.write("80 F1 11 03");
Serial.write("41");
SendSpace();
Serial.write(cmds[2]);
Serial.write(cmds[3]);
if (spaces)
{
for (int j = 0; j < response.length(); j += 2)
{
SendSpace();
Serial.write(response[j]);
Serial.write(response[j + 1]);
}
}
else
Serial.print(response);
//if (headerInfo)
// Serial.write("03");
}
SendNewLine();
SendPrompt();
ClearBuffer();
return true;
}
return false;
}
bool ReceivePIDs() {
if (counter >= 4)
{
if (cmds[0] == '0' && cmds[1] == '1' && cmds[3] == '0')
{
}
else
{
return false;
}
}
else
return false;
SendEcho();
uint8_t elmResponse[12];
int responseCounter = 0;
if (headerInfo)
{
elmResponse[responseCounter++] = 0x80;
elmResponse[responseCounter++] = 0xF1;
elmResponse[responseCounter++] = 0x11;
elmResponse[responseCounter++] = 0x06;
}
elmResponse[responseCounter++] = 0x41;
elmResponse[responseCounter++] = GetByteFromHexString(String(cmds[2]) + String(cmds[3]));
switch(cmds[2])
{
case '0':
elmResponse[responseCounter++] = 0x18;
elmResponse[responseCounter++] = 0x1B;
elmResponse[responseCounter++] = 0x80;
elmResponse[responseCounter++] = 0x01;
break;
case '2':
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x20;
elmResponse[responseCounter++] = 0x01;
break;
case '4':
elmResponse[responseCounter++] = 0x48;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x01;
break;
case '6':
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x02;
break;
case '8':
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
break;
case 'A':
if (cmds[3] == '0')
{
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
}
break;
case 'C':
if (cmds[3] == '0')
{
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
elmResponse[responseCounter++] = 0x00;
}
break;
default:
return false;
}
if (headerInfo)
elmResponse[responseCounter] = calcChecksum(elmResponse, responseCounter++);
for (int i = 0; i < responseCounter; i++)
{
PrintHex(elmResponse[i]);
if (i + 1 < responseCounter)
SendSpace();
}
SendNewLine();
SendPrompt();
ClearBuffer();
return true;
}
bool ReadInput() {
while (Serial.available())
{
char input = Serial.read();
if (input == ' ')
continue;
cmds[counter++] = input;
delay(3);
if (input == 0x0D)
break;
}
if (counter == 0)
return false;
if (counter == 1 && cmds[counter] == 0x0D)
{
ClearBuffer();
return true;
}
if (cmds[0] == 'A')
if (CheckAT())
return true;
if (!EcuConnected)
{
delay(50);
Serial.println("SEARCHING...");
EcuConnected = true;
}
if (cmds[0] == '0' && cmds[1] == '1' && cmds[3] == '0')
if (ReceivePIDs())
return true;
if (cmds[0] == '0' && cmds[1] == '1')
if (CheckPID())
return true;
if (counter >= 4)
if (cmds[0] == '0')
if (CheckService())
return true;
if (cmds[counter] == 0x0A)
{
ClearBuffer();
return true;
}
ClearBuffer();
return false;
}
void setup() {
Serial.begin(38400);
Serial.println("start!!!");
}
void loop() {
if (Serial.available())
{
ReadInput();
}
delay(10);
}
以上。