32feet.net howto discover nearby bluetooth devices async in c#-Collection of common programming errors
A couple of caveats up front, I’m presuming you’re not dealing with HID devices here, they’re typically handled by the OS. I’ve also only just started using 32feet, and I’m using it to create connections to the serial port service on bluetooth barcode scanners, so there may be better ways for your needs but this may point you in the right direction to get started.
You need to pair the device, yes. If you’re using it in a WinForms app there’s actually form you can display which handles scanning for devices and lets you select one, like so:
bool PairDevice()
{
using (var discoverForm = new SelectBluetoothDeviceDialog())
{
if (discoverForm.ShowDialog(this) != DialogResult.OK)
{
// no device selected
return false;
}
BluetoothDeviceInfo deviceInfo = discoverForm.SelectedDevice;
if (!deviceInfo.Authenticated) // previously paired?
{
// TODO: show a dialog with a PIN/discover the device PIN
if (!BluetoothSecurity.PairDevice(deviceInfo.DeviceAddress, myPin))
{
// not previously paired and attempt to pair failed
return false;
}
}
// device should now be paired with the OS so make a connection to it asynchronously
var client = new BluetoothClient();
client.BeginConnect(deviceInfo.DeviceAddress, BluetoothService.SerialPort, this.BluetoothClientConnectCallback, client);
return true;
}
}
void BluetoothClientConnectCallback(IAsyncResult result)
{
var client = (BluetoothClient)result.State;
client.EndConnect();
// get the client's stream and do whatever reading/writing you want to do.
// if you want to maintain the connection then calls to Read() on the client's stream should block when awaiting data from the device
// when you're done reading/writing and want to close the connection or the device servers the connection control flow will resume here and you need to tidy up
client.Close();
}
By far and away the best way, if your devices are broadcasting that they’re available for a connection, is to set up a BluetoothListener
that will continuously listen for broadcasting devices and when one is found you’ll get a BluetoothClient
instance that you can use the same as the first time you paired:
void SetupListener()
{
var listener = new BluetoothListener(BluetoothService.SerialPort);
listener.Start();
listener.BeginAcceptBluetoothClient(this.BluetoothListenerAcceptClientCallback, listener);
}
void BluetoothListenerAcceptClientCallback(IAsyncResult result)
{
var listener = (BluetoothListener)result.State;
// continue listening for other broadcasting devices
listener.BeginAcceptBluetoothClient(this.BluetoothListenerAcceptClientCallback, listener);
// create a connection to the device that's just been found
BluetoothClient client = listener.EndAcceptBluetoothClient();
// the method we're in is already asynchronous and it's already connected to the client (via EndAcceptBluetoothClient) so there's no need to call BeginConnect
// TODO: perform your reading/writing as you did in the first code sample
client.Close();
}
Less appealing, but useful if your device isn’t broadcasting for connections, you can create a new BluetoothClient
and ask it to return all the devices it can find:
void ScanForBluetoothClients()
{
var client = new BluetoothClient();
BluetoothDeviceInfo[] availableDevices = client.DiscoverDevices(); // I've found this to be SLOW!
foreach (BluetoothDeviceInfo device in availableDevices)
{
if (!device.Authenticated)
{
continue;
}
var peerClient = new BluetoothClient();
peerClient.BeginConnect(deviceInfo.DeviceAddress, BluetoothService.SerialPort, this.BluetoothClientConnectCallback, peerClient);
}
}