Languages

Menu
Sites
Language
How to properly create and notify a characteristic with GATT Server and BLE on Tizen (watch 3)

Hello, I am currently trying to establish a connection via GATT with Android and Tizen on a watch 3, and everything seems to be working correctly, and I can see the service on nRF app, but I cannot see the value nor notify when I press the button on the watch.

 

I cannot find a way to see connected clients from the server side, and I cannot notify with null, as it throws an exception.

nRF SS:

 

Error thrown:

Here is the code of the Server running on Tizen watch:

 

using System.Text;

using Xamarin.Forms;
using Tizen.Network.Bluetooth;
using Tizen.Wearable.CircularUI.Forms;
using Tizen.NUI;
using System;

namespace TizenWearableApp1
{
    public class App : Application
    {
        BluetoothGattServer m_GattServer;
        private BluetoothGattService m_GattService;
        BluetoothLeAdvertiser m_Advertiser;
        BluetoothLeAdvertiseData m_AdvertiseData;
        BluetoothGattCharacteristic m_CharcTX;
        BluetoothLeDevice m_Device;
        Button b;

        const string SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; // UART service UUID
        const string CHARAC_UUID_RX = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
        const string CHARAC_UUID_TX = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";

        public App()
        {
            b = new Button();
            b.Clicked += OnClick;
            b.Text = "Set Charc Val";
            // The root page of your application
            MainPage = new CirclePage
            {
                Content = new StackLayout
                {
                    VerticalOptions = LayoutOptions.Center,
                    Children =
                    {
                        b
                    }
                }
            };
        }

        private void OnClick(object sender, EventArgs e)
        {
            test++;
            //byte[] descriptorValue = UTF8Encoding.UTF8.GetBytes(test.ToString());
            IntDataType intType = IntDataType.UnsignedInt8;
            b.Text = m_GattService.GetCharacteristic(CHARAC_UUID_RX).GetValue(0).ToString();
            m_GattService.GetCharacteristic(CHARAC_UUID_TX).SetValue(intType, test, 1);
            m_GattServer.SendNotification(m_GattService.GetCharacteristic(CHARAC_UUID_TX), null);
        }

        public void bt_onoff_operation()
        {
            /// Launch the Bluetooth activation settings to allow the user to enable Bluetooth
            Tizen.Applications.AppControl myAppControl = new Tizen.Applications.AppControl();
            myAppControl.Operation = Tizen.Applications.AppControlOperations.SettingBluetoothEnable;
            Tizen.Applications.AppControl.SendLaunchRequest(myAppControl);
        }

        protected override void OnStart()
        {
            BluetoothAdapter.DiscoveryStateChanged += DiscoveryChanged;
            BluetoothAdapter.NameChanged += NameChanged;
            BluetoothAdapter.ScanResultChanged += ScanChanged;
            BluetoothAdapter.StateChanged += StateChanged;
            BluetoothAdapter.VisibilityDurationChanged += VisibilityChanged;
            BluetoothAdapter.VisibilityModeChanged += VisibilityModeChanged;
            BluetoothAdapter.Name = "ArielTESTTT";
            
            m_GattServer = BluetoothGattServer.CreateServer();
            m_GattServer.NotificationSent += GattNotificationSent;
            m_GattService = new BluetoothGattService(SERVICE_UUID, BluetoothGattServiceType.Secondary);

            byte[] characteristicValue = UTF8Encoding.UTF8.GetBytes("test1");
            byte[] characteristic2Value = UTF8Encoding.UTF8.GetBytes("test1");
            byte[] descriptorValue = UTF8Encoding.UTF8.GetBytes("test2");
            
            m_CharcTX = new BluetoothGattCharacteristic(CHARAC_UUID_TX, BluetoothGattPermission.Read, BluetoothGattProperty.Notify, characteristicValue);
            m_CharcTX.SetValue("test1");
            m_CharcTX.ReadRequested += ReadRequested;
            m_CharcTX.WriteRequested += WriteRequested;
            BluetoothGattDescriptor desc = new BluetoothGattDescriptor("2902", BluetoothGattPermission.Read, descriptorValue);
            desc.SetValue("test1");
            m_CharcTX.AddDescriptor(desc);
            m_CharcTX.Value = characteristicValue;

            m_CharcTX.WriteType = BluetoothGattWriteType.NoResponse;
            m_GattService.AddCharacteristic(m_CharcTX);
            m_GattService.GetCharacteristic(CHARAC_UUID_TX).NotificationStateChanged += NotificationStateChanged;
            m_GattServer.RegisterGattService(m_GattService);
            m_GattServer.Start();
            StartBLEAdvertise();
        }

        /// Register for GATT connection event handler
        public static void GattClient_ConnectionStateChanged(object sender, GattConnectionStateChangedEventArgs e)
        {
            if (e.Result != (int)BluetoothError.None)
            { 
            }           
            else if (!e.RemoteAddress.Equals(""))
            {
            }
            else if (e.IsConnected.Equals(false))
            {
            }
            else
            {
            }
        }


        private void NotificationStateChanged(object sender, NotificationStateChangedEventArg e)
        {
            int a = 0;
        }

        private void WriteRequested(object sender, WriteRequestedEventArgs e)
        {
            m_CharcTX.Value = e.Value;
        }

        private void GattNotificationSent(object sender, NotificationSentEventArg e)
        {
            int a = 0;
        }

        private void VisibilityModeChanged(object sender, VisibilityModeChangedEventArgs e)
        {
            int a = 0;
        }

        private void VisibilityChanged(object sender, VisibilityDurationChangedEventArgs e)
        {
            int a = 0;
        }

        private void StateChanged(object sender, StateChangedEventArgs e)
        {
            int a = 0;
        }

        private void ScanChanged(object sender, AdapterLeScanResultChangedEventArgs e)
        {
            int a = 0;
        }

        private void NameChanged(object sender, NameChangedEventArgs e)
        {
            int a = 0;
        }
        int test = 0;
        private void ReadRequested(object sender, ReadRequestedEventArgs e)
        {
            test++;
            byte[] descriptorValue = UTF8Encoding.UTF8.GetBytes(test.ToString());
            m_CharcTX.Value = descriptorValue;
            int a = 0;
        }

        private void StartBLEAdvertise()
        {
            AddAdvertiseData();
            BluetoothAvrcp avrcp;
            m_Advertiser = BluetoothAdapter.GetBluetoothLeAdvertiser();
            m_Advertiser.AdvertisingStateChanged += AdvertisingStateChanged;
            m_Advertiser.StartAdvertising(m_AdvertiseData);
        }

        private void AdvertisingStateChanged(object sender, AdvertisingStateChangedEventArgs e)
        {
            int a = 0;
            //throw new NotImplementedException();
        }

        void AddAdvertiseData()
        {
            m_AdvertiseData = new BluetoothLeAdvertiseData();

            // Add appearance
            m_AdvertiseData.PacketType = BluetoothLePacketType.BluetoothLeAdvertisingPacket;
            m_AdvertiseData.Appearance = 192;

            /// Add device name
            m_AdvertiseData.IncludeDeviceName = true;

            /// Add TX power level
            m_AdvertiseData.IncludeTxPowerLevel = false;

            /// Add manufacturer data
            ManufacturerData manufData = new ManufacturerData();
            manufData.Data = new byte[5] { 0x01, 0x02, 0x03, 0x04, 0x05 };
            manufData.Id = 117;
            manufData.DataLength = 5;
            m_AdvertiseData.AddAdvertisingManufacturerData(BluetoothLePacketType.BluetoothLeScanResponsePacket, manufData);

            /// Add service solicitation UUID
            string serviceSolicitationUuid = "180d";
            m_AdvertiseData.AddAdvertisingServiceSolicitationUuid(BluetoothLePacketType.BluetoothLeScanResponsePacket, serviceSolicitationUuid);

            /// Add service UUID
            string serviceUuid = "1805";
            m_AdvertiseData.AddAdvertisingServiceUuid(BluetoothLePacketType.BluetoothLeScanResponsePacket, serviceUuid);
            
            /// Add service data
            BluetoothServiceData serviceData = new BluetoothServiceData();
            serviceData.Uuid = "1805";
            serviceData.DataLength = 3;
            serviceData.Data = new byte[3] { 0x01, 0x02, 0x03 };
            m_AdvertiseData.AddAdvertisingServiceData(BluetoothLePacketType.BluetoothLeScanResponsePacket, serviceData);
            m_AdvertiseData.AdvertisingConnectable = true;
        }

        private void DiscoveryChanged(object sender, DiscoveryStateChangedEventArgs e)
        {
            e.DeviceFound.CreateBond();
            e.DeviceFound.CreateSocket("test");
        }

        private void EventHandlerStateChanged(object sender, StateChangedEventArgs e)
        {
            if (e.BTState == BluetoothState.Enabled)
            {
                StartBLEAdvertise();
            }
            else
            {
                bt_onoff_operation();
            }
        }

        protected override void OnSleep()
        {
            // Handle when your app sleeps
        }

        protected override void OnResume()
        {
            // Handle when your app resumes
        }
    }
}

 

Edited by: ariel madril on 17 Sep, 2020

Responses

14 Replies
Wootak Jung

Dear ariel madril,

WriteRequested/ReadRequested/NotificationStateChanged callback should be called after RegisterGattService() called.

Please move above callbacks to below like this:

m_GattServer.RegisterGattService(m_GattService);
m_CharcTX.ReadRequested += ReadRequested;
m_CharcTX.WriteRequested += WriteRequested;
m_CharcTX.NotificationStateChanged += NotificationStateChanged;
m_GattServer.Start();

And regarding InvalidParameter exception, please share more log if issue still remained after you apply above code.

Thank you

Wootak

ariel madril

Thank you for your response Wootak Jung!

The error persists even after changing the order like you suggested.

I managed to send data using SendIndicationAsync, and the characteristic configured as Notify. That worked without issues, so I don't know what is wrong with the SendNotification code.

 

Here is the callstack:

 

System.InvalidOperationException: Invalid parameter
   at Tizen.Network.Bluetooth.BluetoothErrorFactory.ThrowBluetoothException(Int32 exception)
   at Tizen.Network.Bluetooth.GattUtil.ThrowForError(Int32 err, String message, String file, String func, Int32 line)
   at Tizen.Network.Bluetooth.BluetoothGattServerImpl.SendNotification(BluetoothGattCharacteristic characteristic, String clientAddress)
   at Tizen.Network.Bluetooth.BluetoothGattServer.SendNotification(BluetoothGattCharacteristic characteristic, String clientAddress)
   at TizenWearableApp1.App.ButtonReleased(Object sender, EventArgs e) in C:\Users\ariel.m\source\repos\TizenWearableApp1\TizenWearableApp1\App.cs:line 134
   at Xamarin.Forms.Button.Xamarin.Forms.Internals.IButtonElement.PropagateUpReleased()
   at Xamarin.Forms.ButtonElement.ElementReleased(VisualElement visualElement, IButtonElement ButtonElementManager)
   at Xamarin.Forms.Button.SendReleased()
   at Xamarin.Forms.Platform.Tizen.ButtonRenderer.OnButtonReleased(Object sender, EventArgs e)
   at ElmSharp.Button.<.ctor>b__4_3(Object sender, EventArgs e)
   at ElmSharp.SmartEvent.SendEvent(Object sender, EventArgs e)
   at ElmSharp.SmartEvent`1.<>c__DisplayClass12_0.<add_On>b__0(IntPtr d, IntPtr o, IntPtr e)
   at Tizen.Applications.CoreBackend.UICoreBackend.Run(String[] args)
   at Tizen.Applications.CoreApplication.Run(String[] args)
   at Tizen.Applications.CoreUIApplication.Run(String[] args)
   at TizenWearableApp1.Program.Main(String[] args) in C:\Users\ariel.m\source\repos\TizenWearableApp1\TizenWearableApp1\TizenWearableApp1.cs:line 19 occurred

 

 

Wootak Jung

Could you check the Tizen.NET version on your environment?

This error was fixed on 7.0.0.15156 version.

If you already installed above version, please share the dlog with below LOG_TAG.

$ dlogutil CAPI_NETWORK_BLUETOOTH

Thank you,

ariel madril

I am now installing Visual Studio 2019 to see if I can get the newest tools for tizen, but would it be possible to upgrade the visual studio 2017 environment, or do I have to ask for a key for 2019 VS?

 

Thank you for the help so far, this has been very important for me and very good help.

ariel madril

The tizen integration I have is the one offered by Visual Studio "Extensions and Updates" window inside Visual Studio.

It is for VS 2017, and the tool version is 2.6.0.0.

I only have access to visual studio 2017 here, as this is the one that my company has license for.

 

Is there a way I can check the Tizen.net version itself?

Wootak Jung

You can check Tizen.NET version in here.

Visual Studio > Project > Manage NuGet Pakcages... > Installed Tab > Tizen.NET version

 

Maybe you need to install VS2019 to use Tizen 5.5.

https://docs.tizen.org/application/vstools/install/

 

Please give me your env information.

Thank you

ariel madril

As asked, watch 3 version:

Tizen: 5.5.0.0

Software Version:

R845FXXE1ATF5

 

I downloaded visual studio 2019, and inside nuget package I dont see version 7.0.0.15156, which has the correction for the bug, the top most I see is 6.0.0.14629, which I cannot select due project limitation, I also don't know how to unlock this version.

How can I install version 7?

ariel madril

I managed to create a new project using a 5.5 wearable template that allows me to pick 6.0.0.14995 version, but I still cannot see the latest one you mentioned.

Wootak Jung

Oh, it seems Tizen.NET 7 version is not released yet on sdk.

That's ok. Then, could you check target .net version by using below command?

$ sdb shell

$ rpm -qa | grep tizenfx

Thank you

ariel madril

This is what shows up when I type those commands:

 

It seems it is the one that has the bug fix, but how can I use it inside visual studio?
I have both visual studio 2017 and 2019 installed now.

 

Thank you!

Wootak Jung

Change was merged on 7.0.0.15156 not 15140.

hmm, There are 2 options.

1. Use SendIndicationAsync() method instead of SendNotification() - it's working same

2. I can share the new version dll. Then, you can build your application based on new dll by adding reference.

I suggest to use 1 option unless you really should use SendNotification().

Please tell me your idea. If you need new dll, please send me an email here, I can share that.

> wootak.jung@samsung.com

Thank you

ariel madril

I am using GATT as a input reporter, so I require high frequency of value updates.

My main worry is how performant Indication is vs notification. Seems like notification is lighter and better suited for this, but if they are similar in performance, I can use indication (I am using it right now while we figure out what to do).

 

Performance will become a priority latter on, so if send notification is more performant, I would like to get this dll to properly send notifications.

 

If performance is similar, I can keep using indication, it is working as for now!

Thank you for all the help so far, it's been very enlightening!

Wootak Jung

As you said, notification is lighter than indication.

But, it depends on characteristic property. I mean when you create characterisitc by using below method, transmittion type is determined.

public BluetoothGattCharacteristic(string uuid, BluetoothGattPermission permissions, BluetoothGattProperty properties, byte[] value) : base(uuid, permissions)

So, if you use Notify property instead of Indicate, your gatt service works as notification instead of indication regardless of the sending method SendNotification and SendIndicationAsync.

Thank you

ariel madril

That's great to hear! In this case, I have all I need to keep going!

 

Thank you for all the help so far!

 

Kind regards,

 

Ariel.