This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

How to notify several characteristics in central

Hi, I am using ble_app_hrs_c as the base for central. I have included 5 characteristics in the peripheral and central side. How to make ble_nus_c_rx_notif_enable() to notify when any of the 5 characteristics is updated? At the moment, ble_nus_c_rx_notif_enable has only this: return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_rx_cccd_handle, true);

How do I change it so that I get notification even when nus_rx_wheel_status_handle also receives a notification? My ble_nus_c_handles_t looks like this:

typedef struct {
    uint16_t                nus_rx_wheel_control_handle;      

    uint16_t                nus_rx_wheel_control_cccd_handle; /**< Handle of the CCCD of the NUS RX characteristic as provided by a discovery. */
    uint16_t                nus_rx_wheel_status_handle;	
    uint16_t                nus_rx_wheel_status_cccd_handle;	
    uint16_t                nus_rx_wheel_battery_handle;	
    uint16_t                nus_rx_wheel_battery_cccd_handle;		
    uint16_t                nus_rx_wheel_information_handle;	
    uint16_t                nus_rx_wheel_information_cccd_handle;		
    uint16_t                nus_rx_wheel_debug_handle;	
    uint16_t                nus_rx_wheel_debug_cccd_handle;		
    uint16_t                nus_tx_handle_wheel_control;      /**< Handle of the NUS TX characteristic as provided by a discovery. */
    uint16_t                nus_tx_handle_wheel_status;	
    uint16_t                nus_tx_handle_wheel_battery;	
    uint16_t                nus_tx_handle_wheel_information;		
    uint16_t                nus_tx_handle_wheel_debug;		
} ble_nus_c_handles_t;

The code works fine when I enable notification for one character at a time.

Parents Reply Children
  • Hi Petter, Thanks for the reply. But, I need to get notifications at the central code, whenever a characteristic gets written by any of the peripherals that are already in connected mode with the central.

  • Ok. What is the problem? Have you enabled notifications in all peripherals by writing to their CCCD?

  • Hi Petter, Thanks for the reply. Yes, I am enabling the read and write permissions to the peripherals for all the characteristics. I use the following for adding all characteristics at the peripheral side:

    static uint32_t rx_char_add_information(ble_nus_t * p_nus, const ble_nus_init_t * p_nus_init)
    {
        /**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_md_t cccd_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.notify = 1;
        char_md.p_char_user_desc  = NULL;
        char_md.p_char_pf         = NULL;
        char_md.p_user_desc_md    = NULL;
        char_md.p_cccd_md         = &cccd_md;
        char_md.p_sccd_md         = NULL;
    
        ble_uuid.type = p_nus->uuid_type;
        ble_uuid.uuid = BLE_UUID_NUS_RX_INFORMATION_CHARACTERISTIC;
    
        memset(&attr_md, 0, sizeof(attr_md));
    
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
    
        attr_md.vloc    = BLE_GATTS_VLOC_STACK;
        attr_md.rd_auth = 0;
        attr_md.wr_auth = 0;
        attr_md.vlen    = 1;
    
        memset(&attr_char_value, 0, sizeof(attr_char_value));
    
        attr_char_value.p_uuid    = &ble_uuid;
        attr_char_value.p_attr_md = &attr_md;
        attr_char_value.init_len  = sizeof(uint8_t);
        attr_char_value.init_offs = 0;
        attr_char_value.max_len   = BLE_NUS_MAX_RX_CHAR_LEN;
    
        return sd_ble_gatts_characteristic_add(p_nus->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_nus->rx_handles_information);
        /**@snippet [Adding proprietary characteristic to S110 SoftDevice] */
    }
    

    But, at the central side, I get notified when a peripheral has written to one particular characteristic(which is the same characteristic used in ble_nus_c_rx_notif_enable). In other words, I dont get notified at the central end when the peripheral writes to the any characteristic that is not used in ble_nus_c_rx_notif_enable.

  • I am not talking about enabling read and write permissions, I'm talking about the client (central) enabling notifications by writing 0x0001 to the CCCD of the characteristics you want to notify.

    Have you done this on all characteristics you want to be able to notify? Or only one?

  • Hi Petter, Thanks for the reply. In the central code, in the ble_nus_c_rx_notif_enable, I have configured only one of the characteristics as shown below:

    uint32_t ble_nus_c_rx_notif_enable(ble_nus_c_t * p_ble_nus_c)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus_c);
    
        if ( (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID)
           ||(p_ble_nus_c->handles.nus_rx_debug_cccd_handle == BLE_GATT_HANDLE_INVALID)
    			||(p_ble_nus_c->handles.nus_rx_speed_cccd_handle == BLE_GATT_HANDLE_INVALID)
    			||(p_ble_nus_c->handles.nus_rx_information_cccd_handle == BLE_GATT_HANDLE_INVALID)
           )
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
    		return cccd_configure(p_ble_nus_c->conn_handle,p_ble_nus_c->handles.nus_rx_speed_cccd_handle, true);
    
    }
    

    I have configured only for 1 characteristic in ble_nus_c_rx_notif_enable because, if I configure for more than 1 characteristic, I get NRF_ERROR_BUSY error. Also, upon discovery event, I assign cccd handles for all the characteristics as shown below:

    void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt)
    {
        ble_nus_c_evt_t nus_c_evt;
        memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t));
    
        ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics;
    
        // Check if the NUS was discovered.
        if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE &&
            p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_NUS_SERVICE &&
            p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type)
        {
    
            uint32_t i;
    
            for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
            {
                switch (p_chars[i].characteristic.uuid.uuid)
                {
    
                    case BLE_UUID_NUS_RX_SPEED_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_speed_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_rx_speed_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    case BLE_UUID_NUS_TX_SPEED_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle_speed = p_chars[i].characteristic.handle_value;
                        break;
    								
                    case BLE_UUID_NUS_RX_INFORMATION_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_information_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_rx_information_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    case BLE_UUID_NUS_TX_INFORMATION_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle_information = p_chars[i].characteristic.handle_value;
                        break;								
    
    								
                    case BLE_UUID_NUS_RX_DEBUG_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_debug_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_rx_debug_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    case BLE_UUID_NUS_TX_DEBUG_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle_debug = p_chars[i].characteristic.handle_value;
                        break;		
    
                    case BLE_UUID_NUS_RX_CONTROL_CHARACTERISTIC:
                        nus_c_evt.handles.nus_rx_control_handle = p_chars[i].characteristic.handle_value;
                        nus_c_evt.handles.nus_rx_control_cccd_handle = p_chars[i].cccd_handle;
                        break;
    
                    case BLE_UUID_NUS_TX_CONTROL_CHARACTERISTIC:
                        nus_c_evt.handles.nus_tx_handle_control = p_chars[i].characteristic.handle_value;
                        break;									
    								
    
                    default:
                        break;
                }
            }
            if (p_ble_nus_c->evt_handler != NULL)
            {
                nus_c_evt.conn_handle = p_evt->conn_handle;
                nus_c_evt.evt_type    = BLE_NUS_C_EVT_DISCOVERY_COMPLETE;
                p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt);
            }
        }
    }
    

    Also I have used the following routines:

    static uint32_t cccd_configure(uint16_t conn_handle, uint16_t cccd_handle, bool enable)
    {
        uint8_t buf[BLE_CCCD_VALUE_LEN];
    
        buf[0] = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
        buf[1] = 0;
    
        const ble_gattc_write_params_t write_params = {
            .write_op = BLE_GATT_OP_WRITE_REQ,
            .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
            .handle   = cccd_handle,
            .offset   = 0,
            .len      = sizeof(buf),
            .p_value  = buf
        };
    
        return sd_ble_gattc_write(conn_handle, &write_params);
    }
    
    uint32_t ble_nus_c_handles_assign(ble_nus_c_t * p_ble_nus,
                                      const uint16_t conn_handle,
                                      const ble_nus_c_handles_t * p_peer_handles)
    {
        VERIFY_PARAM_NOT_NULL(p_ble_nus);
    
        p_ble_nus->conn_handle = conn_handle;
        if (p_peer_handles != NULL)
        {
            p_ble_nus->handles.nus_rx_control_cccd_handle = p_peer_handles->nus_rx_control_cccd_handle;
            p_ble_nus->handles.nus_rx_control_handle      = p_peer_handles->nus_rx_control_handle;
            p_ble_nus->handles.nus_tx_handle_control      = p_peer_handles->nus_tx_handle_control;
    			
            p_ble_nus->handles.nus_rx_speed_cccd_handle = p_peer_handles->nus_rx_speed_cccd_handle;
            p_ble_nus->handles.nus_rx_speed_handle      = p_peer_handles->nus_rx_speed_handle;
            p_ble_nus->handles.nus_tx_handle_speed      = p_peer_handles->nus_tx_handle_speed;		
    			
            p_ble_nus->handles.nus_rx_information_cccd_handle = p_peer_handles->nus_rx_information_cccd_handle;
            p_ble_nus->handles.nus_rx_information_handle      = p_peer_handles->nus_rx_information_handle;
            p_ble_nus->handles.nus_tx_handle_information      = p_peer_handles->nus_tx_handle_information;				
    			
    
            p_ble_nus->handles.nus_rx_debug_cccd_handle = p_peer_handles->nus_rx_debug_cccd_handle;
            p_ble_nus->handles.nus_rx_debug_handle      = p_peer_handles->nus_rx_debug_handle;
            p_ble_nus->handles.nus_tx_handle_debug      = p_peer_handles->nus_tx_handle_debug;			
        }
        return NRF_SUCCESS;
    }
    
Related