Trouble Connecting To Known Bluetooth Device - c#

I am using 32Feet.Net's sample (list below) with using statements removed for brevity.
static void Main(string[] args)
{
BluetoothClient client = new BluetoothClient();
BluetoothDeviceInfo device = null;
foreach (var dev in client.DiscoverDevices())
{
if (dev.DeviceName.Contains("moto g(6)"))
{
device = dev;
break;
}
}
client.Connect(device.DeviceAddress, BluetoothService.SerialPort);
client.Close();
}
The line client.Connect(device.DeviceAddress, BluetoothService.SerialPort); blows up with this error {"The requested address is not valid in its context 601D914C50BF:0000110100001000800000805f9b34fb"}.
The only thing I altered in the sample was to find my smart phone, the moto g6. What am I missing?
Before putting a bounty on this question, I need to clarify that I am also looking for documentation or examples of having a desktop computer running Windows 10 be able to receive a file from iOS or Android and without having to use the built-in Bluetooth step by step in Windows 10. I would like to know what to do to correct the error.
I realize there is Command Line Bluetooth, but it would be nice to click a button in a gui and transfer a file using 32Feet.net.

Looks like the issue is because of services that are running on the device https://archive.codeplex.com/?p=32feet
Are you sure that device you are using has SerialPort profile running?
Also, Can you try the following code by using
private void BluetoothClientConnectCallback(IAsyncResult ar)
{
// Write your Call Back Code here
}
static void Main(string[] args)
{
BluetoothClient client = new BluetoothClient();
AllDevices = client.DiscoverDevicesInRange();
foreach (BluetoothDeviceInfo Device in AllDevices)
{
if (Device.DeviceName.Equals("moto g(6)"))
{
if (!client.Connected)
client = new BluetoothClient();
client.BeginConnect(Device.DeviceAddress, Device.InstalledServices[0], this.BluetoothClientConnectCallback, client);
break;
}
}
client.Close();
}
Also, you have to pair your device before connecting. Check here
BluetoothSecurity.PairRequest(Device.DeviceAddress,"123456");

Related

How to programmatically pair a bluetooth device

I recently bought a Lilypad Simblee BLE Board and I'd like to pair it programmatically to my computer (using the 32feet.NET library in C#).
I'm aware the "How to programmatically pair a bluetooth device" has already been asked on StackOverflow (here for example), however for some reason, all my attempts to pair the device programmatically have failed. Indeed, I successfully paired the device with the "Manage Bluetooth devices" window in Windows 10 Settings panel (Settings > Devices > Bluetooth).
Firstly, I don't know the pairing method (either legacy or SSP) to use with my device. Windows never asked me for a PIN or something, so I guess it's SSP, but I'm unsure.
I searched on Google how to do a SSP pairing request with 32feet.NET: I found this.
However, once it discovered my device (the device discovery works properly), the pairing request instantly fails.
My code:
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using System;
using System.Collections.Generic;
namespace HLK_Client
{
class HLKBoard
{
public event HLKBoardEventHandler HLKBoardConnectionComplete;
public delegate void HLKBoardEventHandler(object sender, HLKBoardEventArgs e);
private BluetoothClient _bluetoothClient;
private BluetoothComponent _bluetoothComponent;
private List<BluetoothDeviceInfo> _inRangeBluetoothDevices;
private BluetoothDeviceInfo _hlkBoardDevice;
private EventHandler<BluetoothWin32AuthenticationEventArgs> _bluetoothAuthenticatorHandler;
private BluetoothWin32Authentication _bluetoothAuthenticator;
public HLKBoard()
{
_bluetoothClient = new BluetoothClient();
_bluetoothComponent = new BluetoothComponent(_bluetoothClient);
_inRangeBluetoothDevices = new List<BluetoothDeviceInfo>();
_bluetoothAuthenticatorHandler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(_bluetoothAutenticator_handlePairingRequest);
_bluetoothAuthenticator = new BluetoothWin32Authentication(_bluetoothAuthenticatorHandler);
_bluetoothComponent.DiscoverDevicesProgress += _bluetoothComponent_DiscoverDevicesProgress;
_bluetoothComponent.DiscoverDevicesComplete += _bluetoothComponent_DiscoverDevicesComplete;
}
public void ConnectAsync()
{
_inRangeBluetoothDevices.Clear();
_hlkBoardDevice = null;
_bluetoothComponent.DiscoverDevicesAsync(255, true, true, true, false, null);
}
private void PairWithBoard()
{
Console.WriteLine("Pairing...");
bool pairResult = BluetoothSecurity.PairRequest(_hlkBoardDevice.DeviceAddress, null);
if (pairResult)
{
Console.WriteLine("Success");
}
else
{
Console.WriteLine("Fail"); // Instantly fails
}
}
private void _bluetoothComponent_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
{
_inRangeBluetoothDevices.AddRange(e.Devices);
}
private void _bluetoothComponent_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e)
{
for (int i = 0; i < _inRangeBluetoothDevices.Count; ++i)
{
if (_inRangeBluetoothDevices[i].DeviceName == "HLK")
{
_hlkBoardDevice = _inRangeBluetoothDevices[i];
PairWithBoard();
return;
}
}
HLKBoardConnectionComplete(this, new HLKBoardEventArgs(false, "Didn't found any \"HLK\" discoverable device"));
}
private void _bluetoothAutenticator_handlePairingRequest(object sender, BluetoothWin32AuthenticationEventArgs e)
{
e.Confirm = true; // Never reach this line
}
}
}
Why does the pairing request fail?
The answer to the question you linked has a plausible suggestion... did you read it?
Also you should look at this question as well.
32feet library is built around legacy pairing, so that you either need to know the pin of the device you are connecting to, or you supply it with a null to get a popup window to enter a pin.
It also says that the windows function used by 32feet is deprecated in newer versions of windows. If that's true, the reason it's failing instantly is because you've passed a null pin in your pairing request and for it to proceed windows needs to show a dialog which no longer exists.
What happens if you try to connect with the pin "0000" or "1234" ?
I'm looking at the source code of WindowsBluetoothSecurity.cs in 32feet.net and I see if a pairing request fails, it logs the error code to Debug.WriteLine, any chance you could post that error code here?
One good work around to this problem might be to import BluetoothAuthenticateDeviceEx and use that manually to complete the pairing request. If you don't want to do this manually, it looks like in the latest version of the 32feet source, there is actually a SSP pairing method that utilises this method but it's not public and it's not used anywhere so you'll need to access it via reflection:
typeof(BluetoothSecurity)
.GetMethod("PairRequest", BindingFlags.Static | BindingFlags.NonPublic)
.Invoke(null, new object[] { _hlkBoardDevice.DeviceAddress, BluetoothAuthenticationRequirements.MITMProtectionNotRequired });

Can't establish connection using StreamSocket (universal windows)

Im trying to follow this code sample from microsoft, who is a basic code for sending/receiving data over network from windows 10 computer/phone.
Im on VS2015, i have a phone on W10 and my computer also.
The problem is that my application seems to create packet and send one to establish the connection (i have seen this packet with wireshark), but i never received it on the server side.
Here is code to listen port from the actual internet connection available and wait for a connection :
public static async void StartServer()
{
try
{
StreamSocketListener listener = new StreamSocketListener();
//ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
//await listener.BindServiceNameAsync("5043", SocketProtectionLevel.PlainSocket, internetConnectionProfile.NetworkAdapter);
listener.ConnectionReceived += OnConnection;
await listener.BindServiceNameAsync("5043");
Debug.WriteLine("Server Started !");
}
catch (Exception)
{
Debug.WriteLine("Error StartServer Method !");
}
}
The method "OnConnection" is never reach cause the event "ConnectionReceived" is never called.
Here is the code to establish connection (the string ipDestination contain the internet ip address from my phone for example, that i get from checkip.dyndns.org) :
private static StreamSocket socket;
public static async void Connect(string ipDestination)
{
try
{
//Destination Ip address
HostName host = new HostName(ipDestination);
ConnectionProfile internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
socket = new StreamSocket();
socket.Control.KeepAlive = true;
await socket.ConnectAsync(host, "5043");
//EXCEPTION RAISE HERE after a moment "System.Runtime.InteropServices.COMException, cant join destination.
Debug.WriteLine("Connected !");
}
catch (Exception)
{
Debug.WriteLine("Erreur Connect Method !");
}
}
I think i should miss something but i dont know why and im block at this part since a long and can't continue my project...
I apologize for the bad english I try to make my best :)
Update from comments :
As Jay Zuo suggested, i have try to use local address on private
network and it works, i can establish connection, send and receive
data without problems... So the problem come when i use internet IP
address, and i still can't figure why...
As Kiewic suggested, i have simplify my code and commented the
precedent version.

Client Bluetooth connection with 32feet.NET fails all the time

I'm trying to get a Bluetooth socket connection up and running but for some reason my client will not connect.
More precisely I get an exception when I try to connect to the stream:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
All examples I found online didn't really solve my problem and I'm currently not really sure where the problem comes from.
The scanning and pairing works fine - I see that the Bluetooth device in question gets successfully paired.
I try to connect via first setting the Client and then call connect
Client Bluetooth name, address and pin are known:
public bool SetClient(String clientName, String btAddress, String pin)
{
bool retVal = false;
m_remoteBluetoothClient = new BluetoothDeviceInfo(BluetoothAddress.Parse(btAddress));
m_localBluetoothClient.SetPin(pin);
if (m_remoteBluetoothClient.Authenticated)
{
//m_localBluetoothClient.Authenticate = true;
retVal = true;
}
else
{
if (BluetoothSecurity.PairRequest(m_remoteBluetoothClient.DeviceAddress, pin))
{
retVal = true;
}
}
return retVal;
}
Then an async connect:
private void ClientConnectThread()
{
m_localBluetoothClient.BeginConnect(m_remoteBluetoothClient.DeviceAddress, BluetoothService.SerialPort, Connect, m_localBluetoothClient);
}
private void Connect(IAsyncResult result)
{
if (result.IsCompleted)
{
m_localBluetoothClient.EndConnect(result);
mBtStream = m_localBluetoothClient.GetStream();
}
}
The locals m_localBluetoothEndpoint and m_localBluetoothClient are created like this although the Endpoint is more or less new (before I used BluetoothCLient without parameter):
m_localBluetoothEndpoint = new BluetoothEndPoint(BluetoothRadio.PrimaryRadio.LocalAddress, BluetoothService.SerialPort);
m_localBluetoothClient = new BluetoothClient(m_localBluetoothEndpoint);
I also tried to work with a Listener in case the remote devices wants to connect but the callback gets never called:
public void SetupListener()
{
var listener = new BluetoothListener(BluetoothService.SerialPort);
listener.Start();
listener.BeginAcceptBluetoothClient(this.BluetoothListenerAcceptClientCallbackTwo, listener);
}
Can anyone tell me if there is anything wrong with my connection approach above and how I can figure out why I get the exception mentioned above?
The exception gets thrown here:
m_localBluetoothClient.EndConnect(result);
A thing I also don't understand is that the SupportedServices call to the remoteCLient returned 0 guids - so the device did not list any Bluetooth services.
m_remoteBluetoothClient.InstalledServices()
Thank you

Pair bluetooth devices to a computer with 32feet .NET Bluetooth library

If you want to know how to use 32feet.NET library to communicate with bluetooth devices, read the solution
I am currently trying to communicate via bluetooth between a computer and a self-built .NET Gadgeteer prototype.
The Gadgeteer prototype consists of the mainboard, a power supply and a bluetooth module. The module is in discoverable mode.
On the computer a custom bluetooth program based on 32feet .NET Bluetooth is running. The program detects all bluetooth devices in range and tries to pair with them. However, this is not done automatically at the moment, I have to enter a pairing code for the device.
How can I pair devices without entering the pairing code?
Devices are found, the problem is the pairing part. I experimented a lot, but didn't find a solution...
foreach (BluetoothDeviceInfo device in this.deviceList)
{
try
{
//BluetoothClient client = new BluetoothClient(this.CreateNewEndpoint(localAddress));
//BluetoothEndPoint ep = this.CreateNewEndpoint(device.DeviceAddress);
EventHandler<BluetoothWin32AuthenticationEventArgs> handler = new EventHandler<BluetoothWin32AuthenticationEventArgs>(HandleRequests);
BluetoothWin32Authentication auth = new BluetoothWin32Authentication(handler);
BluetoothSecurity.PairRequest(device.DeviceAddress, null);
}
}
This code block initiates the pairing and it works, but Windows is asking me to enter the pairing code for the device. I read about the BluetoothWin32Authentication to prevent this case but I don't get it right.
private void HandleRequests(object that, BluetoothWin32AuthenticationEventArgs e)
{
e.Confirm = true;
}
This is the code of the event handler (http://32feet.codeplex.com/wikipage?title=BluetoothWin32Authentication)
If you simply want to allow the pairing to go ahead when to SSP devices are connecting then handling the callback and setting e.Confirm=True will be enough -- but that is a little insecure...
I am confused -.- The goal is that the application and the gadgeteer module can send data in both directions without any user interference.
Is it true that I can't pair devices automatically without user interaction?
Is it true that if two device were already paired they can exchange data without user interaction?
I figured out how to solve my problems and my knowledge about Bluetooth connections is a bit bigger now. If someone else has problems with that, I provide my solution. The code examples represent the C# implementation of a bluetooth controller with the 32feet Bluetooth library.
Scanning
This means that devices in range are detected. My code:
// mac is mac address of local bluetooth device
BluetoothEndPoint localEndpoint = new BluetoothEndPoint(mac, BluetoothService.SerialPort);
// client is used to manage connections
BluetoothClient localClient = new BluetoothClient(localEndpoint);
// component is used to manage device discovery
BluetoothComponent localComponent = new BluetoothComponent(localClient);
// async methods, can be done synchronously too
localComponent.DiscoverDevicesAsync(255, true, true, true, true, null);
localComponent.DiscoverDevicesProgress += new EventHandler<DiscoverDevicesEventArgs>(component_DiscoverDevicesProgress);
localComponent.DiscoverDevicesComplete += new EventHandler<DiscoverDevicesEventArgs>(component_DiscoverDevicesComplete);
private void component_DiscoverDevicesProgress(object sender, DiscoverDevicesEventArgs e)
{
// log and save all found devices
for (int i = 0; i < e.Devices.Length; i++)
{
if (e.Devices[i].Remembered)
{
Print(e.Devices[i].DeviceName + " (" + e.Devices[i].DeviceAddress + "): Device is known");
}
else
{
Print(e.Devices[i].DeviceName + " (" + e.Devices[i].DeviceAddress + "): Device is unknown");
}
this.deviceList.Add(e.Devices[i]);
}
}
private void component_DiscoverDevicesComplete(object sender, DiscoverDevicesEventArgs e)
{
// log some stuff
}
Pairing
This means that devices get coupled with the local bluetooth device. This needs to be done once by entering a code of both sides. Can be done via code so that the user doesn't even notice that a device was added. My code for this purpose:
// get a list of all paired devices
BluetoothDeviceInfo[] paired = localClient.DiscoverDevices(255, false, true, false, false);
// check every discovered device if it is already paired
foreach (BluetoothDeviceInfo device in this.deviceList)
{
bool isPaired = false;
for (int i = 0; i < paired.Length; i++)
{
if (device.Equals(paired[i]))
{
isPaired = true;
break;
}
}
// if the device is not paired, pair it!
if (!isPaired)
{
// replace DEVICE_PIN here, synchronous method, but fast
isPaired = BluetoothSecurity.PairRequest(device.DeviceAddress, DEVICE_PIN);
if (isPaired)
{
// now it is paired
}
else
{
// pairing failed
}
}
}
Connecting
This means establishing a connection and exchanging of data. Again some code:
// check if device is paired
if (device.Authenticated)
{
// set pin of device to connect with
localClient.SetPin(DEVICE_PIN);
// async connection method
localClient.BeginConnect(device.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), device);
}
// callback
private void Connect(IAsyncResult result)
{
if (result.IsCompleted)
{
// client is connected now :)
}
}
If you keep the order scan, pair, connect, everything should work fine. To send or receive data, use the GetStream() method of the BluetoothClient. It provides a network stream that can be manipulated.
Receiving a connection
If you want another device to connect with your device you need to listen to incoming connection requests. This only works if the device have already been paired before. My code:
BluetoothListener l = new BluetoothListener(LOCAL_MAC, BluetoothService.SerialPort);
l.Start(10);
l.BeginAcceptBluetoothClient(new AsyncCallback(AcceptConnection), l);
void AcceptConnection(IAsyncResult result){
if (result.IsCompleted){
BluetoothClient remoteDevice = ((BluetoothListener)result.AsyncState).EndAcceptBluetoothClient(result);
}
}
Replace LOCAL_MAC with a valid BluetoothAddress (e.g. by using BluetoothAddress.Parse();). After the devices are connected they can exchange messages via the underlying stream. If the connection does not work there might be authentication issues, so try setting the local device pin in the listener (l.SetPin(LOCAL_MAC, MY_PASSWORD);

COM port disappears when unplugging USB

I am prototyping a sort of Arduino-based docking station for a tablet, using the USB port as connector. This means I need to support to ability to plug/unplug the USB connector while the application on the tablet is running.
The tablet runs a c# application (.net 4.5 on Win7 64 bit) in which I am connecting to the Arduino Uno. When the application is launched I loop all available COM ports using:
var ports = SerialPort.GetPortNames(); // -> [COM3,COM4,COM8]
foreach (var port in ports)
{
var serial = new SerialPort(portname, baudRate);
//attempt handshake and connect to right port
}
This work fine, but if I unplug and replug the USB cable and reattempt to reconnect to the Arduino (while the application is still running), the Arduino port (COM8) is no longer listed in:
SerialPort.GetPortNames(); // -> [COM3,COM4] and no COM8
Even restarting the application (with the Arduino replugged) will result in only [COM3,COM4] being listed.
The only way to get it back to work is to unplug and replug the Arduino while the application is not running.
What confuses me is the fact that when I plug in the Arduino Uno after starting the application, the SerialClass does recognize the newly added port and allows me to connect.
The problem only occurs when I unplug and replug the device when the application is running. It seems that despite the ability to reset the COM port (in code or manually in device manager), the SerialClass (and native Win32_SerialPort - I checked this too) do not recognize this, unless I restart the application
What could be the reason for this? And how can I make sure that my application can reconnect to that port? Are there any alternatives to using the SerialPort to handle the USB connector?
I found a solution that can handle plugging and unplugging a SerialPort.
First of all, it requires the use the SafeSerialPort, which allows you to dispose the serial port properly.
SafeSerialPort serialPort;
private void Connect()
{
string portname = "COM8";
serialPort = new SafeSerialPort(portname, 9600);
serialPort.DataReceived += port_DataReceived;
serialPort.Open();
}
Second, you need to use LibUsbDotNet to detect whether a USB device is connected or disconnected. This will allow you to determine whether to connect to the device or reset the COM port.
public UsbDevice MyUsbDevice;
//Find your vendor id etc by listing all available USB devices
public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001);
public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
{
if (e.Object.ToString().Split('\n')[1].Contains("0x2341"))
{
if (e.EventType == EventType.DeviceArrival)
{
Connect();
}
else if(e.EventType == EventType.DeviceRemoveComplete)
{
ResetConnection();
}
}
}
Finally, disposing the SerialPort will makes sure it is registered by Windows in HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM, meaning that SerialPort.GetPortNames() can re-detect the port.
private void ResetConnection()
{
try
{
//Send any data to cause an IOException
serialPort.Write("Any value");
}
catch (IOException ex)
{
//Dispose the SafeSerialPort
serialPort.Dispose();
serialPort.Close();
}
}
After this process, you can simply reconnect to the COM port when the USB device is connected without the need to restart the application.
Full code:
using LibUsbDotNet;
using LibUsbDotNet.DeviceNotify;
using LibUsbDotNet.Info;
using LibUsbDotNet.Main;
SafeSerialPort serialPort;
public SerialPortTest()
{
Connect();
UsbDeviceNotifier.OnDeviceNotify += OnDeviceNotifyEvent;
}
private void Connect()
{
string portname = "COM8";
serialPort = new SafeSerialPort(portname, 9600);
serialPort.DataReceived += port_DataReceived;
serialPort.Open();
}
private void ResetConnection()
{
try
{
serialPort.Write("Any value");
}
catch (IOException ex)
{
serialPort.Dispose();
serialPort.Close();
}
}
void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
Console.WriteLine(serialPort.ReadExisting());
}
public UsbDevice MyUsbDevice;
//Vendor ID etc can be found through enumerating the USB devices
public UsbDeviceFinder MyUsbFinder = new UsbDeviceFinder(0x2341, 0x0001);
public IDeviceNotifier UsbDeviceNotifier = DeviceNotifier.OpenDeviceNotifier();
private void OnDeviceNotifyEvent(object sender, DeviceNotifyEventArgs e)
{
//if this is your usb device, in my case an Arduino
if (e.Object.ToString().Split('\n')[1].Contains("0x2341"))
{
if (e.EventType == EventType.DeviceArrival)
{
Connect();
}
else
{
ResetConnection();
}
}
}
So I believe this is happening because your program is caching the address of the USB the first time it is plugged in.
When someone plugs in a device, the hub detects voltage on either D+
or D- and signals the insertion to the host via this interrupt
endpoint. When the host polls this interrupt endpoint, it learns that
the new device is present. It then instructs the hub (via the default
control pipe) to reset the port where the new device was plugged in.
***This reset makes the new device assume address 0, and the host can
then interact with it directly; this interaction will result in the
host assigning a new (non-zero) address to the device.
Your best bet is to research how to programically flush the address cache of USB devices.
Reference:http://en.wikipedia.org/wiki/USB_hub

Categories