I'm currently working on a Xamarin Forms C# app for a digital dashboard that aims to read real-time data from an OBD-II ELM327 device. I'm facing an issue where the app is not receiving accurate data for RPM and Speed in km/h. My phone connects succesfuly with obd 2 device it starts retreiving data but this data for rpm and speed is kinda unreal like when car is not moving i got values aroun 60 til 100 kmph or even more same goes for rpm... i checked the commands they are fine protocol is fine i dont know from where problem can come from. my vehicle is using iso14230 kwp fast protocol
tried with different protocols and different commands and still no difference
ObdProtocol.cs
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using OBD.NET;
using OBD.NET.Common.Devices;
using OBD.NET.Common.Extensions;
using OBD.NET.Common.Logging;
using OBD.NET.Common.OBDData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace App6
{
public class ObdProtocol
{
public static int ParseValue(string data, string pid)
{
// Find the PID in the response
int startIndex = data.IndexOf(pid);
if (startIndex != -1)
{
// Extract the value
int valueStartIndex = startIndex + pid.Length;
string valueHex = data.Substring(valueStartIndex, 2);
return Convert.ToInt32(valueHex, 16);
}
// Return a default or error value if the PID is not found
return -1;
}
public static int ParseRPM(string data)
{
// Implement RPM parsing logic
// Example: assuming data is in the format "41 0C 0A 1F", where 0C is RPM
int startIndex = data.IndexOf("010C") + 6;
string rpmHex = data.Substring(startIndex, 2) + data.Substring(startIndex + 3, 2);
return Convert.ToInt32(rpmHex, 16) / 4; // RPM is usually in 1/4 RPM units
}
public static string ParseProtocol(string data)
{
int startIndex = data.IndexOf("DP");
if (startIndex != -1)
{
int protocolStartIndex = startIndex + 2;
string protocol = data.Substring(protocolStartIndex).Trim();
return protocol;
}
return "Unknown"; // Set a default value or handle the case when protocol is not found
}
public static int ParseSpeed(string data)
{
// Implement speed parsing logic
// Example: assuming data is in the format "41 0D 2A", where 0D is speed
int startIndex = data.IndexOf("010D") + 6;
string speedHex = data.Substring(startIndex, 2);
return Convert.ToInt32(speedHex, 16);
}
}
}
MainActivity.cs
using Android.App;
using Android.OS;
using Android.Widget;
using Android.Views;
using Java.Util;
using System;
using System.Threading;
using OBD.NET.Common.Devices;
using OBD.NET.Common.Extensions;
using OBD.NET.Common.Logging;
using OBD.NET.Common.OBDData;
using System.Timers;
using Xamarin.Essentials;
using System.Threading.Tasks;
using Android.Bluetooth;
using System.Reflection;
using In.UnicodeLabs.KdGaugeViewLib;
namespace App6
{
[Activity(Label = "@string/app_name", Theme = "@style/AppTheme", MainLauncher = true)]
public class MainActivity : Activity
{
private TextView rpmLabel;
private TextView speedLabel;
private ObdManager obdManager;
private BluetoothSocket btnSocket;
private TextView obdInfoLabel;
private Button requestButton;
private TextView obdProtocolLabel;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.activity_main);
rpmLabel = FindViewById<TextView>(Resource.Id.rpmLabel);
speedLabel = FindViewById<TextView>(Resource.Id.speedLabel);
obdInfoLabel = FindViewById<TextView>(Resource.Id.obdInfoLabel);
obdProtocolLabel = FindViewById<TextView>(Resource.Id.obdProtocolLabel);
InitializeBluetooth();
obdManager = new ObdManager(btnSocket);
// Set up a timer to periodically request and update RPM and speed (every 0.1 seconds)
System.Timers.Timer updateTimer = new System.Timers.Timer(500);
updateTimer.Elapsed += OnUpdateTimerElapsed;
updateTimer.Start();
}
private void OnUpdateTimerElapsed(object sender, ElapsedEventArgs e)
{
// Request RPM
obdManager.SendCommand("010C", OnRPMReceived);
// Request speed
obdManager.SendCommand("010D", OnSpeedReceived);
// Request protocol
obdManager.SendCommand("AT DP", OnProtocolReceived);
}
private void OnRPMReceived(string data)
{
try
{
int rpmValue = ObdProtocol.ParseRPM(data);
UpdateRPMUI(rpmValue);
}
catch (Exception ex)
{
Console.WriteLine($"Error parsing RPM data: {ex.Message}");
}
}
private void OnSpeedReceived(string data)
{
try
{
int speedValue = ObdProtocol.ParseSpeed(data);
UpdateSpeedUI(speedValue);
}
catch (Exception ex)
{
Console.WriteLine($"Error parsing Speed data: {ex.Message}");
}
}
private void OnProtocolReceived(string data)
{
try
{
// Parse and display the received OBD2 protocol information
string protocol = ObdProtocol.ParseProtocol(data);
// Update the obdInfoLabel
UpdateObdInfoLabel($"Protocol: {protocol}");
// Update the obdProtocolLabel
UpdateObdProtocolLabel($"Protocol: {protocol}");
}
catch (Exception ex)
{
Console.WriteLine($"Error parsing OBD2 protocol data: {ex.Message}");
}
}
private void UpdateRPMUI(int rpmValue)
{
RunOnUiThread(() => rpmLabel.Text = $"RPM: {rpmValue} RPM");
}
private void UpdateSpeedUI(int speedValue)
{
RunOnUiThread(() => speedLabel.Text = $"Speed: {speedValue} km/h");
}
private void UpdateObdInfoLabel(string info)
{
RunOnUiThread(() =>
{
obdInfoLabel.Text = $"OBD Info: {info}";
});
}
private void UpdateObdProtocolLabel(string info)
{
RunOnUiThread(() =>
{
obdProtocolLabel.Text = info;
});
}
private void InitializeBluetooth()
{
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.DefaultAdapter;
if (bluetoothAdapter == null)
{
return;
}
if (!bluetoothAdapter.IsEnabled)
{
Android.Content.Intent enableBtIntent = new Android.Content.Intent(BluetoothAdapter.ActionRequestEnable);
StartActivityForResult(enableBtIntent, requestCode: 1);
return;
}
BluetoothDevice obdDevice = FindOBDIIBluetoothDevice("00:1D:A5:68:98:8A");
if (obdDevice != null)
{
try
{
UUID sppUuid = UUID.FromString("00001101-0000-1000-8000-00805F9B34FB");
btnSocket = obdDevice.CreateRfcommSocketToServiceRecord(sppUuid);
btnSocket.Connect();
// Connection successful, show a message to the user
MainThread.BeginInvokeOnMainThread(() =>
{
Toast.MakeText(this, $"Bluetooth connection to {obdDevice.Name} established.", ToastLength.Long).Show();
});
// Set the protocol to "AUTO" after connection
obdManager.SendCommand("AT SP 0", data => { });
// Request protocol information after the connection is successful
obdManager.SendCommand("AT DP", OnProtocolReceived);
}
catch (Exception ex)
{
// Connection failed, show a message to the user
MainThread.BeginInvokeOnMainThread(() =>
{
Toast.MakeText(this, $"Bluetooth connection error: {ex.Message}", ToastLength.Long).Show();
});
}
}
else
{
// Device not found, show a message to the user
MainThread.BeginInvokeOnMainThread(() =>
{
Toast.MakeText(this, "Bluetooth device not found.", ToastLength.Long).Show();
});
}
}
private BluetoothDevice FindOBDIIBluetoothDevice(string deviceAddress)
{
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.DefaultAdapter;
if (bluetoothAdapter == null || !bluetoothAdapter.IsEnabled)
{
return null;
}
foreach (BluetoothDevice device in bluetoothAdapter.BondedDevices)
{
if (device.Address == deviceAddress)
{
return device;
}
}
// If not found among bonded devices, try discovering new devices
if (bluetoothAdapter.IsDiscovering)
{
bluetoothAdapter.CancelDiscovery();
}
bluetoothAdapter.StartDiscovery();
// Wait for discovery to complete (you might want to implement a BroadcastReceiver for better handling)
System.Threading.Thread.Sleep(5000); // Adjust this timeout as needed
foreach (BluetoothDevice device in bluetoothAdapter.BondedDevices)
{
if (device.Address == deviceAddress)
{
return device;
}
}
return null;
}
}
}
ObdManager class is designed to facilitate communication with an OBD device through a Bluetooth socket. ObdManager.cs
using Android.App;
using Android.Bluetooth;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace App6
{
public class ObdManager
{
private readonly BluetoothSocket _btnSocket;
public ObdManager(BluetoothSocket btnSocket)
{
_btnSocket = btnSocket;
}
public void SendCommand(string command, Action<string> onDataReceived)
{
if (_btnSocket.IsConnected)
{
byte[] cmd = Encoding.ASCII.GetBytes(command + "\r");
_btnSocket.OutputStream.Write(cmd, 0, cmd.Length);
_btnSocket.OutputStream.Flush();
ReadData(out string data);
if (!string.IsNullOrEmpty(data))
{
onDataReceived?.Invoke(data);
}
}
}
public void ReadData(out string data)
{
StringBuilder res = new StringBuilder();
try
{
int b = 0;
char c;
while ((b = (byte)_btnSocket.InputStream.ReadByte()) > -1)
{
c = (char)b;
if (c == '>')
{
break;
}
res.Append(c);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
data = res.ToString().Replace("SEARCHING", "");
data = data.Replace("\\s", "");
}
}
}
i really dont know from where the problem can come from