How to implement a write handler in nRF Connect SDK?

Hi,

Perhaps this question is too basic, but I haven't been able to find this anywhere.

I've followed this tutorial successfully with an nRF52832 DK:  nRF Connect SDK Bluetooth Low Energy tutorial part 1: Custom Service in Peripheral role

However, I'm missing the part about how to implement a peripheral write handler. In other words, how to make writing to a characteristic operate on a uC peripheral; something as simple as turning on/off a GPIO by writing 1/0 to a characteristic.

In this tutorial (using the old nRF SDK) it is clear how to implement this write handler and initialize it: https://novelbits.io/smart-ble-lightbulb-application-nrf52/. The function in question is the "static void led_write_handler" function that receives a led state uint8_t, and is able to write to an LED. Furthermore, it also shows how to declare a function pointer to it within structure linked to the service and how to initialize it from the main.c

My question is: how can I implement such a function and "register" it with the service? If there's a tutorial that shows how to do it, I'd greatly appreciate it.

Thanks in advance for your help



Parents
  • Hello,

    In the guide you refer to, look at Step 4, where you create your services and characteristics:

    /* LED Button Service Declaration and Registration */
    BT_GATT_SERVICE_DEFINE(my_service,
    BT_GATT_PRIMARY_SERVICE(BT_UUID_MY_SERIVCE),
    BT_GATT_CHARACTERISTIC(BT_UUID_MY_SERIVCE_RX,
    			       BT_GATT_CHRC_WRITE | BT_GATT_CHRC_WRITE_WITHOUT_RESP,
    			       BT_GATT_PERM_READ | BT_GATT_PERM_WRITE, 
                       NULL, on_receive, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_MY_SERIVCE_TX,
    			       BT_GATT_CHRC_NOTIFY,
    			       BT_GATT_PERM_READ,
                       NULL, NULL, NULL),
    BT_GATT_CCC(lbslc_ccc_cfg_changed,
            BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
    );

    On line 7 in that snippet, there is a parameter: "on_receive", which is a function pointer to the function that is triggered when the connected device writes to that characteristic.It can be implemented the way it is in the snippet right below that:

    /* This function is called whenever the RX Characteristic has been written to by a Client */
    static ssize_t on_receive(struct bt_conn *conn,
    			  const struct bt_gatt_attr *attr,
    			  const void *buf,
    			  u16_t len,
    			  u16_t offset,
    			  u8_t flags)
    {
        const u8_t * buffer = buf;
        
    	printk("Received data, handle %d, conn %p, data: 0x", attr->handle, conn);
        for(u8_t i = 0; i < len; i++){
            printk("%02X", buffer[i]);
        }
        printk("\n");
    
    	return len;
    }

    So that function will be triggered whenever a connected device writes to the characteristic. Is that what you were looking for? Or do you need/want the callback to be in your main.c function? In that case, I happen to have a github repository that I used for a course at some point, where I did something similar, except that we forward the interrupt to a callback function in main.c. Feel free to have a look:

    https://github.com/edvinand/OmegaV_BLE_Course/tree/main/remote_controller/src

    Look at how I forwarded custom callback functions (remote_callbacks) in to the bluetooth_init() function in main(), and how these are used inside the remote.c file, inside the on_write() callback. In that case, you can use the callback function in main.c to toggle an LED or GPIO.

    Best regards,

    Edvin

  • Also, why didn't you register the "button_value" variable into the user_data field when registering your BT_UUID_REMOTE_BUTTON_CHRC characteristic? Sounds like it would've been the cleanest thing to do.

Reply Children
No Data
Related