从 Xamarin Android 中的 RPM 响应中提取最后 4 位数字(例如“41 0C”)并执行十进制转换并除以 4

问题描述 投票:0回答:1

我正在使用 C# 为 Xamarin Android 应用程序开发数字仪表板。作为该项目的一部分,我收到十六进制字符串形式的 RPM 响应。现在,我需要从这些响应中提取最后 4 位数字,将它们转换为十进制,然后以编程方式将结果除以 4 就像如果响应采用这种格式 41 0C 11 F1 我想提取这个 11 F1 但值可以有所不同。这是我的 mainactivity.cs

using Android.App;
using Android.OS;
using Android.Widget;
using Android.Views;
using Java.Util;
using System;
using System.Threading;
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 rawRpmLabel;
        private TextView rawSpeedLabel;
        private TextView anotherRpmDoubleLabel;
        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);
            rawRpmLabel = FindViewById<TextView>(Resource.Id.rawRpmLabel);
            rawSpeedLabel = FindViewById<TextView>(Resource.Id.rawSpeedLabel);
            anotherRpmDoubleLabel = FindViewById<TextView>(Resource.Id.anotherRpmDoubleLabel);
            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(2000);
            updateTimer.Elapsed += OnUpdateTimerElapsed;
            updateTimer.Start();
        }


        private void OnUpdateTimerElapsed(object sender, ElapsedEventArgs e)
        {
            // Request RPM
            obdManager.SendCommand("010C", OnRPMReceived);
            obdManager.SendCommand("010C", OnRAWRpmReceived);
            // Request speed
            obdManager.SendCommand("010D", OnSpeedReceived);


        }

        private void OnRPMReceived(string rpmdata)
        {
            try
            {
                // Parse the RPM value
                string rpmValue = ObdProtocol.ParseRPM(rpmdata);

                // Update the raw RPM label with the parsed raw RPM data
                RunOnUiThread(() => rawRpmLabel.Text = $"Raw RPM Data: {rpmValue}");

                // Optionally, you can also update the RPM label with the same value
                RunOnUiThread(() => rpmLabel.Text = $"RPM: {rpmValue}");
                //obdManager.SendCommand("010D", OnRealRAWRpmReceived);
                //  RunOnUiThread(() => anotherRpmDoubleLabel.Text = $"RPM: {rpmdata}");
                // Update the new label with the parsed RPM data as a double

            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error updating RPM label: {ex.Message}");
            }
        }
        /*public static double ParseRealRPM(string realrpmdata)
        {
            // Find the RPM value in the response
            int startIndex = realrpmdata.LastIndexOf("010C") + 4;

            // Check if the start index is valid
            if (startIndex < 0 || startIndex + 4 > realrpmdata.Length)
            {
                // Handle invalid data or return a default value
                return 0.0; // You can adjust the default value based on your needs
            }

            // Get the last 4 digits of the response
            string rpmHex = realrpmdata.Substring(startIndex, 4);

            try
            {
                // Convert the hexadecimal value to decimal
                int rpmDecimal = Convert.ToInt32(rpmHex, 16);

                // Divide the decimal value by 4
                double realrpmValue = rpmDecimal / 4.0;

                return realrpmValue;
            }
            catch (FormatException ex)
            {
                // Handle the FormatException (non-parsable characters)
                // Log the error or return a default value
                Console.WriteLine($"Error parsing RPM value: {ex.Message}");
                return 0.0; // You can adjust the default value based on your needs
            }
        }*/


        /*   public void OnRealRAWRpmReceived(string realrpmdata)
           {
               RunOnUiThread(() => anotherRpmDoubleLabel.Text = $"RealRPM: {ParseRealRPM(realrpmdata)}");
           }*/




        private void UpdateRPMUI(double actualRPM)
        {
            RunOnUiThread(() => rpmLabel.Text = $"RPM: {actualRPM:F2} RPM");
        }
        private void OnSpeedReceived(string speeddata)
        {
            try
            {
                // Update the speed label with raw speed data
                RunOnUiThread(() => rawSpeedLabel.Text = $"Raw Speed Data: {speeddata}");

                // Parse and display the converted speed value
                int speedValue = ObdProtocol.ParseSpeed(speeddata);
                UpdateSpeedUI(speedValue);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error parsing Speed data: {ex.Message}");
            }
        }





        private void UpdateSpeedUI(int speedValue)
        {
            RunOnUiThread(() => speedLabel.Text = $"Speed: {speedValue} km/h");
        }

        /* public void OnRAWRpmReceived(string rpmData)
          {
              // Check if the response contains "010C" (the command)
              int index = rpmData.IndexOf("010C");
              if (index != -1)
              {
                  // If "010C" is found, extract the RPM data after it
                  string rpmDataWithoutCommand = rpmData.Substring(index + 8); // Assuming "010C" is 4 characters long

                  // Extract the last 4 digits of the response
                  string lastFourDigitsHex = rpmDataWithoutCommand.Substring(0, 8);

                  // Convert the last 4 hexadecimal digits to decimal
                  int decimalValue = Convert.ToInt32(lastFourDigitsHex, 16);

                  // Divide the decimal value by 4
                  double result = decimalValue / 4.0;

                  // Now you can update the UI with the result
                  RunOnUiThread(() => rawRpmLabel.Text = $"Raw RPM Data: {result}");
              }
              else
              {
                  // If "010C" is not found, handle the response as needed
                  Console.WriteLine("Response does not contain RPM data.");
              }
          }*/


          public void OnRAWRpmReceived(string rpmData)
              {
                  // Check if the response contains "010C" (the command)
                  int index = rpmData.IndexOf("010C");
                  if (index != -1)
                  {
                      // If "010C" is found, extract the RPM data after it
                      string rpmDataWithoutCommand = rpmData.Substring(index + 4); // Assuming "010C" is 4 characters long
                                                                                   // Now you can update the UI with the extracted RPM data
                      RunOnUiThread(() => rawRpmLabel.Text = $"Raw RPM Data: {rpmDataWithoutCommand}");
                  }
                  else
                  {
                      // If "010C" is not found, handle the response as needed
                      Console.WriteLine("Response does not contain RPM data.");
                  }
             }
     




        /* public void OnRAWRpmReceived(string rpmData)
         {
             // Check if the response contains "410C" (the command)
             int index = rpmData.IndexOf("410C");
             if (index != -1)
             {
                 // If "410C" is found, extract the RPM data after it
                 string rpmDataWithoutCommand = rpmData.Substring(index + 4); // Assuming "410C" is 4 characters long

                 // Extract the last 4 digits of the response
                 string lastFourDigitsHex = rpmDataWithoutCommand.Substring(0, 4);

                 // Convert the last 4 hexadecimal digits to decimal
                 int decimalValue = Convert.ToInt32(lastFourDigitsHex, 16);

                 // Divide the decimal value by 4
                 double result = decimalValue / 4.0;

                 // Now you can update the UI with the result
                 RunOnUiThread(() => rawRpmLabel.Text = $"Raw RPM Data: {result}");
             }
             else
             {
                 // If "410C" is not found, handle the response as needed
                 Console.WriteLine("Response does not contain RPM data.");
             }
         }*/



        /*public void OnRAWRpmReceived(string rpmdata)
        {
            try
            {
                // Parse the RPM value as a string
                string rpmHex = ObdProtocol.ParseRPM(rpmdata);

                // Convert the string to decimal and divide by 4.0
                double rpmValue = Convert.ToInt32(rpmHex, 16) / 4.0;

                // Update the raw RPM label with the parsed raw RPM data
                RunOnUiThread(() => rawRpmLabel.Text = $"Raw RPM{rpmValue} data");
            }
            catch (Exception ex)
            {
                // Handle any exceptions that might occur during parsing or UI update
                Console.WriteLine($"Error processing RPM data: {ex.Message}");
            }
        }*/





        /*VAJNO RABOTESHT KOD ZA SKOROST V 16-TICEN KOD private void OnRawSpeedReceived(string rawspeeddata)
          {
              RunOnUiThread(() => rawSpeedLabel.Text = $"Raw Speed Data: {rawspeeddata}");
          }*/
        public void OnRawSpeedReceived(string rawSpeedData)
        {
            // Check if the response contains "010D" (the command for speed)
            int index = rawSpeedData.IndexOf("010D");
            if (index != -1)
            {
                // If "010D" is found, extract the speed data after it
                string speedDataWithoutCommand = rawSpeedData.Substring(index + 4); // Assuming "010D" is 4 characters long
                                                                                    // Now you can update the UI with the extracted speed data
                RunOnUiThread(() => rawSpeedLabel.Text = $"Raw Speed Data: {speedDataWithoutCommand}");
            }
            else
            {
                // If "010D" is not found, handle the response as needed
                Console.WriteLine("Response does not contain speed data.");
            }
        }


        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

                    // Request protocol information after the connection is successful

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

和我的 obdprotocol 类

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 ObdProtocol
    {

        /* public static double ParseRPM(string rpmdata)
         {
             // Find the RPM value in the response
             int startIndex = rpmdata.IndexOf("010C") + 6;
             string rpmHex = rpmdata.Substring(startIndex, 4);

             // Convert the hex RPM value to decimal
             int rpmDecimal = Convert.ToInt32(rpmHex, 16);

             // Calculate the actual RPM value as per the specified formula
             double actualRPM = rpmDecimal * 0.25; // Multiply by 0.25 to get RPM in its physical units

             return actualRPM;
         }*/

        /* WOOORKS public static string ParseRPM(string rpmdata)
              {
                  // Find the RPM value in the response
              //changed from 010C to 410C   int startIndex = rpmdata.IndexOf("410C") + 6;
                  string rpmHex = rpmdata.Substring(startIndex, 4);

                  return rpmHex;
          }*/


         public static string ParseRPM(string rpmdata)
          {
              // Find the RPM value in the response
              //hanged from 010C to 410C
        int startIndex = rpmdata.IndexOf("410C") + 6;
            string rpmHex = rpmdata.Substring(startIndex, 4);

            return rpmHex;
        }

    



        /*   public static double ParseRealRPM(string realrpmdata)
       {
           // Find the RPM value in the response
           int startIndex = realrpmdata.LastIndexOf("010C") + 4;

              // Get the last 4 digits of the response
              string rpmHex = realrpmdata.Substring(startIndex, 4);

              // Convert the hexadecimal value to decimal
              int rpmDecimal = Convert.ToInt32(rpmHex, 16);

              // Divide the decimal value by 4
              double realrpmValue = rpmDecimal / 4.0;

           return realrpmValue;
       }*/





        public static int ParseSpeed(string speeddata)
        {
            // Example: assuming data is in the format "2131 7F", where 7F is speed
            int startIndex = speeddata.IndexOf("410D") + 8;
            string speedHex = speeddata.Substring(startIndex, 2);
            return Convert.ToInt32(speedHex, 16);
        }
    }
}



c# xamarin.android obd-ii
1个回答
0
投票

以下是 CAN 车辆对 Pid 0x0C rpm 的典型字符串响应

“7E804410C0AF4”。

此响应表明命令 410C 已发送至车辆的 Ecu,并且 Ecu 已响应上述字符串。最后两个字节包含计算转速所需的信息。他们是0A F4。

使用 SAE 约定,我们将它们称为 dataA 和 dataB,声明为 int。 处理它们的最简单方法如下。 2 字节响应是 dataA = 000A 和 dataB = 00F4。所以

rpm = dataA << 8 | dataB.

现在你有了两个字节的数字表示。

Pid 0x0C 的缩放位为每位 1/4 rpm。现在除以 4。因此,rpm 范围为 0 – 16383.75rpm。

处理 Pid 字符串响应的最简单方法是为每个 Pid 提供一个事件处理程序。例如

public EngineRPMSensorReceivedEventArgs(byte[] message) : base(message){…}

然后当您解析 OBD 字符串响应时

case 0x0C: // Engine rpm
    OnEngineRPMSensorReceived(new EngineRPMSensorReceivedEventArgs(pidMessage));
    break;

同一车辆对 Pid 0x0D 速度 7E803410D19 的响应。 dataA 为 19。单字节响应。缩放位 1 km/h。因此19公里/小时。最大值 255 公里/小时。

case 0x0D: // Vehicle speed
    OnVehicleSpeedSensorReceived(new VehicleSpeedSensorReceivedEventArgs(pidMessage));
break;

处理 OBD 数据始终是十六进制字符串到数字,因此您需要使用最有效的技术来处理转换。 C# Sharp 拥有您需要的所有位操作工具,无需求助于 Convert.ToInt32() 等。

不要忘记我的示例响应是针对 CAN 车辆的,与早期协议的响应完全不同(数据相同但标头不同)。

© www.soinside.com 2019 - 2024. All rights reserved.