This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Adding custom service to sample peripheral_dis

SDK Environment: nRF Connect SDK v1.7.1

Target: Decawave DWM1001-DEV. This uses the nRF52832

Simon posted in this discussion an example of adding a custom service to the sample peripheral_dis

When I ran this example I did not get a notification. my_service_send is not called.

I added the following to the end of main()

    uint32_t number = 0;
    for (;;) {
        // Main loop
        my_service_send(my_connection, (uint8_t *)&number, sizeof(number));
        number++;
        k_sleep(K_MSEC(1000)); // 1000ms
    }

This still did not send the notification, so I added CONFIG_ASSERT=y to proj.conf. When run I got an assertion fault.

I then removed the first BT_GATT_CC in BT_GATT_SERVICE_DEFINE

I also changed the index in the line const struct bt_gatt_attr *attr = &my_service.attrs[4]; from 4 to 2; This seemed to better match the comments above in the code, as well as this tutorial. I am still getting an assertion fault when run.

I have added my complete project in the attached zip file.

I initially built this with west build -b decawave_dwm1001_dev2 -d build2 -- -DBOARD_ROOT=\ncs\myapps\peripheral_dis_test1

When run I get the following:

*** Booting Zephyr OS build v2.6.99-ncs1-1  ***
[00:00:00.001,098] <inf> sdc_hci_driver: SoftDevice Controller build revision:
                                         3f 47 70 8e 81 95 4e 86  9d d3 a2 95 88 f6 30 0a |?Gp...N. ......0.
                                         7f 53 49 fd                                      |.SI.
[00:00:00.006,195] <inf> bt_hci_core: No ID address. App must call settings_load()
[00:00:00.009,918] <err> bt_gatt: Failed to save Database Hash (err -2)
Bluetooth initialized
Advertising successfully started
ASSERTION FAIL [conn] @ WEST_TOPDIR/zephyr/subsys/bluetooth/host/gatt.c:2653
        invalid parameter

[00:00:00.012,420] <err> os: r0/a1:  0x00000004  r1/a2:  0x00000a5d  r2/a3:  0x00000008
[00:00:00.012,420] <err> os: r3/a4:  0x00000000 r12/ip:  0x00000000 r14/lr:  0x0001aebb
[00:00:00.012,451] <err> os:  xpsr:  0x41000000
[00:00:00.012,451] <err> os: Faulting instruction address (r15/pc): 0x00024400
[00:00:00.012,451] <err> os: >>> ZEPHYR FATAL ERROR 4: Kernel panic on CPU 0
[00:00:00.012,481] <err> os: Current thread: 0x20001e40 (main)
[00:00:01.732,971] <err> fatal_error: Resetting system

I have posted a separate query about the line  [00:00:00.009,918] <err> bt_gatt: Failed to save Database Hash (err -2). I don't know if this is related or not.

The assertion fail happens when bt_gatt_is_subscribed is called.

peripheral_dis_test1.zip

  • I made some changes to "my_service.c" and the code now seems to work if I don't set CONFIG_ASSERT=y in "prj.conf".

    If I set CONFIG_ASSERT=y in "prj.conf", the code still fails with an assertion error when bt_gatt_is_subscribed is called.

    I updated the GATT service definition to

    /* Service Declaration and Registration */
    BT_GATT_SERVICE_DEFINE(my_service,
        // Primary service
        BT_GATT_PRIMARY_SERVICE(BT_UUID_MY_SERVICE),
        // Custom service SEND_CHAR characteristic.
        // Properties Notify, Read.
        BT_GATT_CHARACTERISTIC(SEND_CHAR, BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ, NULL, NULL, NULL),
        BT_GATT_CCC(on_cccd_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
        // Custom service RECV_CHAR characteristic.
        // Properties Write.
        BT_GATT_CHARACTERISTIC(RECV_CHAR, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, on_receive, NULL), );

    I also changed the index into the attribute table to 1 in this line const struct bt_gatt_attr *attr = &my_service.attrs[1]; so that it now points to the Characteristic Declaration for SEND_CHAR

    "my_service.c" now looks like the following:

    #include <errno.h>
    #include <soc.h>
    #include <stddef.h>
    #include <string.h>
    #include <sys/byteorder.h>
    #include <sys/printk.h>
    #include <zephyr.h>
    #include <zephyr/types.h>
    
    #include <bluetooth/addr.h>
    #include <bluetooth/bluetooth.h>
    #include <bluetooth/conn.h>
    #include <bluetooth/gatt.h>
    #include <bluetooth/hci.h>
    #include <bluetooth/uuid.h>
    
    #include "my_service.h"
    
    #define BT_UUID_MY_SERVICE BT_UUID_DECLARE_128(MY_SERVICE_UUID)
    #define SEND_CHAR BT_UUID_DECLARE_128(SEND_CHARACTERISTIC)
    #define RECV_CHAR BT_UUID_DECLARE_128(RECEIVE_CHARACTERISTIC)
    #define MAX_TRANSMIT_SIZE 240
    
    uint8_t data_rx[MAX_TRANSMIT_SIZE];
    uint8_t data_tx[MAX_TRANSMIT_SIZE];
    
    static climb_received_cb_t received_cb;
    static notif_func notification_function;
    
    static ssize_t on_receive(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf,
                              uint16_t len, uint16_t offset, uint8_t flags)
    {
        // const uint8_t * buffer = buf;
    
        if (received_cb) {
            received_cb(conn, buf, len);
        }
    
        return len;
    }
    
    /* This function is called whenever a Notification has been sent by the TX Characteristic */
    static void on_sent(struct bt_conn *conn, void *user_data)
    {
        ARG_UNUSED(user_data);
    
        const bt_addr_le_t *addr = bt_conn_get_dst(conn);
    
        printk("Data sent to Address 0x %02X %02X %02X %02X %02X %02X \n", addr->a.val[0],
               addr->a.val[1], addr->a.val[2], addr->a.val[3], addr->a.val[4], addr->a.val[5]);
    }
    
    /* This function is called whenever the CCCD register has been changed by the client*/
    void on_cccd_changed(const struct bt_gatt_attr *attr, uint16_t value)
    {
        // ARG_UNUSED(attr);
        switch (value) {
        case BT_GATT_CCC_NOTIFY:
            // Start sending stuff!
            printk("enabled notification on %d\n", attr->handle);
            if (notification_function) {
                notification_function();
            }
            break;
    
        case BT_GATT_CCC_INDICATE:
            // Start sending stuff via indications
            break;
    
        case 0:
            // Stop sending stuff
            break;
    
        default:
            printk("Error, CCCD has been set to an invalid value");
        }
    }
    
    /* Service Declaration and Registration */
    BT_GATT_SERVICE_DEFINE(my_service,
        // Primary service
        BT_GATT_PRIMARY_SERVICE(BT_UUID_MY_SERVICE),
        // Custom service SEND_CHAR characteristic.
        // Properties Notify, Read.
        BT_GATT_CHARACTERISTIC(SEND_CHAR, BT_GATT_CHRC_NOTIFY, NULL, NULL, NULL),
        BT_GATT_CCC(on_cccd_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
        // Custom service RECV_CHAR characteristic.
        // Properties Write.
        BT_GATT_CHARACTERISTIC(RECV_CHAR, BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                               BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, NULL, on_receive, NULL), );
    
    int my_service_init(climb_received_cb_t rec_cb, notif_func notif_func)
    {
        received_cb = rec_cb;
    
        notification_function = notif_func;
        int err = 0;
        memset(&data_rx, 0, MAX_TRANSMIT_SIZE);
        memset(&data_tx, 0, MAX_TRANSMIT_SIZE);
        return err;
    }
    
    /* This function sends a notification to a Client with the provided data,
    given that the Client Characteristic Control Descripter has been set to Notify (0x1).
    It also calls the on_sent() callback if successful*/
    void my_service_send(struct bt_conn *conn, const uint8_t *data, uint16_t len)
    {
        /*
        The attribute for the TX characteristic is used with bt_gatt_is_subscribed
        to check whether notification has been enabled by the peer or not.
        Attribute table: 0 = Primary service, 1 = TX, 3 = CCC, 4 = RX.
        */
        const struct bt_gatt_attr *attr = &my_service.attrs[1];
    
        struct bt_gatt_notify_params params = {
            .uuid = SEND_CHAR, .attr = attr, .data = data, .len = len, .func = on_sent};
        // Check whether notifications are enabled or not
        if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) {
            // Send the notification
            if (bt_gatt_notify_cb(conn, &params)) {
                printk("Error, unable to send notification\n");
            }
        } else {
            printk("Warning, notification not enabled on the selected attribute\n");
        }
    }
    

  • Try modifying your for loop in main.c accordingly:

    for (;;) {
        // Main loop
        if(my_connection){
            my_service_send(my_connection, (uint8_t *)&number, sizeof(number));
            number++;
        }
        k_sleep(K_MSEC(1000)); // 1000ms
    }

    Then your application should run fine with CONFIG=ASSERT=n. The reason it fails for you is that you're trying to send out data wihout being connected to any device (my_connection is 0), and that will trigger the assert __ASSERT(conn, "invalid parameter\n") in gatt.c.

    The device the nRF52832 is connected to also needs to enable to enable notifications for the characteristic being notified.

    Best regards,

    Simon

  • Thanks that does fix the problem. However the program was not getting as far as trying to send out data. The assert was happening on the line if (bt_gatt_is_subscribed(conn, attr, BT_GATT_CCC_NOTIFY)) { in my_service.c

    Without CONFIG_ASSERT=y, bt_gatt_is_subscribed does return false when there is no connection.

Related