How does one find the valid signatures in D-Bus for an interface method?

,

From BlueZ documentation for the GATT API’s:

		void WriteValue(array{byte} value, dict options)

			Issues a request to write the value of the
			characteristic.

This is the error when I try to connect to the above API:

Method "WriteValue" with signature "aya{sv}" on interface "org.bluez.GattCharacteristic1" doesn't exist

How do I determine exactly what the signature should be? The error message has the parameter list described as I intended.

You can use

$ gdbus introspect --system --dest org.bluez --object-path /org/bluez --recurse

to get information on all interfaces of all objects under the /org/bluez hierarchy.

gdbus introspect --system --dest org.bluez --object-path /org/bluez --recurse | grep -i gatt
    interface org.bluez.GattManager1 {

But org.bluez.GattCharacteristic1 does not exist in the output. That is unlikely, since it is used in the python-dbus example that comes with BlueZ (I have tried it and it works), and I have successfully done ReadValue:

 gatt_objects = g_dbus_connection_call_sync(con,
                "org.bluez",
                charp,
                "org.bluez.GattCharacteristic1",
                "ReadValue",
                g_variant_new_tuple(&v1, 1),  // Empty variant.
                NULL,
                G_DBUS_CALL_FLAGS_NONE,  // Flags
                10000, // 10 second timeout
                NULL, // Cancellable
                &errorO  // error
            );  // User data for callback

This stuff is apparently dynamic. So you cannot introspect until the device is connected:

        interface org.bluez.GattCharacteristic1 {
            methods:
              ReadValue(in  a{sv} options,
                        out ay value);
              WriteValue(in  ay value,
                         in  a{sv} options);
              AcquireWrite(in  a{sv} options,
                           out h fd,
                           out q mtu);
              AcquireNotify(in  a{sv} options,
                            out h fd,
                            out q mtu);
              StartNotify();
              StopNotify();
            signals:

So the first parameter for WriteValue is :
ay value

The 2nd is:
a{sv} options

Isn’t that what the error message is telling me is wrong? Or is the problem not in my code?

Hard to tell without seeing the code. Maybe you forgot to wrap the parameters in a tuple?

The function g_variant_get_type_string() can be used to get the formatting string for the GVariant.

So for sanity, I first tried this on org.freedesktop.DBus.Properties method called “Set”.

   Set(in  s interface,
            in  s name,
            in  v value);

This results in g_variant_get_type_string() on its parameter returns:

(ssv)

This function is working correctly.

For my org.bluez.GattCharacteristic1 method “WriteValue”, g_variant_get_type_string() returns:

(aya{sv})

The gdbus introspect returns:

         interface org.bluez.GattCharacteristic1 {
            methods:
              ReadValue(in  a{sv} options,
                        out ay value);
              WriteValue(in  ay value,
                         in  a{sv} options);

The error I see is:

Error message: Method "WriteValue" with signature "aya{sv}" on interface "org.bluez.GattCharacteristic1" doesn't exist

Code:

            GVariantBuilder *builder;
            GVariant *v1=g_variant_new("(q)", 0);
            GVariant *options;
            GVariant *parameters;
            const gchar *typestring;
            
            builder = g_variant_builder_new( G_VARIANT_TYPE("a{sv}") );
            g_variant_builder_add(builder, "{sv}", "offset", v1);
            options = g_variant_new ("a{sv}", builder);
            g_variant_builder_unref (builder);
            GBytes *bytes = g_bytes_new(RSU2_PASSWORD, strlen(RSU2_PASSWORD)+1);
            GVariant *pwd = g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, bytes, TRUE);
            GVariant *args = g_variant_new("(@ay@a{sv})",pwd,options);

            typestring = g_variant_get_type_string(args);
            g_print("%p: %s: typestring for WriteValue: %s\n",g_thread_self(),__func__,typestring);

            gatt_objects = g_dbus_connection_call_sync(con,
                "org.bluez",
                charp,
                "org.bluez.GattCharacteristic1",
                "WriteValue",
                args,
                NULL,
                G_DBUS_CALL_FLAGS_NONE,  // Flags
                10000, // 10 second timeout
                NULL, // Cancellable
                &errorO  // error
            );  // User data for callback

I solved this one. The problem was that errorO was not cleared in my outer loop. I eventually intend to add a wait for the characteristic to appear, but for now I called the function in a loop, and errorO has to be set to NULL before invoking the function.

Apparently g_dbus_callsync will not overwrite &errorO with a new error.

So the “doesn’t exist” message means that it really did not exist yet, and now after clearing errorO I see:

0x7fd10c0082a0: print_error: Error message: GDBus.Error:org.bluez.Error.InvalidArguments: Invalid arguments in method call
0x7fd10c0082a0: print_error: Remote error
0x7fd10c0082a0: print_error: Raw message: org.bluez.Error.InvalidArguments
0x7fd10c0082a0: print_error: Returning

Rather strange semantics that the error parameter is not overwritten on the next call.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.