BLE connection from my windows pc to the bangle js 2

Posted on
  • Hi there,
    I am implementing a BLE connection between my pc and the Bangle js 2 to stream data from the Bangle to the pc and send back responses to the bangle. I successfully managed to connect the two devices (the bangle is acting as a server device streaming the data I need to a C# console), but I'd like to send back a response string. Data is wrapped in my C# and sent to the bangle but I cannot find a way to read it on the device: do I need to create a specific characteristic on my pc to which connect the bangle or am I missing something? Connection actually is successfull but is it biunivocal?
    Thanks in advance!

  • Hi - if you connect to the BLE UART service (which I think is what you might be doing?) then by default you're sharing it with the JavaScript REPL.

    The simplest method is just to wrap what you send in a function call. For instance if you send the string "\x10X({my:"data"})\n" and have a function called X then that function will be called automatically. The \x10 at the start turns 'echo' off so Espruino doesn't try and output what you wrote back to you

    OR you can handle data coming in with Bluetooth.on('data', function(d) { ... }) but only if you remove the REPL. E.setConsole(null) will remove the JS REPL so then the 'data' handler works (until you disconnect/reconnect) - you just need to be careful as moving the REPL means you can no longer write code to the device :)

    Or you could create another characteristic - but using the BLE UART is nice and easy

  • Hi! Thanks for your prompt repyl: where can I find reference to the

    Bluetooth.on('data', function(d) { ... })
    

    method? I couldn't find anything on the doc. Anyway, regarding the first method, do you think this is correct in my c# console? This is just a test:

    else if (properties.HasFlag(GattCharacteristicProperties.Write))
                                            {
                                                Console.WriteLine($"\t \t Characteristic {characteristic.Uuid} has a write property ");
                                                Console.WriteLine("-------------------------------- ");
                                                var writer = new DataWriter();
                                                // WriteByte used for simplicity. Other common functions - WriteInt16 and WriteSingle
                                                writer.WriteByte(0x01);
                                                writer.WriteString("\\x10X({my:\"data\"})\\n");
    
                                                GattCommunicationS
    
  • the \\x10X is probably not OK, you need to send binary value 0x10 inside the data, so something like the writer.WriteByte(0x01); which is maybe attempt to do it?

  • It's at http://www.espruino.com/Reference#l_Serial_data - Bluetooth is an instance of Serial

    I think you have two issues here...

    • You're sending writer.WriteByte(0x01); for some reason? I'd remove that
    • As @fanoush says, you're over-escaping the string, for the 0x10 as well as the newline at the end. Something like writer.WriteString("\x10X({my:\"data\"})\n"); would do it
  • Hi,
    I'll remove the line of code concerning the

    writer.WriteByte(0x01);
    

    and test as you suggest!
    This is instead my js code running on Bangle:

    g.setFontAlign(0,0); 
    g.setFont("Vector",25);
    var gatt;
    NRF.on('connect', function(addr) {
      g.clear();
      g.setColor(255,0,0);
      g.drawString("Connected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=>g.clear(), 1000);
    });
    
    Bluetooth.on('data', function(d) { g.drawString(d, g.getWidth()/2, g.getHeight()/2); });
    
    NRF.on('disconnect', function(reason) {
      g.clear();
      g.setColor(0,0,255);
      g.drawString("Disconnected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=> g.clear(), 1000);
    });
    

    Is Bluetooth.on() called once the BLE received packets ?

  • Ahh - maybe you could try what I suggested at the start first? Just a function called 'X'?

    Bluetooth.on('data', is called when data is received, but only when you move the REPL out the way with something like E.setConsole(null) as I'd said above - and you don't seem to be doing that here?

    Try adding E.setConsole(null) to NRF.on('connect', function(addr) { but just be aware that you won't then be able to connect to flash the Bangle - you'll have to hold the button to reload the default clock (which hopefully isn't your app!).

  • No actually I didn't call the E.setConsole(), I'll try even if I'd like to keep the console on my logic to double check the response. As for your first suggestion, did you mean to implement a callback function 'X' which will accept the data sent as parametr and which is call when something is received? Basically adding this function within Bluetooth.on()?

  • No actually I didn't call the E.setConsole()

    If you don't call E.setConsole(null) then Bluetooth.on('data', won't be called so your code won't work. If you do call it you can still print with Bluetooth.println

    Basically adding this function within Bluetooth.on()?

    No... I mean just code like this:

    g.setFontAlign(0,0); 
    g.setFont("Vector",25);
    var gatt;
    NRF.on('connect', function(addr) {
      g.clear();
      g.setColor(255,0,0);
      g.drawString("Connected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=>g.clear(), 1000);
    });
    function X(d) { g.drawString(d, g.getWidth()/2, g.getHeight()/2); } // <----- this
    NRF.on('disconnect', function(reason) {
      g.clear();
      g.setColor(0,0,255);
      g.drawString("Disconnected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=> g.clear(), 1000);
    });
    
  • I tried but anyway the connection print the data received to my C# console and not the bangle. I tried even by deactivating the console with the code below, same results:

    setInterval(() => (console.log(E.getTemperature())), 1000);
    
    g.setFontAlign(0,0); 
    g.setFont("Vector",25);
    var gatt;
    
    E.setConsole(null);
    
    
    NRF.on('connect', function(addr) {
      g.clear();
      g.setFont("Vector",10);
      g.setColor(255,0,0);
      g.drawString(addr,g.getWidth()/2, g.getHeight()/2);
      g.setFont("Vector",25);
      setTimeout(()=>g.drawString("Connected", g.getWidth()/2, g.getHeight()/2), 3000);
      setTimeout(()=>g.clear(), 1000);
    });
    
    NRF.on('disconnect', function(reason) {
      g.clear();
      g.setColor(0,0,255);
      g.drawString("Disconnected", g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=> g.clear(), 1000);
    });
    
    
    
    Bluetooth.on('data', function(d) { 
      g.clear();
      Bluetooth.println(d);
      g.setColor(0,0,0);
      g.drawString('Data received', g.getWidth()/2, g.getHeight()/2);
      g.drawString(s); 
      g.drawString(s, g.getWidth()/2, g.getHeight()/2); 
    });
    

    this is instead the C# console class:

        internal class Program
        {
            static DeviceInformation _device = null;
            private static string NORDIC_UART_SERVICE = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
            static DataFormat _dataFormat = DataFormat.UTF8;
    
            static GattCommunicationStatus result;
            static GattCharacteristic _characteristic;
            static async Task Main(string[] args)
            {
                // Query for extra properties you want returned
                string[] requestedProperties = { "System.Devices.Aep.DeviceAddress", "System.Devices.Aep.IsConnected" };
    
                DeviceWatcher deviceWatcher =
                            DeviceInformation.CreateWatcher(
                                    BluetoothLEDevice.GetDeviceSelectorFromPairingState(false),
                                    requestedProperties,
                                    DeviceInformationKind.AssociationEndpoint);
    
                // Register event handlers before starting the watcher.
                // Added, Updated and Removed are required to get all nearby devices
                deviceWatcher.Added += DeviceWatcher_Added;
                deviceWatcher.Updated += DeviceWatcher_Updated;
                deviceWatcher.Removed += DeviceWatcher_Removed;
    
                // EnumerationCompleted and Stopped are optional to implement.
                deviceWatcher.EnumerationCompleted += DeviceWatcher_EnumerationCompleted;
                deviceWatcher.Stopped += DeviceWatcher_Stopped;
    
                // Start the watcher.
                deviceWatcher.Start();
    
                while (true)
                {
                    if (_device == null)
                    {
                        Thread.Sleep(200);
                    }
                    else
                    {
                        Console.WriteLine("Press any key to connect to the Bangle. Js");
                        Console.ReadKey();
                        BluetoothLEDevice bluetoothLEDevice = await BluetoothLEDevice.FromIdAsync(_device.Id);
                        Console.WriteLine("Pairing with the device");
    
                        GattDeviceServicesResult servicesResult = await bluetoothLEDevice.GetGattServicesAsync();
    
                        if (servicesResult.Status == GattCommunicationStatus.Success)
                        {
                            Console.WriteLine("Pairing succeed");
                            var services = servicesResult.Services;
                            foreach (var service in services)
                            {
                                Console.WriteLine($"Service: {service.Uuid}");
                                Console.WriteLine("-----------------------");
    
                                if (service.Uuid.ToString() == NORDIC_UART_SERVICE)
                                {
                                    Console.WriteLine("Connected to NUS Service");
                                    Console.WriteLine("----------------------------------");
    
                                    GattCharacteristicsResult characteristicsResult = await service.GetCharacteristicsAsync();
                                  
                                    if (characteristicsResult.Status == GattCommunicationStatus.Success)
                                    {
                                        var characteristics = characteristicsResult.Characteristics;
                                        foreach (var characteristic in characteristics)
                                        {
                                            Console.WriteLine($"Characteristic {characteristic.Uuid}");
                                            Console.WriteLine("--------------------------------");
                                            GattCharacteristicProperties properties = characteristic.CharacteristicProperties;
    
                                            if (properties.HasFlag(GattCharacteristicProperties.Notify))
                                            {
                                                Console.WriteLine("Notify property found");
    
                                                GattCommunicationStatus status = await characteristic.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
                                                if (status == GattCommunicationStatus.Success)
                                                {
                                                    Console.WriteLine("Server has been informed of clients interest and has set the client in notify status");
                                                    characteristic.ValueChanged += Characteristic_ValueChanged;
                                                    _characteristic = characteristic;
                                                    
                                                }
                                            }
    
                                            else if (properties.HasFlag(GattCharacteristicProperties.Write))
                                            {
                                                Console.WriteLine($"\t \t Characteristic {characteristic.Uuid} has a write property ");
                                                Console.WriteLine("-------------------------------- ");
    
                                                var writer = new DataWriter();                                           
                                                writer.WriteString("Data received");
                                                
                                                result = await characteristic.WriteValueAsync(writer.DetachBuffer());
                                                if (result == GattCommunicationStatus.Success)
                                                {
                                                    Console.WriteLine("Data sent");     
                                                }
                                            }
                                            else if (properties.HasFlag(GattCharacteristicProperties.WriteWithoutResponse))
                                            {
                                                Console.WriteLine($"\t \t Characteristic {characteristic.Uuid} has a write withoutresponse property ");
                                                Console.WriteLine("-------------------------------- ");
    
                                            }
                                        }
                                    }
                                }
                            }
                        }
    
                        Console.WriteLine("Press space to disconnect or q to exit");
                      
                        if (Console.ReadKey().Key == ConsoleKey.Spacebar)
                        {
                            bluetoothLEDevice.Dispose();
                            return;
                        }
                        else if (Console.ReadKey().Key == ConsoleKey.Q)
                        {
                            Console.WriteLine("Closing");
                            Thread.Sleep(1000);
                        } 
                        break;
                    }
                    
                }
    
            }
    
            private static void DeviceWatcher_Stopped(DeviceWatcher sender, object args)
            {
                //throw new NotImplementedException();
            }
    
            private static void DeviceWatcher_EnumerationCompleted(DeviceWatcher sender, object args)
            {
                //throw new NotImplementedException();
            }
    
            private static void DeviceWatcher_Removed(DeviceWatcher sender, DeviceInformationUpdate args)
            {
                //throw new NotImplementedException();
            }
    
            private static void DeviceWatcher_Updated(DeviceWatcher sender, DeviceInformationUpdate args)
            {
                //throw new NotImplementedException();
            }
    
            private static void DeviceWatcher_Added(DeviceWatcher sender, DeviceInformation args)
            {
                if (args.Name == "Bangle.js 0ea8")
                {
                    Console.WriteLine(args.Name);
                    _device = args;
                }
               
                
                
            }
    
            private static void Characteristic_ValueChanged(GattCharacteristic sender, GattValueChangedEventArgs args)
            {
                //An Indicate or Notify reported that the value has changed.
                var value = Utilities.FormatValue(args.CharacteristicValue, _dataFormat);
                if (value.Contains('J'))
                {
                    string[] values = value.Split('J');
                    Console.WriteLine(values[1]);
                }
                else
                {
                    Console.WriteLine(value);
                }
            }
    

    Any other suggestion?

  • Do E.setConsole(null); on the connect event.

    Otherwise when BLE connects the console swap over to BLE automatically.

    You can do E.setConsole(null,true); to force the console, but if you do that you won't even be able to program your Bangle unless you completely reboot it without loading your code.

  • Tried but nothing! I am thinking of creating a new service on my PC to which connect the Bangle Js. I did not find any other valid solution to the topic. Actually the message is sent to my PC, but the Bangle seems not to be receiving it.

  • I don't know if maybe you can try using NRF Connect on your phone to emulate the Bangle.js UART service, and then you'd be able to see if your code on the PC is working properly?

  • Just to know, which is the protocol type of the BLE module running on the Bangle Js 2? 5.2? Because on my laptop I am running BLE 4.0.

  • It is something between 5.0 and 5.1, doesn't matter much, should just work with4.0.

    Current firmware is using S140 6.0.0 as per https://www.nordicsemi.com/Products/Development-software/S140 , qualification for 5.1 was passed in version 7.0.1

  • Ok i successfully managed to trigger the X.on("data"...) event, but it is not evoked when I tried to send again another message.

    Bluetooth.on('data', function(d) { 
      g.clear();
      g.setFont("Vector", 20);
      g.setColor(0,255,0);
      //buf += d;
      //var l = buf.split("\n");
      //buf = l.pop();
      //l.forEach(onLine);
      //console.log(value);
      //c = d.getInt16(0);
      const buffer = new ArrayBuffer(16);
      const view = new DataView(buffer);
      c = view.getInt16(0);
      g.drawString(c, g.getWidth()/2, g.getHeight()/2);
      setTimeout(()=>g.clear(),1500); 
      });
    
    

    Does the function(d) return a dataview?

  • On the case of Bluetooth.on('data' it's a string. It should definitely be called again if you get more data though - it's not a one-shot thing

  • Clear! Thanks you! What about if I'd like reading bytes or int16 data sent over ble to my bangle?
    The bangle encode the data in the ASCII format right? I then need to convert it in string right?

  • If you send binary data to Bangle.js over the UART connection, you can just read that out with Bluetooth.on('data', function(d) { too.

    The event returns a string, but it's easy enough to use E.toUint8Array: http://www.espruino.com/Reference#l_E_toUint8Array

    Bluetooth.on('data', function(d) { 
      const view = new DataView(E.toUint8Array(d).buffer);
      ... view.getInt16(0)
    });
    
  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

BLE connection from my windows pc to the bangle js 2

Posted by Avatar for Riccardokhm @Riccardokhm

Actions