elm327の研究 その5

# 概要

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);
}



```

以上。