0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

elm327の研究 その22

Posted at

概要

elm327の研究やってみた。
練習問題やってみた。

練習問題

c#で、ELM327のエミュレータを書け。

参考にしたページ

写真

image.png

サンプルコード


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.Resources;

namespace ExpressOBD
{
	public class ELM327 {
		public bool IsOpen = true;
		public int BytesToRead = 2;
		public string res = "";
		public void Open() {
		}
		public void Close() {
		}
		public string Read() {
			if (BytesToRead > 1)
			{
				BytesToRead = 1;
				return res;
			}
			else
			{
				BytesToRead = 0;
				return ">";
			}
		}
		public void Write(string a) {
			//Console.WriteLine(a);
			string[] b = a.Split(new string[] {
				"\r"
			}, StringSplitOptions.None);
			res = "";
			int len = b[0].Length;
			if (len < 2)
			{
				return;
			}
			if (b[0].Substring(0, 2) == "AT")
			{
				switch (b[0])
				{
				case "ATWS":
				case "ATE0":
				case "ATL0":
				case "ATH1":
				case "ATSP0":
				break;
				case "AT@1":
					res += "OBDII to RS232 Interpreter";
				break;
				case "ATRV":
					res += "12.8V";
				break;
				case "ATZ":
				case "ATI":
					res += "ELM327 v1.4";
				break;
				case "ATDP":
					res += "AUTO, ISO 9141-2";
				break;
				default:
					res += " NO COMMAND\n";
				break;
				}
			}
			else
			{
				switch (b[0])
				{
				case "01 00":
					res += "41 00 FF FF FC FF";
				break;
				case "01 01":
					res += "41 01 84 07 61 00";
				break;
				case "01 20":
					res += "41 20 FF FF FC FF";
				break;
				case "01 40":
					res += "41 40 FF FF FC FF";
				break;
				case "01 60":
					res += "41 60 FF FF FC FF";
				break;
				case "01 80":
					res += "41 80 FF FF FC FF";
				break;
				case "01 A0":
					res += "41 A0 FF FF FC FF";
				break;
				case "01 C0":
					res += "41 C0 FF FF FC FF";
				break;
				case "04 ":
					res += "44";
				break;
				default:
					res += b[0] + " NO DATA\n";
				break;
				}
			}
			BytesToRead = 2;
			//Console.WriteLine(res);
			return;
		}
	}
	public partial class MainForm: Form {
		private ELM327 sp;
		private GroupBox gbConnection;
		private Button btnConnect;
		private Label descRate;
		private Label descPort;
		private ComboBox cbBaud;
		private ComboBox cbPort;
		private GroupBox gbOBDActions;
		private Button btnResetErrors;
		private Label descReset;
		private GroupBox gbStatus;
		private Label label1;
		private ListView lvLog;
		private ColumnHeader chLog;
		private ImageList ilListviewImages;
		private int numberOfPromptsSinceInit = 0;
		private bool ecuIsAvailable = false;
		private bool serialPortsAreAvailable = true;
		private bool connectingInProgress = false;
		StringBuilder serialBuffer = new StringBuilder();
		private IContainer components = null;
		public MainForm() {
			this.components = new Container();
			ListViewItem listViewItem2 = new ListViewItem("ExpressOBD Initializing..", 2);
			ResXResourceSet resources = new ResXResourceSet("MainForm.resx");
			this.gbConnection = new GroupBox();
			this.label1 = new Label();
			this.btnConnect = new Button();
			this.descRate = new Label();
			this.descPort = new Label();
			this.cbBaud = new ComboBox();
			this.cbPort = new ComboBox();
			this.gbOBDActions = new GroupBox();
			this.btnResetErrors = new Button();
			this.descReset = new Label();
			this.gbStatus = new GroupBox();
			this.lvLog = new ListView();
			this.chLog = ((ColumnHeader)(new ColumnHeader()));
			this.ilListviewImages = new ImageList(this.components);
			this.gbConnection.SuspendLayout();
			this.gbOBDActions.SuspendLayout();
			this.gbStatus.SuspendLayout();
			this.SuspendLayout();
			this.gbConnection.Controls.Add(this.label1);
			this.gbConnection.Controls.Add(this.btnConnect);
			this.gbConnection.Controls.Add(this.descRate);
			this.gbConnection.Controls.Add(this.descPort);
			this.gbConnection.Controls.Add(this.cbBaud);
			this.gbConnection.Controls.Add(this.cbPort);
			this.gbConnection.Font = new Font("Segoe UI Light", 15.75F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.gbConnection.Location = new Point(12, 12);
			this.gbConnection.Name = "gbConnection";
			this.gbConnection.Padding = new Padding(15);
			this.gbConnection.Size = new Size(300, 241);
			this.gbConnection.TabIndex = 0;
			this.gbConnection.TabStop = false;
			this.gbConnection.Text = "Connection";
			this.label1.AutoSize = true;
			this.label1.Font = new Font("Segoe UI", 9.75F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.label1.Location = new Point(15, 122);
			this.label1.Name = "label1";
			this.label1.Size = new Size(246, 51);
			this.label1.TabIndex = 5;
			this.label1.Text = "To identify the correct port,\r\nDisconnect device && note available ports\r\nReconne" + "ct device && select the new entry";
			this.btnConnect.Enabled = true;
			this.btnConnect.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.btnConnect.Location = new Point(18, 186);
			this.btnConnect.Name = "btnConnect";
			this.btnConnect.Size = new Size(264, 37);
			this.btnConnect.TabIndex = 4;
			this.btnConnect.Text = "Connect";
			this.btnConnect.UseVisualStyleBackColor = true;
			this.btnConnect.Click += new System.EventHandler(this.btnConnect_Click);
			this.descRate.AutoSize = true;
			this.descRate.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.descRate.Location = new Point(18, 83);
			this.descRate.Name = "descRate";
			this.descRate.Size = new Size(80, 21);
			this.descRate.TabIndex = 3;
			this.descRate.Text = "Baud Rate";
			this.descPort.AutoSize = true;
			this.descPort.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.descPort.Location = new Point(18, 48);
			this.descPort.Name = "descPort";
			this.descPort.Size = new Size(85, 21);
			this.descPort.TabIndex = 2;
			this.descPort.Text = "Port Name";
			this.cbBaud.DropDownStyle = ComboBoxStyle.DropDownList;
			this.cbBaud.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.cbBaud.FormattingEnabled = true;
			this.cbBaud.Items.AddRange(new object[] {
				"9600",
				"19200",
				"38400",
				"57600",
				"115200"
			});
			this.cbBaud.Location = new Point(129, 80);
			this.cbBaud.Name = "cbBaud";
			this.cbBaud.Size = new Size(153, 29);
			this.cbBaud.TabIndex = 1;
			this.cbPort.DropDownStyle = ComboBoxStyle.DropDownList;
			this.cbPort.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.cbPort.FormattingEnabled = true;
			this.cbPort.Location = new Point(129, 45);
			this.cbPort.Name = "cbPort";
			this.cbPort.Size = new Size(153, 29);
			this.cbPort.TabIndex = 0;
			this.gbOBDActions.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left)));
			this.gbOBDActions.Controls.Add(this.btnResetErrors);
			this.gbOBDActions.Controls.Add(this.descReset);
			this.gbOBDActions.Font = new Font("Segoe UI Light", 15.75F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.gbOBDActions.Location = new Point(12, 264);
			this.gbOBDActions.Name = "gbOBDActions";
			this.gbOBDActions.Padding = new Padding(15);
			this.gbOBDActions.Size = new Size(300, 250);
			this.gbOBDActions.TabIndex = 5;
			this.gbOBDActions.TabStop = false;
			this.gbOBDActions.Text = "OBD Actions";
			this.btnResetErrors.Enabled = false;
			this.btnResetErrors.Font = new Font("Segoe UI", 12F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.btnResetErrors.Location = new Point(18, 195);
			this.btnResetErrors.Name = "btnResetErrors";
			this.btnResetErrors.Size = new Size(264, 37);
			this.btnResetErrors.TabIndex = 4;
			this.btnResetErrors.Text = "Reset Errors";
			this.btnResetErrors.UseVisualStyleBackColor = true;
			this.btnResetErrors.Click += new System.EventHandler(this.btnResetErrors_Click);
			this.descReset.AutoSize = true;
			this.descReset.Font = new Font("Segoe UI", 9.75F);
			this.descReset.Location = new Point(18, 43);
			this.descReset.Name = "descReset";
			this.descReset.Size = new Size(259, 136);
			this.descReset.TabIndex = 2;
			this.descReset.Text = "Reset Errors with 04 Command\r\n\r\nAvailable after connecting\r\n\r\nClear MIL (\"Check E" + "ngine Light\")\r\nErase Diagnostic Trouble Codes\r\nErase Freeze Frame Data\r\nErase Ox" + "ygen Test Data, Mode 06, 07 Data";
			this.gbStatus.Anchor = ((AnchorStyles)((((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left) | AnchorStyles.Right)));
			this.gbStatus.Controls.Add(this.lvLog);
			this.gbStatus.Font = new Font("Segoe UI Light", 15.75F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.gbStatus.Location = new Point(318, 12);
			this.gbStatus.Name = "gbStatus";
			this.gbStatus.Padding = new Padding(15);
			this.gbStatus.Size = new Size(604, 502);
			this.gbStatus.TabIndex = 6;
			this.gbStatus.TabStop = false;
			this.gbStatus.Text = "Status";
			this.lvLog.Anchor = ((AnchorStyles) ((((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left) | AnchorStyles.Right)));
			this.lvLog.Columns.AddRange(new ColumnHeader[] {
				this.chLog
			});
			this.lvLog.Font = new Font("Segoe UI Semibold", 9.75F, FontStyle.Bold, GraphicsUnit.Point, ((byte)(0)));
			this.lvLog.HeaderStyle = ColumnHeaderStyle.Nonclickable;
			this.lvLog.Items.AddRange(new ListViewItem[] {
				listViewItem2
			});
			this.lvLog.Location = new Point(18, 46);
			this.lvLog.Name = "lvLog";
			this.lvLog.Size = new Size(570, 438);
			this.lvLog.SmallImageList = this.ilListviewImages;
			this.lvLog.TabIndex = 1;
			this.lvLog.UseCompatibleStateImageBehavior = false;
			this.lvLog.View = View.Details;
			this.chLog.Text = "Log Details";
			this.chLog.Width = 570;
			this.ilListviewImages.ImageStream = ((ImageListStreamer) (resources.GetObject("ilListviewImages.ImageStream")));
			this.ilListviewImages.TransparentColor = Color.Transparent;
			this.ilListviewImages.Images.SetKeyName(0, "accept.png");
			this.ilListviewImages.Images.SetKeyName(1, "error.png");
			this.ilListviewImages.Images.SetKeyName(2, "information.png");
			this.ilListviewImages.Images.SetKeyName(3, "delete.png");
			this.ilListviewImages.Images.SetKeyName(4, "application_xp_terminal.png");
			this.AutoScaleDimensions = new SizeF(6F, 13F);
			this.AutoScaleMode = AutoScaleMode.Font;
			this.ClientSize = new Size(934, 526);
			this.Controls.Add(this.gbStatus);
			this.Controls.Add(this.gbOBDActions);
			this.Controls.Add(this.gbConnection);
			this.Font = new Font("Segoe UI", 8.25F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(0)));
			this.Name = "MainForm";
			this.StartPosition = FormStartPosition.CenterScreen;
			this.Text = "ExpressOBD";
			this.FormClosing += new FormClosingEventHandler(this.MainForm_FormClosing);
			this.Load += new System.EventHandler(this.MainForm_Load);
			this.gbConnection.ResumeLayout(false);
			this.gbConnection.PerformLayout();
			this.gbOBDActions.ResumeLayout(false);
			this.gbOBDActions.PerformLayout();
			this.gbStatus.ResumeLayout(false);
			this.ResumeLayout(false);
		}
		private void MainForm_Load(object sender, EventArgs e) {
			lvLog.Items.Clear();
			cbBaud.SelectedIndex = 2;
			LogCustom("ExpressOBD 1.0 [github.com/jglim]. Icons: [famfamfam.com/lab/icons/silk]", 4);
		}
		protected override void Dispose(bool disposing) {
			if (disposing && (components != null))
			{
				components.Dispose();
			}
			base.Dispose(disposing);
		}
		private void btnConnect_Click(object sender, EventArgs e) {
			connectingInProgress = true;
			sp = new ELM327();
			sp.Open();
			numberOfPromptsSinceInit = 0;
			serialBuffer.Clear();
			sp.Write("ATWS\r");
			tmrSerialEvent();
			SetupFormForPostConnect();
		}
		private void SetupFormForPreConnect() {
			cbBaud.Enabled = true;
			cbPort.Enabled = true;
			btnConnect.Enabled = serialPortsAreAvailable;
			btnResetErrors.Enabled = false;
		}
		private void SetupFormForPostConnect() {
			cbBaud.Enabled = false;
			cbPort.Enabled = false;
			btnConnect.Enabled = false;
			btnResetErrors.Enabled = ecuIsAvailable;
		}
		private void tmrSerialEvent() {
			while (sp.IsOpen && sp.BytesToRead > 0)
			{
				string inString = sp.Read();
				if (inString == ">")
				{
					numberOfPromptsSinceInit++;
					Console.WriteLine("PC: {0}, Value: {1}", numberOfPromptsSinceInit, serialBuffer.ToString().Replace("\r", ""));
					if (numberOfPromptsSinceInit == 1)
					{
						sp.Write("ATZ\r");
						tmrSerialEvent();
					}
					else if (numberOfPromptsSinceInit == 2)
					{
						if (serialBuffer.ToString().Contains("ELM327"))
						{
							sp.Write("ATE0\r");
						}
					}
					else if (numberOfPromptsSinceInit == 3)
					{
						sp.Write("ATL0\r");
					}
					else if (numberOfPromptsSinceInit == 4)
					{
						sp.Write("ATH1\r");
					}
					else if (numberOfPromptsSinceInit == 5)
					{
						sp.Write("ATSP0\r");
					}
					else if (numberOfPromptsSinceInit == 6)
					{
						sp.Write("ATI\r");
					}
					else if (numberOfPromptsSinceInit == 7)
					{
						if (serialBuffer.ToString().Contains("ELM327"))
						{
							Log("Connected to " + serialBuffer.ToString());
							sp.Write("AT@1\r");
						}
						else
						{
							LogError("No compatible ELM327 device available on " + cbPort.Text);
							DisconnectAndTidyUp();
						}
					}
					else if (numberOfPromptsSinceInit == 8)
					{
						Log("Device Description: " + serialBuffer.ToString());
						sp.Write("ATRV\r");
					}
					else if (numberOfPromptsSinceInit == 9)
					{
						Log("Vehicle Voltage: " + serialBuffer.ToString());
						sp.Write("01 00\r");
					}
					else if (numberOfPromptsSinceInit == 10)
					{
						if (serialBuffer.ToString().Contains("UNABLE TO CONNECT"))
						{
							LogError("ECU not detected! Check OBD2 connection, or if vehicle is switched ON");
							DisconnectAndTidyUp();
						}
						else
						{
							Log("ECU Ready for OBD actions");
							ecuIsAvailable = true;
							sp.Write("ATDP\r");
						}
					}
					else if (numberOfPromptsSinceInit == 11)
					{
						Log("Communicating with ECU via " + serialBuffer.ToString());
						sp.Write("01 01\r");
					}
					else if (numberOfPromptsSinceInit == 12)
					{
						string milData = serialBuffer.ToString();
						milData = milData.Replace("\r", " ").Trim();
						string[] milDataSegments = milData.Split(' ');
						if (milDataSegments.Length != 6)
						{
							LogWarn("MIL Data could not be parsed");
						}
						else
						{
							byte milByte = byte.Parse(milDataSegments[2], System.Globalization.NumberStyles.HexNumber);
							bool milIsActive = ((milByte & 0x80) > 0);
							int milCount = (milByte & 0x7F);
							if (milIsActive)
							{
								LogWarn("MIL (Check Engine Light) is ON. Number of Errors: " + milCount.ToString());
							}
							else
							{
								LogSuccess("MIL (Check Engine Light) is OFF");
							}
						}
						sp.Write("01 01\r");
					}
					else if (numberOfPromptsSinceInit > 99)
					{
						LogSuccess("Erase acknowledged by ECU");
						LogWarn("Restart vehicle to reflect changes");
						DisconnectAndTidyUp();
					}
					serialBuffer.Clear();
				}
				else
				{
					serialBuffer.Append(inString);
				}
			}
		}
		private void btnResetErrors_Click(object sender, EventArgs e) {
			if (MessageBox.Show("This action will: \r\n\r\n\r\n" + "Reset Trouble Code Count and MIL (Check Engine Light)\r\n\r\n" +
				"Erase Diagnostic Trouble Codes, Freeze Frame Data(and associated DTCs), Oxygen Test Data, Mode 06, 07 Data\r\n\r\n" +
				"Mode 0A(Permanent Trouble Codes) are unaffected and can only be reset by ECU\r\n\r\n\r\n" +
				"Would you like to continue?", "Confirm Reset", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK)
			{
				numberOfPromptsSinceInit = 99;
				sp.Write("04 \r");
				tmrSerialEvent();
			}
		}
		private void MainForm_FormClosing(object sender, FormClosingEventArgs e) {
			if (sp != null)
			{
				if (sp.IsOpen)
				{
					sp.Close();
				}
			}
		}
		private void DisconnectAndTidyUp() {
			sp.Close();
			serialBuffer.Clear();
			connectingInProgress = false;
			ecuIsAvailable = false;
			Log("Connection closed automatically");
			SetupFormForPreConnect();
		}
		private void Log(string Message) {
			lvLog.Items.Add(new ListViewItem(Message, 2));
		}
		private void LogWarn(string Message) {
			lvLog.Items.Add(new ListViewItem(Message, 1));
		}
		private void LogSuccess(string Message) {
			lvLog.Items.Add(new ListViewItem(Message, 0));
		}
		private void LogCustom(string Message, int ImageIndex) {
			lvLog.Items.Add(new ListViewItem(Message, ImageIndex));
		}
		private void LogError(string Message) {
			lvLog.Items.Add(new ListViewItem(Message, 3));
		}
		[STAThread]
		static void Main() {
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new MainForm());
		}
	}
}





以上。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?