在开发前,以为蓝牙这块已经很成熟了,基本信手拈来。
蛋是!搜索一圈下来,发现unity支持蓝牙开发的寥寥无几,找下来就发现一个BLE的插件和一个arduino的插件。然而...我要做的是通过PC的蓝牙模块来连接并取得蓝牙传感器数据,开始方了...
由于我是一个unity钉子户,.Net的winform不会写,网上找到的窗体应用也无法复用,又没有开发过蓝牙,项目又催得紧,只能抓紧时间各种找资料。
功夫不负有心人,在stack上找到一个国外大牛的发言,他自己做了一套unity可以调用BLE的库,果断请教。
后来去大佬的github down下来,(末尾已贴链接)本地打开测试后已经可以连接,但是会遇到身份验证无法通过的一个问题,问过硬件厂商说没有加身份验证。
然后偶然发现是我在电脑的蓝牙上需要先连接匹配上传感器,然后在项目内在扫描蓝牙设备,找到自己需要的service name和特征码,点击订阅,就可以接收到传感器的数据了,贴下我自己修改的部分代码,基本没啥大改。
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class Demo : MonoBehaviour
{
public GameManager manager;
public bool isScanningDevices = false;
public bool isScanningServices = false;
public bool isScanningCharacteristics = false;
public bool isSubscribed = false;
public Text deviceScanButtonText;
public Text deviceScanStatusText;
public GameObject deviceScanResultProto;
public Button serviceScanButton;
public Text serviceScanStatusText;
public Dropdown serviceDropdown;
public Button characteristicScanButton;
public Text characteristicScanStatusText;
public Dropdown characteristicDropdown;
public Button subscribeButton;
public Text subcribeText;
public Button writeButton;
public InputField writeInput;
public Text errorText;
Transform scanResultRoot;
public string selectedDeviceId;
public string selectedServiceId;
Dictionary<string, string> characteristicNames = new Dictionary<string, string>();
public string selectedCharacteristicId;
Dictionary<string, Dictionary<string, string>> devices = new Dictionary<string, Dictionary<string, string>>();
string lastError;
// Start is called before the first frame update
void Start()
{
scanResultRoot = deviceScanResultProto.transform.parent;
deviceScanResultProto.transform.SetParent(null);
}
GameObject g = null;
// Update is called once per frame
void Update()
{
BleApi.ScanStatus status;
if (isScanningDevices)
{
BleApi.DeviceUpdate res = new BleApi.DeviceUpdate();
do
{
status = BleApi.PollDevice(ref res, false);
if (status == BleApi.ScanStatus.AVAILABLE)
{
if (!devices.ContainsKey(res.id))
{
devices[res.id] = new Dictionary<string, string>() {
{ "name", "" },
{ "isConnectable", "False" }
};
}
if (res.nameUpdated)
devices[res.id]["name"] = res.name;
if (res.isConnectableUpdated)
devices[res.id]["isConnectable"] = res.isConnectable.ToString();
// consider only devices which have a name and which are connectable
if (devices[res.id]["name"] != "" && devices[res.id]["isConnectable"] == "True")
{
// add new device to list
GameObject g = Instantiate(deviceScanResultProto, scanResultRoot);
g.name = res.id;
g.transform.GetChild(0).GetComponent<Text>().text = devices[res.id]["name"];
g.transform.GetChild(1).GetComponent<Text>().text = res.id;
}
}
else if (status == BleApi.ScanStatus.FINISHED)
{
isScanningDevices = false;
deviceScanButtonText.text = "扫描设备";
deviceScanStatusText.text = "finished";
}
} while (status == BleApi.ScanStatus.AVAILABLE);
//isScanningDevices = false;
}
if (isScanningServices)
{
BleApi.Service res = new BleApi.Service();
do
{
status = BleApi.PollService(out res, false);
if (status == BleApi.ScanStatus.AVAILABLE)
{
serviceDropdown.AddOptions(new List<string> { res.uuid });
// first option gets selected
if (serviceDropdown.options.Count == 1)
SelectService(serviceDropdown.gameObject);
}
else if (status == BleApi.ScanStatus.FINISHED)
{
isScanningServices = false;
serviceScanButton.interactable = true;
serviceScanStatusText.text = "finished";
}
} while (status == BleApi.ScanStatus.AVAILABLE);
}
if (isScanningCharacteristics)
{
BleApi.Characteristic res = new BleApi.Characteristic();
do
{
status = BleApi.PollCharacteristic(out res, false);
if (status == BleApi.ScanStatus.AVAILABLE)
{
string name = res.userDescription != "no description available" ? res.userDescription : res.uuid;
characteristicNames[name] = res.uuid;
characteristicDropdown.AddOptions(new List<string> { name });
// first option gets selected
if (characteristicDropdown.options.Count == 1)
SelectCharacteristic(characteristicDropdown.gameObject);
}
else if (status == BleApi.ScanStatus.FINISHED)
{
isScanningCharacteristics = false;
characteristicScanButton.interactable = true;
characteristicScanStatusText.text = "finished";
}
} while (status == BleApi.ScanStatus.AVAILABLE);
}
if (isSubscribed)
{
BleApi.BLEData res = new BleApi.BLEData();
while (BleApi.PollData(out res, false))
{
subcribeText.text = BitConverter.ToString(res.buf, 0, res.size);
subcribeText.text= Hex2Ten(subcribeText.text);
string[] TenArray = subcribeText.text.Split(' ');
//manager.currentturnCount = manager.totalturnCount -lastCount ;
manager.totalturnCount = int.Parse(TenArray[18]);
}
}
{
// log potential errors
BleApi.ErrorMessage res = new BleApi.ErrorMessage();
BleApi.GetError(out res);
if (lastError != res.msg)
{
Debug.LogError(res.msg);
errorText.text = res.msg;
lastError = res.msg;
}
}
//lastCount = manager.totalturnCount;
//Debug.Log("lastCount" + lastCount);
//Debug.Log("currentturnCount" + manager.currentturnCount);
}
int lastCount = 0;
public static string Hex2Ten(string hex)
{
string[] array = hex.Split('-');
string str = "";
for (int k = 0; k < array.Length; k++)
{
int ten= Convert.ToInt32(array[k], 16);
str += ten.ToString() + " ";
}
return str.ToString();
}
private void OnApplicationQuit()
{
BleApi.Quit();
}
public void StartStopDeviceScan()
{
if (!isScanningDevices)
{
// start new scan
for (int i = scanResultRoot.childCount - 1; i >= 0; i--)
Destroy(scanResultRoot.GetChild(i).gameObject);
BleApi.StartDeviceScan();
isScanningDevices = true;
deviceScanButtonText.text = "停止扫描";
deviceScanStatusText.text = "scanning";
}
else
{
// stop scan
isScanningDevices = false;
BleApi.StopDeviceScan();
deviceScanButtonText.text = "扫描设备";
deviceScanStatusText.text = "stopped";
}
}
public void SelectDevice(GameObject data)
{
for (int i = 0; i < scanResultRoot.transform.childCount; i++)
{
var child = scanResultRoot.transform.GetChild(i).gameObject;
child.transform.GetChild(0).GetComponent<Text>().color = child == data ? Color.red :
deviceScanResultProto.transform.GetChild(0).GetComponent<Text>().color;
}
selectedDeviceId = data.name;
serviceScanButton.interactable = true;
}
public void StartServiceScan()
{
if (!isScanningServices)
{
// start new scan
serviceDropdown.ClearOptions();
BleApi.ScanServices(selectedDeviceId);
isScanningServices = true;
serviceScanStatusText.text = "scanning";
serviceScanButton.interactable = false;
}
}
public void SelectService(GameObject data)
{
selectedServiceId = serviceDropdown.options[serviceDropdown.value].text;
characteristicScanButton.interactable = true;
}
public void StartCharacteristicScan()
{
if (!isScanningCharacteristics)
{
// start new scan
characteristicDropdown.ClearOptions();
BleApi.ScanCharacteristics(selectedDeviceId, selectedServiceId);
isScanningCharacteristics = true;
characteristicScanStatusText.text = "scanning";
characteristicScanButton.interactable = false;
}
}
public void SelectCharacteristic(GameObject data)
{
string name = characteristicDropdown.options[characteristicDropdown.value].text;
selectedCharacteristicId = characteristicNames[name];
subscribeButton.interactable = true;
writeButton.interactable = true;
}
public void Subscribe()
{
// no error code available in non-blocking mode
BleApi.SubscribeCharacteristic(selectedDeviceId, selectedServiceId, selectedCharacteristicId, false);
isSubscribed = true;
}
public void Write()
{
byte[] payload = Encoding.ASCII.GetBytes(writeInput.text);
BleApi.BLEData data = new BleApi.BLEData();
data.buf = new byte[512];
data.size = (short)payload.Length;
data.deviceId = selectedDeviceId;
data.serviceUuid = selectedServiceId;
data.characteristicUuid = selectedCharacteristicId;
for (int i = 0; i < payload.Length; i++)
data.buf[i] = payload[i];
// no error code available in non-blocking mode
BleApi.SendData(in data, false);
}
}
中间做了一个取值和进制转换,就可以渠道自己想要的数据了。
https://github.com/adabru/BleWinrtDll
再次感谢大佬,希望有用到的朋友可以给他点个star。
ok,分享就到这了。
下载不了的私信我。