我正在尝试通过蓝牙将数据从 HoloLens 2 发送到 arduino 设备。从文档中,我发现使用 RFCOMM 将是我执行此操作的最直接、最简单的方法(因为此处页面上确实给出了 RFCOMM 的示例代码)。此外,我选择 RFCOMM 而不是其他受支持的方法 GATT,因为我几乎没有蓝牙开发经验。
我正在 Unity 上使用 MRTK 2 开发我的应用程序。除了蓝牙连接部分之外,该应用程序的所有功能均按预期工作。
到目前为止,我已经实现了文档here中提供的示例代码,但不幸的是,这会导致部署到 HoloLens 进程彻底失败。以下是构建失败时得到的错误代码:
Build completed with a result of 'Failed' in 32 seconds (31897 ms)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
UnityEditor.BuildPlayerWindow+BuildMethodException: 10 errors
at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002da] in <11d97693183d4a6bb35c29ae7882c66b>:0
at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in <11d97693183d4a6bb35c29ae7882c66b>:0
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
我尝试用我有限的知识来调试这个问题,但到目前为止还没有成功。
下面是我程序中的相关代码:
...
#if WINDOWS_UWP
using Windows.Storage;
using Windows.System;
using System.Threading.Tasks;
using Windows.Storage.Streams;
using Windows.Devices.Bluetooth.Rfcomm;
using Windows.Networking.Sockets;
using Windows.Devices.Bluetooth;
Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService _service;
Windows.Networking.Sockets.StreamSocket _socket;
#endif
...
public class LightController : MonoBehaviour{
//this part is mainly for creating the connection as far as I can tell
#if WINDOWS_UWP
Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
bool firstSave = true;
// This App requires a connection that is encrypted but does not care about
// whether it's authenticated.
bool SupportsProtection(RfcommDeviceService service){
switch (service.ProtectionLevel){
case SocketProtectionLevel.PlainSocket:
if ((service.MaxProtectionLevel == SocketProtectionLevel
.BluetoothEncryptionWithAuthentication)
|| (service.MaxProtectionLevel == SocketProtectionLevel
.BluetoothEncryptionAllowNullAuthentication)){
// The connection can be upgraded when opening the socket so the
// App may offer UI here to notify the user that Windows may
// prompt for a PIN exchange.
return true;
}
else{
// The connection cannot be upgraded so an App may offer UI here
// to explain why a connection won't be made.
return false;
}
case SocketProtectionLevel.BluetoothEncryptionWithAuthentication:
return true;
case SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication:
return true;
}
return false;
}
// This App relies on CRC32 checking available in version 2.0 of the service.
const uint SERVICE_VERSION_ATTRIBUTE_ID = 0x0300;
const byte SERVICE_VERSION_ATTRIBUTE_TYPE = 0x0A; // UINT32
const uint MINIMUM_SERVICE_VERSION = 200;
async Task<bool> IsCompatibleVersionAsync(RfcommDeviceService service){
var attributes = await service.GetSdpRawAttributesAsync(
BluetoothCacheMode.Uncached);
var attribute = attributes[SERVICE_VERSION_ATTRIBUTE_ID];
var reader = DataReader.FromBuffer(attribute);
// The first byte contains the attribute's type
byte attributeType = reader.ReadByte();
if (attributeType == SERVICE_VERSION_ATTRIBUTE_TYPE){
// The remainder is the data
uint version = reader.ReadUInt32();
return version >= MINIMUM_SERVICE_VERSION;
}
else return false;
}
//this is called in the "Start()" function
async void Initialize(){
// Enumerate devices with the object push service
var services =
await Windows.Devices.Enumeration.DeviceInformation.FindAllAsync(
RfcommDeviceService.GetDeviceSelector(
RfcommServiceId.ObexObjectPush));
if (services.Count > 0){
// Initialize target Bluetooth BR device
var hc06Device = services.FirstOrDefault(service => service.Name == "HC-06");
var service = await RfcommDeviceService.FromIdAsync(hc06Device.Id);
bool isCompatibleVersion = await IsCompatibleVersionAsync(service);
// Check that the service meets this App's minimum requirement
if (SupportsProtection(service) && isCompatibleVersion){
_service = service;
// Create a socket and connect to the target
_socket = new StreamSocket();
await _socket.ConnectAsync(
_service.ConnectionHostName,
_service.ConnectionServiceName,
SocketProtectionLevel
.BluetoothEncryptionAllowNullAuthentication);
// The socket is connected. At this point the App can wait for
// the user to take some action, for example, click a button to send a
// file to the device, which could invoke the Picker and then
// send the picked file. The transfer itself would use the
// Sockets API and not the Rfcomm API, and so is omitted here for
// brevity.
}
}
}
//this function is called every 14-seconds-ish, called within the "Update()" function.
async void DataSender(int LEDNumber) {
string strOfLED = LEDNumber.ToString();
var dataWriter = new DataWriter(_socket.OutputStream);
dataWriter.WriteString(strOfLED);
await dataWriter.StoreAsync();
await dataWriter.FlushAsync();
dataWriter.Close();
}
#endif
...
#if WINDOWS_UWP
private void OnApplicationQuit() {
_socket.Dispose();
}
#endif
您看到的错误消息表明构建过程失败,但它没有提供有关导致失败的原因的具体详细信息。您可以尝试以下一些方法来诊断和解决问题:
检查编译错误:确保代码中没有编译错误。 Unity 编辑器应在脚本文件中突出显示这些内容。另外,请检查 Unity 控制台是否有任何错误消息。
检查 UWP 功能:在构建 UWP 时,您需要确保在播放器设置中启用必要的功能。对于蓝牙通信,您需要启用“蓝牙”功能。您可以通过在 Unity 编辑器中转至“编辑”>“项目设置”>“播放器”>“发布设置”>“功能”来完成此操作。
检查 API 兼容性级别:确保您的 API 兼容性级别设置为“.NET 4.x”。您可以在“编辑”>“项目设置”>“播放器”>“其他设置”中检查此项。
检查不受支持的 API:Unity 对 UWP 的支持不包括所有 .NET API。某些 API,特别是那些与系统交互的 API,不受支持。如果您使用不受支持的 API,您可能需要找到不同的方法来完成您的任务。
检查 Unity 和 MRTK 版本:确保您使用的 Unity 版本与您正在使用的 MRTK 版本兼容。 Unity 和 MRTK 之间的不兼容可能会导致构建失败。
尝试构建一个最小项目:尝试构建一个仅包含蓝牙通信代码的最小项目。这可以帮助您确定问题是出在您的蓝牙代码还是项目的其他部分。
检查构建设置:确保您在构建设置中选择了正确的平台 (UWP) 和架构(x86、x64 或 ARM)。
检查 UWP 构建类型:在 UWP 构建设置中,确保您选择了正确的构建类型。对于 HoloLens,您应该选择“D3D 项目”。
希望这有帮助!
-$