Настройка считывателя Bluetooth OBD-II Unity не работает на K-LineC#

Место общения программистов C#
Anonymous
Настройка считывателя Bluetooth OBD-II Unity не работает на K-Line

Сообщение Anonymous »

У меня есть система на Unity, которая подключается к одному из адаптеров Bluetooth на базе ELM327 для возврата данных. В моем случае это спидометр.
На SEAT Ibiza Mk-4 (2008–2017) все работает нормально. Однако, когда я попробую это на Audi A3 8L (1996-2000) с портом OBD-II, который, как я полагаю, работает по системе K-Line, а не по шине CAN, как в новых автомобилях. Происходит следующее:
  • Адаптер запускается.
  • Я могу начать чтение.
  • Я получаю обратно немного данных, например. скорость, обороты в минуту, двигатель.
  • Это загружается 1 или 2 раза и, наконец, зависает с сигналом XX XX NO DATA
Что меня сбивает с толку, тот факт, что он работает в течение 2 секунд, а затем выходит из строя
  • Я пробовал инициализировать его для настройки K-line
  • Я пробовал система, которая ожидает ответа перед отправкой следующего.
  • Я пробовал получать только скорость и число оборотов в минуту (поскольку у некоторых автомобилей нет некоторых значений, таких как уровень топлива, положение дроссельной заслонки и т. д.)
Но она все равно делает то же самое.
Моя реальная система работает с библиотекой Java AAB, подключенной к сценарию. Я предполагаю, что с кодом все в порядке, поскольку он отлично работает на новой машине, но я все же хочу посмотреть, в чем может быть проблема для старых автомобилей.
Я использую программу чтения PDF-файлов с адаптером
using System;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using System.Collections.Generic;

public class OBDIIManage : MonoBehaviour
{
public static OBDIIManage _instance;

private AndroidJavaObject obd;

private bool isConnected = false;
private bool isReading = false;

public float rpm;
public float speed;
public float throttle;
public float engineLoad;
public float fuelLevel;
public float coolantTemp;

public string lastsend;

private string pattern = "SRTSRLSRTSRLSRTSRLSRCSRLSRTSRLSRTSRLSRTSRLSRFSRC";
private int patternIndex = 0;

private char lastCommand;

public Action ontick;

public string[] devs;

public RectTransform deviceList;
public GameObject deviceLObj;
public Button refBt;
public Image ConnectBox;
public Text CBText;
public GameObject MMenu;
public GameObject MMenu2;
public List MBts;
public List Textures;
float nextSendTime = 0f;
float sendInterval = 0.01f;
bool usingKLine = false;

void Awake()
{
if (_instance == null) {
_instance = this;
DontDestroyOnLoad(gameObject);
SceneManager.sceneLoaded += OnSceneLoaded;
} else {
Destroy(gameObject);
}
}

void Start()
{
#if UNITY_ANDROID && !UNITY_EDITOR
AndroidJavaClass unityPlayer =
new AndroidJavaClass("com.unity3d.player.UnityPlayer");

AndroidJavaObject activity =
unityPlayer.GetStatic("currentActivity");

obd = new AndroidJavaObject(
"com.example.obdplugin.BluetoothOBD",
activity
);
#endif
int useK = PlayerPrefs.GetInt("KLINEMODE", 0);
ToggleKMode(useK == 1, true);
}

public string[] GetPairedDevices()
{
#if UNITY_ANDROID && !UNITY_EDITOR
return obd.Call("getAvailableDevices");
#else
return new string[0];
#endif
}

public bool Connect(string mac)
{
#if UNITY_ANDROID && !UNITY_EDITOR
isConnected = obd.Call("connect", mac);
return isConnected;
#else
return false;
#endif
}

public void InitELM(int uK) {
usingKLine = (uK == 1);
nextSendTime = Time.time;
Send("ATZ");
Send("ATE0");
Send("ATL0");
Send("ATS0");
Send("ATH0");
if (usingKLine) {
sendInterval = 0.15f;
Send("ATAT0");
Send("ATSTFF");
Send("ATSP5");
} else {
sendInterval = 0.01f;
Send("ATAT2");
Send("ATSP0");
}
}

public void ToggleKMode(bool tr, bool realconnect) {
if(tr) { pattern = "SRSRSRSR";
MBts[0].GetComponent().sprite = Textures[0];
MBts[1].GetComponent().sprite = Textures[1];
PlayerPrefs.SetInt("KLINEMODE", 1); if (realconnect) { InitELM(1); }
} else { pattern = "SRTSRLSRTSRLSRTSRLSRCSRLSRTSRLSRTSRLSRTSRLSRFSRC";
MBts[1].GetComponent().sprite = Textures[0];
MBts[0].GetComponent().sprite = Textures[1];
PlayerPrefs.SetInt("KLINEMODE", 0); if (realconnect) { InitELM(0); }
}
}

void Update() {
if (!isReading) return;
string res = obd.Call("getAndClearResponse");
if (!string.IsNullOrEmpty(res)) {
lastsend = res;
ParseByLastCommand(res);
ontick?.Invoke();
} if (Time.time >= nextSendTime) {
SendNext(); nextSendTime = Time.time + sendInterval;
}
}

void SendNext()
{
char p = pattern[patternIndex];
patternIndex = (patternIndex + 1) % pattern.Length;

lastCommand = p;

switch (p)
{
case 'R': Send("010C"); break;
case 'S': Send("010D"); break;
case 'T': Send("0111"); break;
case 'L': Send("0104"); break;
case 'F': Send("012F"); break;
case 'C': Send("0105"); break;
}
}

void Send(string cmd) {
if (obd != null) obd.Call("sendCommand", cmd);
}

public void StartReading()
{
if (!isConnected || isReading) return;
isReading = true;
}

public void StopReading()
{
isReading = false;
}

void ParseByLastCommand(string res)
{
float val;

switch (lastCommand)
{
case 'R':
val = ParseRPM(res);
if (!float.IsNaN(val)) rpm = val;
break;

case 'S':
val = ParseSpeed(res);
if (!float.IsNaN(val)) speed = val;
break;

case 'T':
val = ParseThrottle(res);
if (!float.IsNaN(val)) throttle = val;
break;

case 'L':
val = ParseLoad(res);
if (!float.IsNaN(val)) engineLoad = val;
break;

case 'F':
val = ParseFuel(res);
if (!float.IsNaN(val)) fuelLevel = val;
break;

case 'C':
val = ParseCoolant(res);
if (!float.IsNaN(val)) coolantTemp = val;
break;
}
}

private string Clean(string res)
{
res = res.Replace("\r", "")
.Replace("\n", "")
.Replace(">", "")
.Trim();

if (!res.Contains(" ") && res.Length % 2 == 0)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for (int i = 0; i < res.Length; i += 2)
{
sb.Append(res.Substring(i, 2));
sb.Append(" ");
}
res = sb.ToString().Trim();
}

return res;
}

float ParseRPM(string res)
{
try
{
string[] p = Clean(res).Split(' ');
if (p.Length < 4) return float.NaN;
int A = Convert.ToInt32(p[2], 16);
int B = Convert.ToInt32(p[3], 16);
return ((A * 256) + B) / 4f;
}
catch { return float.NaN; }
}

float ParseSpeed(string res)
{
try
{
string[] p = Clean(res).Split(' ');
if (p.Length < 3) return float.NaN;
int A = Convert.ToInt32(p[2], 16);
return A;
}
catch { return float.NaN; }
}

float ParseThrottle(string res)
{
try
{
string[] p = Clean(res).Split(' ');
if (p.Length < 3) return float.NaN;
int A = Convert.ToInt32(p[2], 16);
return (A * 100f) / 255f;
}
catch { return float.NaN; }
}

float ParseLoad(string res)
{
try
{
string[] p = Clean(res).Split(' ');
if (p.Length < 3) return float.NaN;
int A = Convert.ToInt32(p[2], 16);
return (A * 100f) / 255f;
}
catch { return float.NaN; }
}

float ParseFuel(string res)
{
try
{
string[] p = Clean(res).Split(' ');
if (p.Length < 3) return float.NaN;
int A = Convert.ToInt32(p[2], 16);
return (A * 100f) / 255f;
}
catch { return float.NaN; }
}

float ParseCoolant(string res)
{
try
{
string[] p = Clean(res).Split(' ');
if (p.Length < 3) return float.NaN;
int A = Convert.ToInt32(p[2], 16);
return A - 40f;
}
catch { return float.NaN; }
}

void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
MBts.Clear(); MMenu = GameObject.Find("SettingMenu");
MMenu2 = GameObject.Find("(OBDMENU");
deviceList = GameObject.Find("DVL").GetComponent();
deviceLObj = GameObject.Find("DVLCL");
refBt = GameObject.Find("rfbt").GetComponent();
ConnectBox = GameObject.Find("DB").GetComponent();
CBText = ConnectBox.transform.GetChild(0).GetComponent();
MBts.Add(GameObject.Find("KLBTN1").GetComponent());
MBts.Add(GameObject.Find("KLBTN2").GetComponent());
MBts[0].onClick.AddListener(() => { ToggleKMode(false, isReading); });
MBts[1].onClick.AddListener(() => { ToggleKMode(true, isReading); });

refBt.onClick.AddListener(() => { RefList(); });

MMenu2.SetActive(false);
MMenu.SetActive(false);
deviceLObj.SetActive(false);

RefList();
}

public void RefList()
{
devs = GetPairedDevices();

foreach (Transform fs in deviceList)
Destroy(fs);

for (int f = 0; f < devs.Length; f++)
{
GameObject newBtn = Instantiate(deviceLObj, deviceList);
newBtn.SetActive(true);

newBtn.GetComponent().anchoredPosition =
new Vector2(0f, -10f + (-120f * f));

int splitpos = devs[f].IndexOf('|');
int lbf = f;

newBtn.transform.GetChild(0).GetComponent().text =
devs[f].Remove(splitpos);

newBtn.GetComponent().onClick.AddListener(() =>
{
StartCoroutine(AttemptConnect(devs[lbf]));
});
}

deviceList.sizeDelta =
new Vector2(deviceList.sizeDelta.x, 20f + (120f * devs.Length));
}

public System.Collections.IEnumerator AttemptConnect(string full)
{
ConnectBox.color = Color.white;
CBText.fontSize = 38;
CBText.text = "Connecting...";

string[] split = full.Split('|');

yield return null;

bool connct = Connect(split[1]);

if (connct) {
ConnectBox.color = new Color(0.45f, 1f, 0.5f);
CBText.fontSize = 60;
CBText.text = split[0];
nextSendTime = Time.time;
int useK = PlayerPrefs.GetInt("KLINEMODE", 0);
obd.Call("getAndClearResponse");
StartReading(); ToggleKMode(useK == 1, true);
}
else
{
ConnectBox.color = Color.red;
CBText.text = "Connection Failed";
}
}
}

Вернуться в «C#»