Sergiy Baydachnyy

Blog about technologies

Archive for May 2017

UWP: Working with Bluetooth (part 5: Bluetooth RFCOMM)

leave a comment »

Windows 10 API supports not just Bluetooth Low Energy devices, but allows you to utilize RFCOMM protocol as the most widespread since Bluetooth invention. Even if your module doesn’t support BLE, you always can use RFCOMM. As in the case of BLE Windows 10 allows you to publish RFCOMM services or work with other services as a client.

I decided to implement client only, and for a server I used a cheap Bluetooth module HC-06. It’s possible to buy the module for couple dollars and you can find lots of videos and examples about how to connect it to Arduino board. But you can use any available Bluetooth module. Just in case you can find a schema below:

clip_image002

My module wasn’t on a plate with a voltage regulator. So, I decided to add a voltage divider for TX->RX connection, because Arduino generate 5 volts there rather than 3.3 volts. If you have a module like on the schema above (with the regulator), you still can use the divider, and it will not break your circuit.

To communicate with the module from Arduino, you can simply use the serial port. So, I connected TX and RX pins on Arduino to RX and TX pins on the module. Additionally, I connected 3.3V and GRN on Arduino to VCC and GRN on the module.

I setup my module to use 115200 speed and changed the name of the module to rfcommhc06. You can do it connection the module to your computer using USB to Serial adapter and execute some AT commands (AT+NAMErfcommhc06 and AT+BAUD8).

Finally, I could implement a very simple code for Arduino:

void setup()
{
   Serial.begin(115200);
   pinMode(13,OUTPUT);
}
byte blue;
void loop()
{
   if(Serial.available())
   {
      blue=Serial.read();
      Serial.write(blue);
      if (blue==3)
      {
         digitalWrite(13,HIGH);
      }
      else if(blue==2)
      {
         digitalWrite(13,LOW);
      }
      Serial.write(blue);
   }
}

This code read data from serial port using infinity loop and one there is 3, it sends high voltage to pin number 13. In the case if 2 is in the stream, it sends low voltage to pin 13. Because pin 13 are connected with a LED on Arduino Uno boards, the led will switch status between on and off depends on input data. At the end of each iteration, I send all incoming data back.

If you finish your circuit and deploy the code successfully, it’s time to start developing a client for Windows 10.

The first part of our code will look similar to BLE example. We have to start watcher and declare handlers for Added and Removed events:

DeviceWatcher deviceWatcher;
DataWriter tx;
DataReader rx;
StreamSocket stream;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
   deviceWatcher = DeviceInformation.CreateWatcher(
      "System.ItemNameDisplay:~~\"rfcommhc\"",
      null,
      DeviceInformationKind.AssociationEndpoint);
   deviceWatcher.Added += DeviceWatcher_Added;
   deviceWatcher.Removed += DeviceWatcher_Removed;
   deviceWatcher.Start();
   base.OnNavigatedTo(e);
}

The DeviceWatcher_Added method will looks different compare to BLE example.

private async void DeviceWatcher_Added(DeviceWatcher sender,
   DeviceInformation args)
{
   var device = await BluetoothDevice.FromIdAsync(args.Id);
   var services = await device.GetRfcommServicesAsync();
   if (services.Services.Count>0)
   {
      var service = services.Services[0];
      stream = new StreamSocket();
      await stream.ConnectAsync(service.ConnectionHostName,
      service.ConnectionServiceName);
      rx = new DataReader(stream.InputStream);
      tx = new DataWriter(stream.OutputStream);
      await this.Dispatcher.RunAsync(
         Windows.UI.Core.CoreDispatcherPriority.Normal,
         () => { switchLed.IsEnabled = true; });
      deviceWatcher.Stop();
   }
}

First, we use the BluetoothDevice class rather than BluetoothLEDevice. Once we have a reference to the device, the GetRfcommServiceAsync method helps us to get list of all available services. Our Arduino code is very primitive and we have just one service. Once we have a reference to the service, we can use the StreamSocket class to establish a connection to the Bluetooth module and get references to input and output streams.

Finally, we can use DataReader and DataWriter classes to start working with the module like with a virtual serial port:

private async void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
   byte data = 2;
   if (switchLed.IsOn)
   {
      data = 3;
   }
   tx.WriteByte(data);
   await tx.StoreAsync();
   uint buf;
   buf = await rx.LoadAsync(1);
   var symbol = rx.ReadByte();
   Debug.WriteLine(data);
}

If you want to develop something more for Arduino and Windows 10, I would recommend to use Remote Wiring project (https://github.com/ms-iot/remote-wiring) that can help you control Arduino board using your own UWP application.

Advertisements

Written by Sergiy Baydachnyy

05/19/2017 at 10:58 PM

UWP: Working with Bluetooth (part 4: Publishing GATT services)

leave a comment »

Thanks to new Bluetooth Low Energy API in Creators Update, UWP applications can publish GATT services playing a virtual peripheral role. It makes sense if you develop a hardware hub on Windows 10 that should be connected to different peripheral devices (not just Bluetooth, but ZigBee, Z-WAVE and even by wires) and want to use Bluetooth as a communication protocol between your phones, computers and the hub. In this case, the hub can read data from the peripheral devices and route these data as a set of Bluetooth services.

Of course, to publish anything as a BLE service you have to make sure that a radio module on your computer supports peripheral role. I didn’t find any list or recommendations yet, but it’s really not easy to find a device for tests. Even if a radio module based on a chip that can work as a transmitter, it means nothing. All my five computers including Surface Book don’t support peripheral role, but I could find at least one device: Raspberry Pi 3 that has embedded Bluetooth module. It’s strange, but using Raspberry Pi 3 you will not be able to implement beacons, but it works fine as a virtual peripheral device. If you have Raspberry Pi 2, it will not work, because both recommended external modules don’t support peripheral role.

To check if your computer supports the peripheral role, you can use the BluetoothAdapter class and check the IsPeripheralRoleSupported property. If it’s true, your device can work as a Bluetooth peripheral device.

Let’s discuss how to publish own services if your module supports the peripheral role. I will create a service that is similar to STEVAL-IDB007V1 default service that we discussed in the beginning. So, I am going to create two services. The first one will publish acceleration data and the second one will publish temperature and pressure. First of all we need to create an instance of the GattServiceProvider class. It’s possible to do using the CreateAsync static method of the class:

var serviceResult =
    await GattServiceProvider.CreateAsync(Guid.Parse(SensorUUIDs.UUID_ACC_SERV));
accService = serviceResult.ServiceProvider;
accService.AdvertisementStatusChanged += AccService_AdvertisementStatusChanged;

You can see that to use the CreateAsync method it’s enough to pass a GUID as a parameter. Pay attention that Bluetooth specification contains some reserved GUIDs for adopted services. So, if you create something from scratch, it’s better to check all reserved GUIDs. In the code above I declared an event handler for the AdvertisementStatusChanged event in order to make sure that my service is started.

Once our service is created, we can add characteristics to it. The following code shows how to do it:

var param = new GattLocalCharacteristicParameters();
param.CharacteristicProperties =
    GattCharacteristicProperties.Indicate |
    GattCharacteristicProperties.Read;
param.WriteProtectionLevel = GattProtectionLevel.Plain;
param.UserDescription = "accelerometer";
var charResult=
    await accService.Service.CreateCharacteristicAsync(
        Guid.Parse(SensorUUIDs.UUID_ACC_DATA),param);
accData = charResult.Characteristic;
accData.ReadRequested += AccData_ReadRequested;

To create a characteristic, you can use CreateCharacteristicAsync method, but prior to call it we need to prepare parameters for the characteristic. You can see that our characteristic is indicatable and supports Read operation. You can add Notify to support notification mechanism. Because our characteristic supports Read, we need to handle ReadRequested event to provide all needed data. Below you can see implementation for the handler:

private async void AccData_ReadRequested(GattLocalCharacteristic sender,
    GattReadRequestedEventArgs args)
{
    var deferral=args.GetDeferral();
    var request = await args.GetRequestAsync();
    var writer = new DataWriter();
    writer.WriteBytes(new byte[6] { 0x12, 0x12, 0x12, 0x12, 0x12, 0x12 });
    request.RespondWithValue(writer.DetachBuffer());
    deferral.Complete();
}

In this code if you forget to use deferral, the code will generate a runtime exception. In the beginning if the chapter my STEVAL-IDB007V1 board had some sensors, but Raspberry Pi 3 doesn’t contain accelerometer or temperature sensors. So, I generate fake values just to test if it works at all, but if you want, you can connect real sensors to your Raspberry Pi 3.

Finally, we are ready to advertise the service.

accService.StartAdvertising(
    new GattServiceProviderAdvertisingParameters() {
        IsDiscoverable = true, IsConnectable = true });

Using StartAdvertising method we need to initialize IsDiscoverable and IsConnectable to true.

Opening my code on github you can find implementation for the second service with similar implementation. To test this service, we can use our first application in this chapter or any BLE scanner.

Written by Sergiy Baydachnyy

05/18/2017 at 3:11 AM

UWP: Working with Bluetooth (part 3: Advertisement)

leave a comment »

Bluetooth Low Energy can be used to implement beacons. Usually beacons are not designed for pairing and simply broadcast data making them available for everybody. You can use beacons in a mall to notify shoppers about some deals, or in quests, notifying players about some treasures in the area, or even for people with disabilities notifying them about surrounding environment. Today, almost all mobile devices support Bluetooth Low Energy and advertisement feature there and you even can find some SDKs for Android and iOS that implement own data payload specifications (Eddystone and iBeacon) based on Bluetooth Low Energy Advertisement. Thanks to the specifications you can understand what kind of data is broadcasting and use them in your applications even if a beacon was implemented by somebody else.

In the case of Universal Windows Platform you have access to a special namespace Windows.Devices.Bluetooth.Advertisement that can help you receive and send data using BLE Advertisement. Using this namespace you can implement classes that will use existing payload specifications or simply broadcast data in your own way.

To implement advertisement example, I am not going to use any microcontroller. Instead, I would recommend to use just Windows 10 computers. In general, any Windows 10 computer can send and receive advertisement, but in some cases, it’s not true and some Bluetooth radio adapters don’t support broadcasting advertisement data.

To understand if your adapter supports broadcasting, you can simply execute the following line of code:

BluetoothAdapter adapter = await BluetoothAdapter.GetDefaultAsync();

And just check adapter’s property using Debugger:

clip_image002

You can see that there is a property IsAdvertisementOffloadSupported that shows if your adapter can broadcast advertisement. In my case this property is true.

Ok, let’s start with code that broadcast some data:

BluetoothLEAdvertisementPublisher publisher;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    var manufacturerData =
        new BluetoothLEManufacturerData();
    var writer = new DataWriter();
    writer.WriteString("Buy our socks for a dollar");
    manufacturerData.CompanyId = 0xFFFE;
    manufacturerData.Data = writer.DetachBuffer();
    publisher =
        new BluetoothLEAdvertisementPublisher();
    publisher.Advertisement.ManufacturerData.Add(manufacturerData);
    publisher.StatusChanged += Publisher_StatusChanged;
    publisher.Start();
    base.OnNavigatedTo(e);
    }
private void Publisher_StatusChanged(BluetoothLEAdvertisementPublisher sender,
    BluetoothLEAdvertisementPublisherStatusChangedEventArgs args)
{
    Debug.WriteLine(args.Status.ToString());
}

In our case we made all preparation work using the BluetoothLEManufacturerData class. We used this class just in order to simplify our work, because we are not going to broadcast anything special, but in the most cases you will use the DataSections property rather than the ManufacturerData property. Exactly DataSections contains all payloads and filling ManufacturerData you automatically add a section to DataSections collection. But working with the BluetoothLEAdvertisementDataSection class to fill DataSections is a little bit more complicated, because you need to know different data types from BLE specification, form a header that will include special flags and size of the buffer and so on. In the case of the BluetoothLEManufacturerData class you can write your data directly and all what you need is just provide a company id. Using this link (https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers), you can find some hardcoded company ids for companies like Apple and Microsoft. Therefore, I selected the first available ID from the end. Additionally, I implemented the StatusChanged event handler to make sure that my application starts broadcasting data.

Therefore, we have a publisher that broadcasts a text message. Now, we can create a watcher that will receive our advertisement. Let’s look at the following code:

private BluetoothLEAdvertisementWatcher watcher;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    watcher = new BluetoothLEAdvertisementWatcher();
    watcher.SignalStrengthFilter.InRangeThresholdInDBm = -70;
    var manufacturerData =
        new BluetoothLEManufacturerData();
    manufacturerData.CompanyId = 0xFFFE;
    watcher.AdvertisementFilter.Advertisement.ManufacturerData.Add(
        manufacturerData);
    watcher.Stopped += Watcher_Stopped;
    watcher.Received += Watcher_Received;
    watcher.Start();
    base.OnNavigatedTo(e);
}
private void Watcher_Stopped(BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementWatcherStoppedEventArgs args)
{ }
private void Watcher_Received(BluetoothLEAdvertisementWatcher sender,
    BluetoothLEAdvertisementReceivedEventArgs args)
{
    Debug.WriteLine(args.Advertisement.LocalName);
    Debug.Write(args.RawSignalStrengthInDBm);
    if ((args.Advertisement.ManufacturerData.Count>0))
    {
        DataReader data =
            DataReader.FromBuffer(args.Advertisement.ManufacturerData[0].Data);
        Debug.Write(data.ReadString(
            args.Advertisement.ManufacturerData[0].Data.Length));
    }
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
    watcher.Stop();
    base.OnNavigatedFrom(e);
}

In fact, it’s not a complex task to create a watcher, but implementing your own application, you should not always watch all advertisements around. It’s better to watch exactly beacons that were designed for your application. That’s why the BluetoothLEAdvertisementWatcher class allows us to setup filters. In our case we have two filters: signal strength and company id. It can help us understand that we are too close to the beacon and that it’s exactly our service.

Working with beacons we have to note several things:

  • In most cases you will work with the DataSections property. So, if you want to develop something cool, you have to learn Bluetooth LE Advertisement specification. Additionally, you may need to implement Eddystone and iBeacon specifications;
  • You can see that beacon broadcasts the same data all time and if you run our application in the Debug mode, you will be able to see that the application prints advertisement message all time. So, it’s important to check if you already received the message to avoid duplicate actions;
  • Above we implemented just foreground applications, but it’s not wisely. Probably, our application will not stay open all time even in the case of watcher. In the case of publisher, there is no sense to implement interface at all. That’s why it’s important to know how to work with Bluetooth in background. We will discuss background approach later;

Written by Sergiy Baydachnyy

05/08/2017 at 10:27 PM