weliem / bluez_inc

A C library for Bluez (BLE) that hides all DBus communication. It doesn't get easier than this. This library can also be used in C++.
MIT License
87 stars 21 forks source link

Server binc_advertisement_set_local_name not sticking to client-side characteristics #66

Open abqjln opened 2 weeks ago

abqjln commented 2 weeks ago

The name advertised by my server is associated with client characteristics throughout the connection, service resolution, and read operations, but reverts to the default server adapter name following notification start. The server address associated with the characteristic does not change. My concern arises from intended use of randomized addresses with only the name remaining fixed.

Server pseudocode: binc_advertisement_set_local_name( advertisement, "advertisedname");

Client pseudocode: Track the device name and address associated with the characteristics inserting

'log_debug(TAG, "\x1B[33mDevice info derived from characteristic: '%s' [%s]\x1B[0m", binc_device_get_name(binc_characteristic_get_device(characteristic) ), binc_device_get_address(binc_characteristic_get_device(characteristic) ) );'

at the start of binc_characteristic_read() binc_internal_signal_characteristic_changed binc_characteristic_start_notify on_central_received_notification (my code)

(I have also changed "TAG" in the binc library to func to see the actual function names below)

Through the connection, service resolution, and notification start processes the server_name associated with the characteristics stays 'advertised_name'. But then upon first invocation of binc_internal_signal_characteristic_changed the device name associated with the characteristic changes to the default for the adapter (pi5dev #1 in this case)

(Reads give advertised name "advertisedname") DEBUG [binc_characteristic_read] Device info derived from characteristic: 'advertisedname' [D8:3A:DD:C9:B3:B4] DEBUG [binc_characteristic_read] reading <00002a19-0000-1000-8000-00805f9b34fb>

(Start notifying using advertised name) DEBUG [binc_characteristic_start_notify] Device info derived from characteristic: 'advertisedname' [D8:3A:DD:C9:B3:B4] DEBUG [binc_characteristic_start_notify] start notify for <00002a19-0000-1000-8000-00805f9b34fb>

(Characteristic changes and reverts to default adapter name "pi5dev #1") DEBUG [binc_internal_signal_characteristic_changed] Device info derived from characteristic: 'pi5dev #1' [D8:3A:DD:C9:B3:B4] DEBUG [binc_internal_signal_characteristic_changed] notification <50> on <00002a19-0000-1000-8000-00805f9b34fb> DEBUG [on_central_received_notification] Notify from 'pi5dev #1' [D8:3A:DD:C9:B3:B4] DEBUG [on_central_received_notification] Updated battery=80 DEBUG [on_central_received_char_read] Device info derived from characteristic: 'pi5dev #1' [D8:3A:DD:C9:B3:B4] DEBUG [on_central_received_char_read] <00002a19-0000-1000-8000-00805f9b34fb>, battery level = 80

My central client (Pi4, Debian12) is receiving notifications from a Pi5, Debian12 server.

weliem commented 2 weeks ago

Let me see if I understand what you are doing. So you first advertise, and when a central connects, you keep advertising? And then, once you turn on notifications on some characteristic, the advertised name changes?

weliem commented 2 weeks ago

In the library there is absolutely no 'link' between the local name in the advertisement and a characteristic. So I don't know where to look for the issue. Can you share some code?

abqjln commented 2 weeks ago

Thanks for caring! I am puzzled as well. This server/client pair, and the more complicated actual code with two adapters, all work. The name change is the odd thing.

Stripped-down server code follows. (I can email full source if you like) Initializes, then adds battery and device info services. Advertised name is "pi5dev-hci0". Adds heart rate service UUID to advertisement and initializes with hr measurement charact notifying. Simulated data running in separate loop. Starts advertising 2024-10-03 15:40:50:251 (testserve.txt) Upon connecting, advertising stops (2024-10-03 15:40:52:818) and will restart on disconnection.

All the escape codes are just color changes in my terminal.

testserve.c (output in [testserve.txt] (https://github.com/user-attachments/files/17250499/testserve.txt)

    //******************************************************************
    // GATT added automatically
    // Initialize DIS and BS (not advertised, discovered)
    service_dis_init( server_s.app, &server_s.dis_s );
    service_bs_init( server_s.app, &server_s.bs_s );
    //******************************************************************
    // Additional services based on adv_uuids
    for( guint j = 0; j < server_s.adv_uuids->len; j++ )
    {
        if( g_str_equal( g_ptr_array_index( server_s.adv_uuids, j ), HRS_SERVICE_UUID ) ){
            if( service_hrs_init( server_s.app, &server_s.hrs_s ) == BINC_OK ){
                server_s.hrs_s.body_sensor_c.location = HRS_SENSOR_LOCATION_FLAGS;
                g_timeout_add( HRS_NOTIFY_MS, server_notify_hrm, &server_s );
            }
            else{
                log_error( TAG, "Failed to initialize HRS" );
                return( -1 );
            }
        }

        // More services later
    }
//******************************************************************
// Advertising
// Local name to be advertised along with uuids
// Garmin does not detect advertised name, only address, but nRF Connect does both
server_s.advertisement = binc_advertisement_create();
binc_advertisement_set_local_name( server_s.advertisement, server_s.name );
binc_advertisement_set_services( server_s.advertisement, server_s.adv_uuids );
binc_adapter_start_advertising( server_s.adapter, server_s.advertisement );
log_debug( TAG, KYEL"Advertising %s with adapter '%s' [%s]"KNRM,
        binc_advertisement_get_path( server_s.advertisement ),
        binc_adapter_get_path(server_s.adapter),
        binc_adapter_get_address(server_s.adapter) );

//******************************************************************
// Set callbacks
binc_application_set_char_read_cb( server_s.app, &on_server_local_charact_read );
binc_application_set_char_updated_cb( server_s.app, &on_server_local_charact_updated) ;
binc_application_set_char_write_cb( server_s.app, &on_server_local_charact_write );
binc_application_set_desc_write_cb( server_s.app, &on_server_local_desc_write);
binc_application_set_char_start_notify_cb( server_s.app, &on_server_start_notify_from_client );
binc_application_set_char_stop_notify_cb( server_s.app, &on_server_stop_notify_from_client );
binc_adapter_set_remote_central_cb( server_s.adapter, &on_server_central_client_state_changed );
binc_adapter_register_application( server_s.adapter, server_s.app );

//binc_device_set_connection_state_change_cb( server_s.server_device, &on_server_connection_state_changed );

// Simulated data populates hrs_s.hrm_c (hr service, hr measurement characteristics)
g_timeout_add( HRS_DATA_UPDATE_MS, hrs_hrm_charact_simulate, &server_s.hrs_s.hrm_c );

//******************************************************************
// Setup mainloop
loop = g_main_loop_new( NULL, FALSE );`

CLIENT testclient.txt In testclient.txt, initializes, discovers "pi5dev-hci0 with uuid 180d (hrs). Stops discovery. Resolves services, then reads the battery and DIS services. In each of these reads, the name/address associated with the characteristic is logged using binc_device_get_name/address(binc_characteristic_get_device(characteristic)). For example, at 2024-10-03 15:40:54:256, the client reads the char 2a19 which is associated with pi5dev-hci0. That is magic?

Then the client requests to start notify from server at 2024-10-03 15:40:54:259. The next log 2024-10-03 15:40:54:815 (binc_internal_signal_characteristic_changed) reverts to using the default adapter name on the server "pi5dev #1" This sticks afterwards.

    //******************************************************************
    // Configure as client
    // Set discovery filter
    service_uuids = g_ptr_array_new();
    g_ptr_array_add( service_uuids, HRS_SERVICE_UUID );
    g_ptr_array_add( service_uuids, CSCS_SERVICE_UUID );
    g_ptr_array_add( service_uuids, CPS_SERVICE_UUID );

    // Initialize central as client and start discovery (acttually ignoring these filter settings and using NULL, NULL)
    if( client_init( &client_s, "hci0", service_uuids, pattern ) != 0 )
    {
        printf( "Error initializing client\n" );
        client_close( &client_s );
        close_gloop( &loop );
        exit( -1 );
    }

in client_init()

    // Connect to DBus, locate adapter and ensure powered on
    if( (p_client_s->dbusConnection = g_bus_get_sync( G_BUS_TYPE_SYSTEM, NULL, NULL )) == NULL ){
        log_error( TAG, KRED"Failed to get DBus connection"KNRM );
        return( -1 );
    }
    else{
        if( ( p_client_s->adapter = binc_adapter_get( p_client_s->dbusConnection, adapter_name ) ) == NULL ){
            log_error( TAG, KRED"Adapter not found"KNRM );
            g_object_unref( p_client_s->dbusConnection );
            return( -1 );
        }
        else{
            log_debug( TAG, DCOLOR"Client using adapter %s [%s]"KNRM, binc_adapter_get_name( p_client_s->adapter ), binc_adapter_get_address( p_client_s->adapter ) );
            binc_adapter_set_powered_state_cb( p_client_s->adapter, &on_central_powered_state_changed );
            if( !binc_adapter_get_powered_state( p_client_s->adapter ) ){
                binc_adapter_power_on( p_client_s->adapter );
                log_debug( TAG, DCOLOR"Powering on adapter '%s'"KNRM, binc_adapter_get_path( p_client_s->adapter ) );
            }
        }
    }

    // Agent
    p_client_s->agent = binc_agent_create( p_client_s->adapter, "/org/bluez/BincAgent", NO_INPUT_NO_OUTPUT );
    binc_agent_set_request_authorization_cb( p_client_s->agent, &on_central_request_authorization );
    binc_agent_set_request_passkey_cb( p_client_s->agent, &on_central_request_passkey );

    // Device callbacks set when services resolved

    // Adapter
    binc_adapter_set_discovery_cb( p_client_s->adapter, &on_central_scan_result );
    binc_adapter_set_discovery_state_cb( p_client_s->adapter, &on_central_discovery_state_changed );

    log_debug( TAG, DCOLOR"Setting discovery filter to '%s'"KNRM, NULL );
    binc_adapter_set_discovery_filter( p_client_s->adapter, -100, NULL, NULL );
    binc_adapter_start_discovery( p_client_s->adapter );