The DFRobot Bluno Boards are a series of Arduino-compatible development boards — such as Bluno Uno and Bluno Nano — developed by DFRobot with an integrated Bluetooth 4.0 (BLE) module based on the TI CC2540 chip. They add wireless communication, smartphone control, and even wireless programming to Arduino projects. The boards are compatible with Arduino Nano, Arduino UNO, Arduino Mega 1280, and Arduino Mega 2560.
The boards work well with Android and iOS applications because DFRobot provides mobile SDKs for those platforms. On Windows, however, the boards cannot be used with applications that rely on the standard Microsoft Bluetooth LE API. Connecting, reading, and writing attributes all work, but characteristic change notifications never arrive. The board firmware is missing the client configuration descriptor on its notifiable characteristic, and the Windows WinRT GATT API requires one.
The Bluetooth Framework solves this. With the ForceNotifications property set to
true, an application can subscribe to the characteristic and receive change notifications as expected.
How it works
To test the feature, use the GattClient sample application from the Bluetooth Framework
package. Start the sample, click Discover, and select the board in the found devices list. Enable the Force indications
checkbox and click Connect. The board is paired during connection using the default PIN, which is 0000. If the board
uses a different PIN, change it in the OnPinRequest event handler.
When the connection is established — the Connected event fires with 0x00000000 in the Error
parameter — the application can start working with the board. After reading services and characteristics, select the notifiable one and
click Subscribe. The application then receives characteristic change notifications.
To work with Bluno boards in code, use the wclGattClient class. The ForceNotifications property must be set to
true to enable characteristic change notifications from Bluno boards, or from any other GATT-enabled device that does not have
the client configuration descriptor. Because the board is paired during connection, the application must handle the OnPinRequest
event of the wclBluetoothManager class. The default PIN is 0000.
Once the connection is established, the application starts receiving notifications by calling the Subscribe method of the
wclGattClient class. It must not call WriteClientConfiguration in this case, because the boards do not have the
client configuration descriptor configured for the characteristic.
Code example
The snippets below are taken from the GattClient sample. They show the three essential steps: handling the PIN request,
setting ForceNotifications from the Force indications checkbox, and calling Subscribe after discovering
characteristics.
procedure TfmMain.wclBluetoothManagerPinRequest(Sender: TObject;
const Radio: TwclBluetoothRadio; const Address: Int64;
out Pin: String);
begin
Pin := '0000';
end;
procedure TfmMain.btConnectClick(Sender: TObject);
var
Res: Integer;
Item: TListItem;
begin
Item := lvDevices.Selected;
wclGattClient.ForceNotifications := cbForceIndications.Checked;
Res := wclGattClient.Connect(TwclBluetoothRadio(Item.Data));
// Check Res for errors...
end;
procedure TfmMain.btSubscribeClick(Sender: TObject);
var
Characteristic: TwclGattCharacteristic;
begin
// FCharacteristics is populated after reading characteristics
Characteristic := FCharacteristics[lvCharacteristics.Selected.Index];
wclGattClient.Subscribe(Characteristic);
end;
void __fastcall TfmMain::wclBluetoothManagerPinRequest(
TObject *Sender, const TwclBluetoothRadio *Radio,
const __int64 Address, String& Pin)
{
Pin = "0000";
}
void __fastcall TfmMain::btConnectClick(TObject *Sender)
{
TListItem* Item = lvDevices->Selected;
wclGattClient->ForceNotifications =
cbForceIndications->Checked;
int Res = wclGattClient->Connect(
(TwclBluetoothRadio*)Item->Data);
// Check Res for errors...
}
void __fastcall TfmMain::btSubscribeClick(TObject *Sender)
{
TwclGattCharacteristic Characteristic =
FCharacteristics[lvCharacteristics->Selected->Index];
wclGattClient->Subscribe(Characteristic);
}
void Manager_OnPinRequest(Object Sender,
wclBluetoothRadio Radio, Int64 Address, out String Pin)
{
Pin = "0000";
}
private void btConnect_Click(Object sender, EventArgs e)
{
ListViewItem Item = lvDevices.SelectedItems[0];
Client.ForceNotifications = cbForceIndications.Checked;
Int32 Res = Client.Connect((wclBluetoothRadio)Item.Tag);
// Check Res for errors...
}
private void btSubscribe_Click(Object sender, EventArgs e)
{
wclGattCharacteristic Characteristic =
FCharacteristics[
lvCharacteristics.SelectedItems[0].Index];
Client.Subscribe(Characteristic);
}
Private Sub Manager_OnPinRequest(ByVal Sender As Object,
ByVal Radio As wclBluetooth.wclBluetoothRadio,
ByVal Address As Long, ByRef Pin As String)
Handles Manager.OnPinRequest
Pin = "0000"
End Sub
Private Sub btConnect_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles btConnect.Click
Dim Item As ListViewItem = lvDevices.SelectedItems(0)
Client.ForceNotifications = cbForceIndications.Checked
Dim Res As Int32 = Client.Connect(
CType(Item.Tag, wclBluetoothRadio))
' Check Res for errors...
End Sub
Private Sub btSubscribe_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles btSubscribe.Click
Dim Characteristic As wclGattCharacteristic =
FCharacteristics(
lvCharacteristics.SelectedItems(0).Index)
Client.Subscribe(Characteristic)
End Sub
void CGattClientDlg::wclBluetoothManagerPinRequest(
void* Sender, CwclBluetoothRadio* const Radio,
const __int64 Address, tstring& Pin)
{
Pin = _T("0000");
}
// Connect button click
void CGattClientDlg::OnBnClickedButtonConnect()
{
int Item = lvDevices.GetNextSelectedItem(Pos);
wclGattClient.ForceNotifications =
(cbForceIndications.GetCheck() != FALSE);
int Res = wclGattClient.Connect(
(CwclBluetoothRadio*)lvDevices.GetItemData(Item));
// Check Res for errors...
}
void CGattClientDlg::OnBnClickedButtonSubscribe()
{
wclGattCharacteristics::iterator it =
FCharacteristics.begin();
std::advance(it,
lvCharacteristics.GetNextSelectedItem(Pos));
wclGattCharacteristic Characteristic = (*it);
wclGattClient.Subscribe(Characteristic);
}
Frequently asked questions
- Why can't I receive notifications from DFRobot Bluno boards on Windows?
- The boards are missing a client configuration descriptor on their notifiable characteristic, and the Windows WinRT GATT API requires one. The Bluetooth Framework bypasses this bug.
- How to enable notifications on Bluno boards with Bluetooth Framework?
- Set the
wclGattClient.ForceNotificationsproperty totruebefore subscribing. The framework then handles the missing descriptor and lets the application receive characteristic change notifications. - What is the default PIN for pairing with Bluno boards?
- The default PIN is
0000. The application must handle theOnPinRequestevent ofwclBluetoothManagerand provide this PIN during pairing.