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

CUSTOM BLE SERVICE : READ WRITE RESPONSE

Hi, I am creating custom ble service.there i need to perform

1. character   -  READ , NOTIF

2. character   -  WRITE READ

3. character  -   READ,WRITE, NOTIF

I achieved - WRITE.  but i am unable to read the response

Here i upload the example code that i have used.

IF THE BUTTON PRESSED  value 0x01 . if released 0x00.

when the NOTIF enabled it works perfect. but when i want to read the current data if the notif in disabled it shows " ERROR 2 : GATT READ NOT PERMITTED "

static void on_connect(ble_uis_t * p_uis, ble_evt_t const * p_ble_evt)
{
    p_uis->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}

static void on_disconnect(ble_uis_t * p_uis, ble_evt_t const * p_ble_evt)
{
    UNUSED_PARAMETER(p_ble_evt);
    p_uis->conn_handle = BLE_CONN_HANDLE_INVALID;
}

static void on_write(ble_uis_t * p_uis, ble_evt_t const * p_ble_evt)
{
    ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
    

    if ( (p_evt_write->handle == p_uis->button_char_handles.cccd_handle) &&
         (p_evt_write->len == 2) )
    {
        ble_device_evt_t    evt;

        if (ble_srv_is_notification_enabled(p_evt_write->data))
        {
            p_uis->is_button_notif_enabled = true;
            evt.evt_type = BLE_DEVICE_EVT_NOTIFICATION_ENABLED;
           
        }
        else
        {
            p_uis->is_button_notif_enabled = false;
            evt.evt_type = BLE_DEVICE_EVT_NOTIFICATION_DISABLED;
        }
        evt.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
         p_uis->evt_handler(p_uis, &evt);
    }
    else
    {
        // Do Nothing. This event is not relevant for this service.
    }
}


void ble_uis_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
    ble_uis_t * p_uis = (ble_uis_t *) p_context;

    if ((p_uis == NULL) || (p_ble_evt == NULL))
    {
        return;
    }

    switch (p_ble_evt->header.evt_id)
    {
        case BLE_GAP_EVT_CONNECTED:
            on_connect(p_uis, p_ble_evt);
            NRF_LOG_INFO("BLE UI connected\r\n");
            break;

        case BLE_GAP_EVT_DISCONNECTED:
            on_disconnect(p_uis, p_ble_evt);
            break;

        case BLE_GATTS_EVT_WRITE:
            on_write(p_uis, p_ble_evt);
            break;

        case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
            on_authorize_req(p_uis, p_ble_evt);
            break;

        default:
            // No implementation needed.
            break;
    }
}
static uint32_t button_char_add(ble_uis_t * p_uis, const ble_uis_init_t * p_uis_init)
{
    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;
    uint8_t            init_value = 0;
    init_value  =   p_uis_init->charge;

    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.read   = 1;
   // char_md.char_props.write  = 1;
    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_uis->uuid_type;
    ble_uuid.uuid = BLE_CHARGE_CHAR;

    memset(&attr_md, 0, sizeof(attr_md));

    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);

    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    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      = sizeof(uint8_t);
    attr_char_value.p_value      = ((uint8_t *)(&init_value));
    

    return sd_ble_gatts_characteristic_add(p_uis->service_handle,
                                          &char_md,
                                          &attr_char_value,
                                          &p_uis->button_char_handles);
}


static uint32_t led_char_add(ble_uis_t * p_uis, const ble_uis_init_t * p_uis_init)
{
    ble_gatts_char_md_t char_md;
    ble_gatts_attr_t    attr_char_value;
    ble_uuid_t          ble_uuid;
    ble_gatts_attr_md_t attr_md;

    memset(&char_md, 0, sizeof(char_md));

    char_md.char_props.read   = 1;
    char_md.char_props.write  = 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         = NULL;
    char_md.p_sccd_md         = NULL;

    ble_uuid.type = p_uis->uuid_type;
    ble_uuid.uuid = BLE_LED_CONFIG_CHAR;

    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    = 1;
    attr_md.vlen       = 0;

    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(ble_uis_led_t);
    attr_char_value.init_offs    = 0;
    attr_char_value.max_len      = sizeof(ble_uis_led_t);;
    attr_char_value.p_value      = ((uint8_t *)(p_uis_init->p_init_led));


    return sd_ble_gatts_characteristic_add(p_uis->service_handle,
                                           &char_md,
                                           &attr_char_value,
                                           &p_uis->led_char_handles);
}


uint32_t ble_uis_init(ble_uis_t * p_uis, const ble_uis_init_t * p_uis_init)
{
    uint32_t   err_code;
    ble_uuid_t ble_uuid;

    // Initialize service structure.
    p_uis->conn_handle             = BLE_CONN_HANDLE_INVALID;
    p_uis->evt_handler             =  p_uis_init->evt_handler;
    p_uis->led_write_handler       = p_uis_init->led_write_handler;
   
    p_uis->is_button_notif_enabled = false;
    // Add service.
    ble_uuid128_t base_uuid = LSPOT_BASE_UUID;
    err_code = sd_ble_uuid_vs_add(&base_uuid, &p_uis->uuid_type);
    VERIFY_SUCCESS(err_code);

    ble_uuid.type = p_uis->uuid_type;
    ble_uuid.uuid = BLE_IO_SERVICE;

    err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_uis->service_handle);
    VERIFY_SUCCESS(err_code);

    // Add characteristics.
    err_code = button_char_add(p_uis, p_uis_init);
    VERIFY_SUCCESS(err_code);
 

    err_code = led_char_add(p_uis, p_uis_init);
    VERIFY_SUCCESS(err_code);

   

    return NRF_SUCCESS;
}


uint32_t ble_uis_on_button_change(ble_uis_t * p_uis, uint8_t buttons_state)
{
    ble_gatts_hvx_params_t params;
    uint16_t len = sizeof(buttons_state);

    VERIFY_PARAM_NOT_NULL(p_uis);

    if ((p_uis->conn_handle == BLE_CONN_HANDLE_INVALID) || (!p_uis->is_button_notif_enabled))
    {
        return NRF_ERROR_INVALID_STATE;
    }

    memset(&params, 0, sizeof(params));
    params.type = BLE_GATT_HVX_NOTIFICATION;
    params.handle = p_uis->button_char_handles.value_handle;
    params.p_data = (uint8_t *)(&buttons_state);
    params.p_len = &len;

    return sd_ble_gatts_hvx(p_uis->conn_handle, &params);
}

please check here what is the problem

static uint32_t button_char_add(ble_uis_t * p_uis, const ble_uis_init_t * p_uis_init)
{
    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;
    uint8_t            init_value = 0;
    init_value  =   p_uis_init->charge;

    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.read   = 1;
   // char_md.char_props.write  = 1;
    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_uis->uuid_type;
    ble_uuid.uuid = BLE_CHARGE_CHAR;

    memset(&attr_md, 0, sizeof(attr_md));

    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);

    attr_md.vloc       = BLE_GATTS_VLOC_STACK;
    attr_md.rd_auth    = 0;
    attr_md.wr_auth    = 0;
    attr_md.vlen       = 0;

    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      = sizeof(uint8_t);
    attr_char_value.p_value      = ((uint8_t *)(&init_value));
    

    return sd_ble_gatts_characteristic_add(p_uis->service_handle,
                                          &char_md,
                                          &attr_char_value,
                                          &p_uis->button_char_handles);
}

NOTIF ENABLED :

WHEN READ BUTTON PRESSED:

  • Hi Sunil, 
    You set 

    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);

    So both read and write permission are not allowed. This explain why you can't read. Note that permission is different from properties. Properties is the information the peer can get from the server, but the permission is the actual configuration of the read/write attribute. 

    You need to set 

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); 

    instead. 

  • Hi Hung,

    Ok , I will tried this

    "BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm); "   its working but

    i received "ldr r3, [pc, #4] " while i force to write the data.

    I received this error while

    if ( valid_data )
                {
                   p_motion->calib_write_handler(p_motion,(ble_calibrate_t *)p_evt_rw_authorize_request->request.write.data);
                }

    But when i use these line it doesn't entered into the calib_write_handler it means that calib_write_handler is NULL. how to make this as not equal to NULL.

    if ( valid_data && (p_motion->calib_write_handler != NULL))
                {
                   p_motion->calib_write_handler(p_motion,(ble_calibrate_t *)p_evt_rw_authorize_request->request.write.data);
                }

    the respective code sequence is below

    ble_motion.c

    ...
    ....
    
    
    static void on_authorize_req(ble_motion_t * p_motion, ble_evt_t const * p_ble_evt)
    {
        ble_gatts_evt_rw_authorize_request_t const * p_evt_rw_authorize_request = &p_ble_evt->evt.gatts_evt.params.authorize_request;
        uint32_t err_code;
    
        if (p_evt_rw_authorize_request->type  == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
        {
             if (p_evt_rw_authorize_request->request.write.handle == p_motion->calibrate_char_handles.value_handle)
            {
                ble_gatts_rw_authorize_reply_params_t rw_authorize_reply;
                bool                                  valid_data = true;
                uint16_t                              data_length = p_evt_rw_authorize_request->request.write.len;
    
                // Check for valid data
                if (data_length != sizeof(ble_calibrate_t))
                {
                    valid_data = false;
                }
                else
                {
                    ble_calibrate_t * p_calib = (ble_calibrate_t *)p_evt_rw_authorize_request->request.write.data;
    
                    if ( ((p_calib->calibrate > 0) && (p_calib->calibrate < 255)))
                       
                         
                    {
                        valid_data = false;
                    }
                }
    
                rw_authorize_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
    
                if (valid_data)
                {
                    rw_authorize_reply.params.write.update      = 1;
                    rw_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
                    rw_authorize_reply.params.write.p_data      = p_evt_rw_authorize_request->request.write.data;
                    rw_authorize_reply.params.write.len         = p_evt_rw_authorize_request->request.write.len;
                    rw_authorize_reply.params.write.offset      = p_evt_rw_authorize_request->request.write.offset;
                }
                else
                {
                    rw_authorize_reply.params.write.update      = 0;
                    rw_authorize_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED;
                }
    
                err_code = sd_ble_gatts_rw_authorize_reply(p_ble_evt->evt.gatts_evt.conn_handle,
                                                           &rw_authorize_reply);
                APP_ERROR_CHECK(err_code);
    
                if ( valid_data && (p_motion->calib_write_handler != NULL))
                {
                   p_motion->calib_write_handler(p_motion,(ble_calibrate_t *)p_evt_rw_authorize_request->request.write.data);
                }
            }
            
        }
    }
    
    ...
    ...
    
    
    static uint32_t calibrate_char_add(ble_motion_t * p_motion, const ble_motion_init_t * p_motion_init)
    {
        ble_gatts_char_md_t char_md;
        ble_gatts_attr_t    attr_char_value;
        ble_uuid_t          ble_uuid;
        ble_gatts_attr_md_t attr_md;
    
        memset(&char_md, 0, sizeof(char_md));
    
        char_md.char_props.read          = 1;
        char_md.char_props.write         = 1;
        char_md.char_props.write_wo_resp = 0;
        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                = NULL;
        char_md.p_sccd_md                = NULL;
    
        ble_uuid.type = p_motion->uuid_type;
        ble_uuid.uuid = BLE_CALIBRATE_CHAR;
    
        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    = 1;
        attr_md.vlen       = 0;
    
        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(ble_calibrate_t);
        attr_char_value.init_offs    = 0;
        attr_char_value.max_len      = sizeof(ble_calibrate_t);;
        attr_char_value.p_value      = ((uint8_t *)(&p_motion_init->init_calibrate));
    
        return sd_ble_gatts_characteristic_add(p_motion->service_handle,
                                               &char_md,
                                               &attr_char_value,
                                               &p_motion->calibrate_char_handles);
    }
    
    
    void ble_motion_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
    {
        ble_motion_t * p_motion = (ble_motion_t *) p_context;
    
        if ((p_motion == NULL) || (p_ble_evt == NULL))
        {
            return;
        }
    
        switch (p_ble_evt->header.evt_id)
        {
            case BLE_GAP_EVT_CONNECTED:
                on_connect(p_motion, p_ble_evt);
                NRF_LOG_INFO("BLE UI connected\r\n");
                break;
    
            case BLE_GAP_EVT_DISCONNECTED:
                on_disconnect(p_motion, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_WRITE:
                on_write(p_motion, p_ble_evt);
                break;
    
            case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
                on_authorize_req(p_motion, p_ble_evt);
                break;
    
            default:
                // No implementation needed.
                break;
        }
    }
    
    
    
    
    uint32_t ble_motion_init(ble_motion_t * p_motion, const ble_motion_init_t * p_motion_init)
    {
        uint32_t   err_code;
        ble_uuid_t ble_uuid;
    
        // Initialize service structure.
        p_motion->conn_handle             = BLE_CONN_HANDLE_INVALID;
    //    p_motion->evt_handler             =  p_motion_init->evt_handler;
       
    
        ble_uuid128_t base_uuid = LSPOT_BASE_UUID;
        err_code = sd_ble_uuid_vs_add(&base_uuid, &p_motion->uuid_type);
        VERIFY_SUCCESS(err_code);
    
        ble_uuid.type = p_motion->uuid_type;
        ble_uuid.uuid = BLE_MOTION_SERVICE;
    
        err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_motion->service_handle);
        VERIFY_SUCCESS(err_code);
    
        // Add characteristics.
        err_code = raw_data_char_add(p_motion, p_motion_init);
        VERIFY_SUCCESS(err_code);
    
         err_code = current_char_add(p_motion, p_motion_init);
        VERIFY_SUCCESS(err_code);
    
    
        err_code = calibrate_char_add(p_motion, p_motion_init);
        VERIFY_SUCCESS(err_code);
    
    
        return NRF_SUCCESS;
    }
    
    
    

    ble_motion.h

    .
    ...
    ...
    
    typedef PACKED( struct
    {
        uint8_t calibrate;  /**< Transisior 1 */
       
    }) ble_calibrate_t;
    
    typedef struct ble_motion_s          ble_motion_t;
    
    typedef void (*ble_calibrate_write_handler_t) (ble_motion_t * p_motion, ble_calibrate_t * calib);
    
    typedef struct
    {
        ble_current_t                   init_current;
        ble_calibrate_t                 init_calibrate;
        ble_calibrate_write_handler_t   calib_write_handler;
        
    } ble_motion_init_t;
    
    
    struct ble_motion_s
    {
        uint16_t                    service_handle;  
        uint8_t                     uuid_type;                 
        uint16_t                    conn_handle; 
        ble_gatts_char_handles_t    raw_data_char_handles;          
        ble_gatts_char_handles_t    threshold_char_handles;          
        ble_gatts_char_handles_t    side_current_char_handles;       
        ble_gatts_char_handles_t    front_current_char_handles;       
        ble_gatts_char_handles_t    calibrate_char_handles;       
        ble_gatts_char_handles_t    tracking_char_handles;       
        ble_gatts_char_handles_t    device_pos_char_handles;       
        ble_gatts_char_handles_t    angle_pos_char_handles;       
        ble_gatts_char_handles_t    pos_config_char_handles;       
        ble_gatts_char_handles_t    vib_config_char_handles;                      
        bool                        is_raw_data_notif_enabled;
        bool                        is_threshold_notif_enabled;
        bool                        is_side_current_notif_enabled;
        bool                        is_front_current_notif_enabled;
        ble_calibrate_write_handler_t   calib_write_handler;
        
    };
    
    void ble_motion_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context);
    
    uint32_t ble_motion_init(ble_motion_t * p_motion, const ble_motion_init_t * p_motion_init);

    and declared at motion.c

    ...
    ...
    
    
    
    ...
    
    static void ble_calibrate_handler(ble_motion_t * p_motion, ble_calibrate_t * calib)
    {
        ret_code_t         err_code;
          NRF_LOG_INFO("RECEIVED VALUE :%d",calib->calibrate);
    
    }
    
    
    
    static ret_code_t service_init(bool major_minor_fw_ver_changed)
    {
        uint32_t                                    err_code;
        ble_motion_init_t                           motion_init;
        motion_init.init_calibrate.calibrate  =     5;
        motion_init.calib_write_handler       =     ble_calibrate_handler;
        //uis_init.device_write_handler = ble_uis_device_handler;
    
       return ble_motion_init(&b_motion, &motion_init);
    }

  • Maybe you need to use static variable ? or public variable ? The way you defined 

       ble_motion_init_t                           motion_init; 

    it's a local variable and will be discarded after service_init() finishes. 

  • Ok, If in that case. I have main.c and drv_motion.c file and ble_motion.h

    in drv_motion.c file

    public variable

    static ble_motion_init_t             motion_init;

    and i process the data. anywhere in the .c file i am able to print or read the perfect variable.

    but same public variable declare in main.c file

    it repeats zero.

    eg:

    in drv_motion.c

    motion_init.init_train.training value = 5;

    anf it prints  value 5;

    but in same method at same time of drv_motion.c prints from main.c file also doing print

    static ble_motion_init_t         b_motion_i;

    when prints it shows 0.

  • Are you sharing the same variable between different C files ? 
    If it's the case you need to use extern when you refer to a variable initialized in other file. 

Related