Hello everyone.

We have decided to phase out the Mixed Reality Forums over the next few months in favor of other ways to connect with us.

The first way we want to connect with you is our mixed reality developer program, which you can sign up for at https://aka.ms/IWantMR.

The plan between now and the beginning of May is to clean up old, unanswered questions that are no longer relevant. The forums will remain open and usable.

On May 1st we will be locking the forums to new posts and replies. They will remain available for another three months for the purposes of searching them, and then they will be closed altogether on August 1st.

So, where does that leave our awesome community to ask questions? Well, there are a few places we want to engage with you. For technical questions, please use Stack Overflow, and tag your questions using either hololens or windows-mixed-reality. If you want to join in discussions, please do so in the HoloDevelopers Slack, which you can join by going to https://aka.ms/holodevelopers. And always feel free to hit us up on Twitter @MxdRealityDev.

HoloLens Arduino Bluetooth

Hi guys,

I want to connect an Arduino using a BlueSMiRF Bluetooth module to my HoloLens.

For that puspose I found an UWP example:
https://developer.microsoft.com/en-us/windows/iot/samples/btserial
Unfortunately, it is not working, not even on the PC. The returned RfcommDeviceService is always null.

Any idea how to fix this is greatly appreciated.

jschnettker 

Answers

  • I started a Unity project, to test the logic behind my app: just a sphere, and I want to manipulate it's width via Bluetooth. This example gave me another lead for finding Bluetooth devices:
    https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing
    In scenario two, it this sample my RN41 under Bluetooth.
    Also, my custom GetDevicesAsync() function retrieves three devices, that have the same name, I gave the Bluetooth module. But it retrieves none of them, when I use a AQS, that lists all serial port rfcomm services. Therefore, I'm almost sure, that one of these devices has any type of rfcomm service, no matter, which. According to this, I implementet error handling, that when the connection to one device fails (because it has no rfcomm service), it continues with the next one.
    But it seems, that this is not enough, every time I run it, I get the following output:

    14 devices found

    Trying to cennect with Bluetooth module

    Executing TryConnectAsync

    Selected device is not null.

    Exception thrown: 'System.Exception' in mscorlib.ni.dll
    Couldn't return RfcommService

    False

    Didn't break

    Exception thrown: 'System.InvalidOperationException' in mscorlib.ni.dll
    The program '[5608] serialinput.exe' has exited with code -1073741189 (0xc000027b).

    How could I handle this error, to make it continue trying to connect to other devices? This is the code I'm currently using:

  • `using UnityEngine;
    using System;
    using System.Collections;
    using System.Collections.Generic;

    if UNITY_EDITOR

    using System.IO.Ports;

    elif NETFX_CORE

    using Windows.Devices.Enumeration;
    using System.Threading.Tasks;
    using Windows.Devices.Bluetooth;
    using Windows.Devices.Bluetooth.Rfcomm;
    using Windows.Networking.Sockets;
    using Windows.Storage.Streams;
    using Windows.Foundation;
    using System.Collections.ObjectModel;

    endif

    public class SizeManipulator : MonoBehaviour
    {

    if UNITY_EDITOR

    public SerialPort serialPort = new SerialPort("COM9", 9600, Parity.None, 8);
    

    elif NETFX_CORE

    private DeviceInformationCollection deviceInformationCollection;
    private DeviceInformation deviceInformation;
    private string DeviceEnumerationAqsString;
    private RfcommDeviceService deviceService;
    private StreamSocket streamSocket;
    private BluetoothDevice BlueSMiRF;
    private IReadOnlyList<RfcommDeviceService> RfcommDeviceServices;
    public DeviceWatcher deviceWatcher;
    private TypedEventHandler<DeviceWatcher, DeviceInformation> handlerAdded = null;
    private TypedEventHandler<DeviceWatcher, DeviceInformationUpdate> handlerUpdated = null;
    private TypedEventHandler<DeviceWatcher, DeviceInformationUpdate> handlerRemoved = null;
    private TypedEventHandler<DeviceWatcher, System.Object> handlerEnumCompleted = null;
    private TypedEventHandler<DeviceWatcher, System.Object> handlerStopped = null;
    bool connected=false,connecting=false,continuing=false;
    public ObservableCollection<DeviceInformation> resultCollection
    {
        get;
        private set;
    }
    public ObservableCollection<DeviceInformation> connectionCollection
    {
        get;
        private set;
    }
    

    endif

    public static string strIn;
    private string inputString;
    private float size;
    Vector3 startScale, scaleManipulation;
    void Start()
    {
    

    if UNITY_EDITOR

        OpenConnection();
    

    elif NETFX_CORE

        streamSocket = new StreamSocket();
        resultCollection = new ObservableCollection<DeviceInformation>();
        connectionCollection = new ObservableCollection<DeviceInformation>();
        StartWatcher();
    

    endif

        startScale = new Vector3(transform.localScale.x, transform.localScale.y, transform.localScale.z);
        scaleManipulation = new Vector3(0f, 0f, 0f);
    }
    void Update()
    {
        inputString = string.Empty;
    

    if UNITY_EDITOR

        inputString = serialPort.ReadLine();
    

    elif NETFX_CORE

        //GetDevicesAsync();
        try
        {
            if(!connected&&!connecting)
            {
                connecting=true;
                connectionCollection=resultCollection;
                Debug.Log(connectionCollection.Count+" devices found");
                AsyncConnectionHandler();
            }
        }
        catch(Exception)
        {
            Debug.Log("Error in Update Function");
            return;
        }
    

    endif

        if (inputString != string.Empty)
        {
            Debug.Log(inputString);
        }
        inputString += ".0";
        scaleManipulation.x = (((float.Parse(inputString)) / 1023) - 0.5f) * startScale.x;
        transform.localScale = startScale + scaleManipulation;
    }
    

    if UNITY_EDITOR

    public void OpenConnection()
    {
        if (serialPort != null)
        {
            if (serialPort.IsOpen)
            {
                serialPort.Close();
                Debug.Log("Closing port, because it was already open!");
            }
            else
            {
                serialPort.Open();
                serialPort.ReadTimeout = 50;
                Debug.Log("Port Opened!");
            }
        }
        else
        {
            if (serialPort.IsOpen)
            {
                print("Port is already open");
            }
            else
            {
                print("Port == null");
            }
        }
    }
    

    elif NETFX_CORE

    private void StartWatcher()
    {
        resultCollection.Clear();
        DeviceEnumerationAqsString=string.Empty;    
        deviceWatcher=DeviceInformation.CreateWatcher();
        handlerAdded = new TypedEventHandler<DeviceWatcher, DeviceInformation>((watcher, deviceInfo) =>
        {
            {
                resultCollection.Add(deviceInfo);
            };
        });
        deviceWatcher.Added += handlerAdded;
        handlerUpdated = new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>((watcher, deviceInfoUpdate) =>
        {
            {
                foreach (DeviceInformation deviceInfo in resultCollection)
                {
                    if (deviceInfo.Id == deviceInfoUpdate.Id)
                    {
                        deviceInfo.Update(deviceInfoUpdate);
                        break;
                    }
                }
            };
        });`
    
  • ` deviceWatcher.Updated += handlerUpdated;
    handlerRemoved = new TypedEventHandler<DeviceWatcher, DeviceInformationUpdate>((watcher, deviceInfoUpdate) =>
    {

            foreach (DeviceInformation deviceInfo in resultCollection)
            {
                if (deviceInfo.Id == deviceInfoUpdate.Id)
                {
                    resultCollection.Remove(deviceInfo);
                    break;
                }
            }
        });
        deviceWatcher.Removed += handlerRemoved;
        handlerEnumCompleted = new TypedEventHandler<DeviceWatcher, System.Object>((watcher, obj) =>
        {
        });
        deviceWatcher.EnumerationCompleted += handlerEnumCompleted;
        handlerStopped = new TypedEventHandler<DeviceWatcher, System.Object>((watcher, obj) =>
        {
        });
        deviceWatcher.Stopped += handlerStopped;
        deviceWatcher.Start();
    }
    private async void GetDevicesAsync()
    {
        DeviceEnumerationAqsString=RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort);
        deviceInformationCollection=await DeviceInformation.FindAllAsync(DeviceEnumerationAqsString);
        foreach(DeviceInformation device in deviceInformationCollection)
        {   
            Debug.Log(device.Name);
            if (device.Name=="RN41-Jonas-CBEC")
            {
                Debug.Log("Device RN41-Jonas-CBEC found");
                try
                {
                    BlueSMiRF=await BluetoothDevice.FromIdAsync(device.Id);
                }
                catch(Exception)
                {
                    Debug.Log("BlueSMiRF is no Bluetooth device");
                }
                Debug.Log(BlueSMiRF.BluetoothAddress);
                connected=await TryConnectAsync(device);
            }
        }
    }
    private async Task<bool> TryConnectAsync(DeviceInformation selectedDevice)
    {
        Debug.Log("Executing TryConnectAsync");
        if (selectedDevice!=null)
        {
            Debug.Log("Selected device is not null.");
            try
            {
                deviceService = await RfcommDeviceService.FromIdAsync(selectedDevice.Id);
                Debug.Log("returned device service");
            }
            catch(Exception)
            {
                Debug.Log("Couldn't return RfcommService");
                return false;
            }
            if (deviceService != null)
            {
                Debug.Log("Try to connect to device");
                try
                {
                    await streamSocket.ConnectAsync(deviceService.ConnectionHostName, deviceService.ConnectionServiceName);
                    Debug.Log("Socket connected");
                    return true;
                }
                catch(Exception)
                {
                    Debug.Log("Couldn't connect streamSocket");
                    return false;
                }
            }
            else
            {
                Debug.Log("Didn't find the Rfcomm service.");
                return false;
            }
        }
        else
        {
            Debug.Log("Didn't find device");
            return false;
        }
    }
    private void StopWatcher()
    {
        if (null != deviceWatcher)
        {
            deviceWatcher.Added -= handlerAdded;
            deviceWatcher.Updated -= handlerUpdated;
            deviceWatcher.Removed -= handlerRemoved;
            deviceWatcher.EnumerationCompleted -= handlerEnumCompleted;
            if (DeviceWatcherStatus.Started == deviceWatcher.Status ||
                DeviceWatcherStatus.EnumerationCompleted == deviceWatcher.Status)
            {
                deviceWatcher.Stop();
            }
        }
    }
    private async void AsyncConnectionHandler()
    {
        foreach(DeviceInformation device in connectionCollection)
        {
            try
            {
                if(continuing)
                {
                    Debug.Log("Continuing");
                    continuing=false;
                }
                if(device.Name=="RN41-Jonas-CBEC")
                {
                    Debug.Log("Trying to cennect with Bluetooth module");
                    connected=await TryConnectAsync(device);
                    Debug.Log(connected);
                    if(connected)
                    {
                        break;
                    }
                    Debug.Log("Didn't break");
                    continuing=true;
                }
            }
            catch(Exception)
            {
                Debug.Log("Exception thrown at device namecheck.");
                continue;
            }
        }
        connecting=false;
    }
    

    endif

    void OnApplicationQuit()
    {
    

    if UNITY_EDITOR

        serialPort.Close();
        Debug.Log("Port closed!");
    

    elif NETFX_CORE

    StopWatcher();
    

    endif

    }
    

    }`

  • I have no idea, how to catch this errors or how to continue.
    The code I use is partially form the following examples:
    https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing
    https://github.com/ms-iot/samples/tree/develop/BTSerial
    https://code.msdn.microsoft.com/windowsapps/Bluetooth-Rfcomm-Chat-afcee559

    Any help about fixing this is greatly appreciated.

    Thank you in advance,

    jschnettker

  • Hi...in my case I have been able to get this to work when my Build Platform is PC Standalone, because I am able to use the System.IO.Ports namespace and it is easy to just read the data that is sent to the SerialPort.Unfortunately, the WSA platform does not allow the use of the System.IO.Ports namespace (among many other limitations).How do I get this string of data to be sent to the game when the target platform is WSA?

  • You have to use RfcommDeviceService, as this is the only way to open a serial port on the Hololens.
    The most important trick is to make sure, that your app has the user consent to open the Bluetooth device. This can be the user consents dialog (I had some problems there too: https://forums.hololens.com/discussion/comment/19578#Comment_19578 )
    or do it manually every time you deploy your app in the "Settings->Privacy->Other devices", where you have to enable your app.

  • I'm not sure if you are having exactly the same problem as I was, but I found that for some reason the RfCommDeviceService would always return null when it was executed on a thread other than the UI. I managed to fix this in Unity by invoking the method where I have "RfcommDeviceService.FromIdAsync(device.Id)" on the UI thread.

    UnityEngine.WSA.Application.InvokeOnUIThread(GetService, true);
    
    private async void GetService()
        {
            _service = await RfcommDeviceService.FromIdAsync(device.Id);
        }
    
Sign In or Register to comment.