Hi All,
I am using nRF52 DK board & nRF5_SDK_17.1.0 for Development(Emulated Project for nRF52805), My application needs creation of multiple service and multiple characteristics. So, I created a Service of two characteristics as shown in code snippet below. Services and its characteristics populated on mobile application with its properties(read/write/notify as done at the time of characteristics making). but when Write/Notify button pressed from Mobile application, I am getting Wrong value handle and cccd handle and not able to read data, written from mobile application side. but I am able to read data written from mobile application, if only one characteristics is created.
below,i am sharing my code snippet, kindly correct me where i am doing wrong.
/**@brief Macro for defining a Connectivity_Service instance.
*
* @param _name Name of the instance.
* @hideinitializer
*/
#define BLE_CONNECTIVITY_SER_DEF(_name) \
static ble_Connecivity_t _name; \
NRF_SDH_BLE_OBSERVER(_name ## _obs, \
BLE_HRS_BLE_OBSERVER_PRIO, \
ble_connectivity_on_ble_evt, &_name)
typedef enum
{
/*! \VarExTransmissionofsmartphoneCHANNEL1 */
BLE_VAREX_TX_OF_SM_CH_1_EVT_NOTIFICATION_ENABLED, /* "VarEx Transmission of smartphone CHANNEL 1" notification enabled event. */
BLE_VAREX_TX_OF_SM_CH_1_EVT_NOTIFICATION_DISABLED, /* "VarEx Transmission of smartphone CHANNEL 1" notification disabled event. */
/*! \VarExTransmissionOfTCUCHANNEL1ACK */
VAREX_TX_OF_TCU_CH1_ACK_EVT_NOTIFICATION_ENABLED, /* "VarEx Transmission of smartphone CHANNEL 1 ACK" notification enabled event. */
VAREX_TX_OF_TCU_CH1_ACK_EVT_NOTIFICATION_DISABLED, /* "VarEx Transmission of smartphone CHANNEL 1 ACK" notification disabled event. */
BLE_CUS_EVT_DISCONNECTED,
BLE_CUS_EVT_CONNECTED
} ble_conn_service_type_t;
/**@brief Connectivity Service event. */
typedef struct
{
ble_conn_service_type_t evt_type; /**< Type of event. */
} ble_conn_service_evt_t;
// Forward declaration of the ble_Connecivity_t type.
typedef struct ble_conn_Service_s ble_Connecivity_t;
/**@brief Connectivity Service event handler type. */
typedef void (*ble_connectivity_evt_handler_t) (ble_Connecivity_t * p_conn, ble_conn_service_evt_t * p_evt);
/**@brief Connectivity Service init structure. This contains all options and data needed for
* initialization of the service.*/
typedef struct
{
ble_connectivity_evt_handler_t evt_handler; /*! Event handler to be called for handling events in the Connectivity Service. */
ble_srv_cccd_security_mode_t VarExTXofSm_Ch1_char_attr_md; /*! Initial security level for "VarEx Transmission of smartphone CHANNEL 1" characteristics attribute */
ble_srv_cccd_security_mode_t VarExTXofSm_Ch1_ACK_char_attr_md; /*! Initial security level for "VarEx Transmission of smartphone CHANNEL 1 \ACK" characteristics attribute */
} ble_Connectivity_Ser_init_t;
/**@brief Connectivity Service structure. This contains various status information for the service. */
struct ble_conn_Service_s
{
ble_connectivity_evt_handler_t evt_handler; /*! Event handler to be called for handling events in the Connectivity Service. */
uint16_t service_handle; /*! Handle of Connectivity Service (as provided by the BLE stack). */
ble_gatts_char_handles_t VarExTXofSm_Ch1_char_handles; /*! Handles related to the "VarEx Transmission of smartphone CHANNEL 1" characteristic. */
ble_gatts_char_handles_t VarExTXofSm_Ch1_ACK_char_handles; /*! Handles related to the "VarEx Transmission of smartphone CHANNEL 1 \ACK" characteristic. */
uint16_t conn_handle; /*! Handle of the current connection (as provided by the BLE stack, is BLE_CONN_HANDLE_INVALID if not in a connection). */
uint8_t uuid_type;
};
/**@brief Function for handling the Write event.
*
* @param[in] p_con Connectivity Service structure.
* @param[in] p_ble_evt Event received from the BLE stack.
*/
static void on_write(ble_Connecivity_t * p_con, ble_evt_t const * p_ble_evt)
{
ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
/*! \VarEx Transmission of smartphone CHANNEL 1 Write Event */
// "VarEx Transmission of smartphone CHANNEL 1" Characteristic Written to.
if (p_evt_write->handle == p_con->VarExTXofSm_Ch1_char_handles.value_handle)
{
//Update Received data to Buffter
memset(&valPtr,0,sizeof(valPtr)/sizeof(valPtr[0]));
memcpy(&valPtr,&p_evt_write->data,p_evt_write->len);
if(*p_evt_write->data == 0x01)
{
#if ((DEVELOP_IN_NRF52832) && (NRFX_COREDEP_DELAY_US_LOOP_CYCLES==3))
nrf_gpio_pin_toggle(LED_4);
#endif
NRF_LOG_INFO("Data Wr VarExTXofSm_Ch1 = %d\r\n", *p_evt_write->data);
}
else if(*p_evt_write->data == 0x00)
{
#if ((DEVELOP_IN_NRF52832) && (NRFX_COREDEP_DELAY_US_LOOP_CYCLES==3))
nrf_gpio_pin_toggle(LED_4);
#endif
NRF_LOG_INFO("Data Wr VarExTXofSm_Ch1 = %d\r\n", *p_evt_write->data);
}
else
{
//Do nothing
NRF_LOG_INFO("Data Wr VarExTXofSm_Ch1=%s\r\n",valPtr);
}
}
/*! \VarEx Transmission of smartphone CHANNEL 1 ACK Write Event */
// "VarEx Transmission of smartphone CHANNEL 1 ACK" Characteristic Written to.
if (p_evt_write->handle == p_con->VarExTXofSm_Ch1_ACK_char_handles.value_handle)
{
//Update Received data to Buffter
memset(&valPtr2,0,sizeof(valPtr2)/sizeof(valPtr2[0]));
memcpy(&valPtr2,&p_evt_write->data,p_evt_write->len);
if(*p_evt_write->data == 0x01)
{
#if ((DEVELOP_IN_NRF52832) && (NRFX_COREDEP_DELAY_US_LOOP_CYCLES==3))
nrf_gpio_pin_toggle(LED_4);
#endif
NRF_LOG_INFO("Data Wr VarExTXofSm_Ch1_ACK = %d\r\n", *p_evt_write->data);
}
else if(*p_evt_write->data == 0x00)
{
#if ((DEVELOP_IN_NRF52832) && (NRFX_COREDEP_DELAY_US_LOOP_CYCLES==3))
nrf_gpio_pin_toggle(LED_4);
#endif
NRF_LOG_INFO("Data Wr VarExTXofSm_Ch1_ACK = %d\r\n", *p_evt_write->data);
}
else
{
//Do nothing
NRF_LOG_INFO("Data Wr VarExTXofSm_Ch1_ACK=%s\r\n",valPtr);
}
}
// Check if the "VarEx Transmission of smartphone CHANNEL 1" CCCD is written to and that the value is the appropriate length, i.e 2 bytes.
if ((p_evt_write->handle == p_con->VarExTXofSm_Ch1_char_handles.cccd_handle) && (p_evt_write->len == 2))
{
// CCCD written, call application event handler
if (p_con->evt_handler != NULL)
{
ble_conn_service_evt_t evt;
NRF_LOG_INFO("CCCD Wr VarExTXofSm_Ch1=%s\r\n",(*p_evt_write->data)?("True"):("False"));
if (ble_srv_is_notification_enabled(p_evt_write->data))
{
evt.evt_type = BLE_VAREX_TX_OF_SM_CH_1_EVT_NOTIFICATION_ENABLED;
}
else
{
evt.evt_type = BLE_VAREX_TX_OF_SM_CH_1_EVT_NOTIFICATION_DISABLED;
}
// Call the application event handler.
p_con->evt_handler(p_con, &evt);
}
}
}
void ble_connectivity_on_ble_evt( ble_evt_t const * p_ble_evt, void * p_context)
{
ble_Connecivity_t * p_con = (ble_Connecivity_t *) p_context;
NRF_LOG_INFO("BLE event received. Event type = %d\r\n", p_ble_evt->header.evt_id);
if (p_con == NULL || p_ble_evt == NULL)
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_con, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_con, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_con, p_ble_evt);
break;
/* Handling this event is not necessary
case BLE_GATTS_EVT_EXCHANGE_MTU_REQUEST:
NRF_LOG_INFO("EXCHANGE_MTU_REQUEST event received.\r\n");
break;
*/
default:
// No implementation needed.
break;
}
}
/**@brief Function for adding the Connectivity Value characteristic.
*
* @param[in] p_con Connectivity Service structure.
* @param[in] p_con_init Information needed to initialize the service.
*
* @return NRF_SUCCESS on success, otherwise an error code.
*/
static uint32_t custom_value_chararacterstic_add(ble_Connecivity_t * p_con, const ble_Connectivity_Ser_init_t * p_con_init,ble_gatts_char_md_t *char_meta_data,ble_gatts_attr_t *attr_characteristic_value)
{
uint32_t err_code;
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
//GATT Characteristic metadata
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = char_meta_data->char_props.read;
char_md.char_props.write = char_meta_data->char_props.write;
char_md.char_props.notify = char_meta_data->char_props.notify;
char_md.p_char_user_desc = char_meta_data->p_char_user_desc;
char_md.p_char_pf = char_meta_data->p_char_pf;
char_md.p_user_desc_md = char_meta_data->p_user_desc_md;
char_md.p_cccd_md = char_meta_data->p_cccd_md;
char_md.p_sccd_md = char_meta_data->p_sccd_md;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = attr_characteristic_value->p_uuid;
attr_char_value.p_attr_md = attr_characteristic_value->p_attr_md;
attr_char_value.init_len = attr_characteristic_value->init_len;
attr_char_value.init_offs = attr_characteristic_value->init_offs;
attr_char_value.max_len = attr_characteristic_value->max_len;
attr_char_value.p_value = attr_characteristic_value->p_value;
err_code = sd_ble_gatts_characteristic_add(p_con->service_handle, &char_md,
&attr_char_value,
&p_con->VarExTXofSm_Ch1_char_handles);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
return NRF_SUCCESS;
}
uint32_t ble_connectivity_Service_init(ble_Connecivity_t * p_con, const ble_Connectivity_Ser_init_t * p_con_init)
{
if (p_con == NULL || p_con_init == NULL)
{
return NRF_ERROR_NULL;
}
uint32_t err_code;
ble_uuid_t ble_uuid;
//Recently Added GATT Characterstic MetaData
ble_gatts_char_md_t char_md;
//Client Characteristic Configuration Descriptor
ble_gatts_attr_md_t cccd_md;
//Recently Added Attribute metadata.
ble_gatts_attr_md_t attr_md;
//Recently Added for Attribute Characterstic Value
ble_gatts_attr_t attr_char_value;
// Initialize service structure
p_con->evt_handler = p_con_init->evt_handler;
p_con->conn_handle = BLE_CONN_HANDLE_INVALID;
// Add Connectivity Service UUID
ble_uuid128_t base_uuid = {CONNECTIVITY_SERVICE_UUID_BASE};
err_code = sd_ble_uuid_vs_add(&base_uuid, &p_con->uuid_type);
VERIFY_SUCCESS(err_code);
ble_uuid.type = p_con->uuid_type;
ble_uuid.uuid = CONNECTIVITY_SERVICE_UUID;
// Add the Connectivity Service
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &ble_uuid, &p_con->service_handle);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
/**********************************************************VAREX_TX_OF_SM_CH1_CHAR_UUID**********************************************************************/
//Attribute metadata forClient Characteristic Configuration Descriptor(CCCD)
memset(&cccd_md, 0, sizeof(cccd_md));
//Read/Write operation on cccd should be possible without authentication.
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
cccd_md.write_perm = p_con_init->VarExTXofSm_Ch1_char_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
//GATT Characteristic metadata
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;
////Add Base UUID For Characterstics
//ble_uuid128_t base_uuid1 = {VAREX_TX_OF_SM_CH1_CHAR_UUID_BASE};
//err_code = sd_ble_uuid_vs_add(&base_uuid1, &p_con->uuid_type);
//VERIFY_SUCCESS(err_code);
//Characterstic UUID
ble_uuid.type = p_con->uuid_type;
ble_uuid.uuid = VAREX_TX_OF_SM_CH1_CHAR_UUID;
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_con_init->VarExTXofSm_Ch1_char_attr_md.read_perm;
attr_md.write_perm = p_con_init->VarExTXofSm_Ch1_char_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;
//Attribute Characterstic Values
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(valPtr);//sizeof(uint8_t);
attr_char_value.p_value = valPtr;
// Add "VarEx Transmission of smartphone CHANNEL 1" characteristic
err_code = custom_value_chararacterstic_add(p_con, p_con_init,&char_md,&attr_char_value);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
/***************************************************************************************************************************************************************/
/**********************************************************VAREX_TX_OF_TCU_CH1_ACK_UUID**********************************************************************/
//Attribute metadata forClient Characteristic Configuration Descriptor(CCCD)
memset(&cccd_md, 0, sizeof(cccd_md));
//Read/Write operation on cccd should be possible without authentication.
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);
cccd_md.write_perm = p_con_init->VarExTXofSm_Ch1_ACK_char_attr_md.cccd_write_perm;
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
//GATT Characteristic metadata
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.char_props.write = 1;
char_md.char_props.notify = 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/* &cccd_md*/;
char_md.p_sccd_md = NULL;
////Add Base UUID For Characterstics
//ble_uuid128_t base_uuid2 = {VAREX_TX_OF_SM_CH1_ACK_UUID_BASE};
//err_code = sd_ble_uuid_vs_add(&base_uuid2, &p_con->uuid_type);
//VERIFY_SUCCESS(err_code);
//Characterstic UUID
ble_uuid.type = p_con->uuid_type;
ble_uuid.uuid = VAREX_TX_OF_TCU_CH1_ACK_UUID;
memset(&attr_md, 0, sizeof(attr_md));
attr_md.read_perm = p_con_init->VarExTXofSm_Ch1_ACK_char_attr_md.read_perm;
attr_md.write_perm = p_con_init->VarExTXofSm_Ch1_ACK_char_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;
//Attribute Characterstic Values
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(valPtr2);//sizeof(uint8_t);
attr_char_value.p_value = valPtr2;
// Add Connectivity Value characteristic
err_code = custom_value_chararacterstic_add(p_con, p_con_init,&char_md,&attr_char_value);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
/***************************************************************************************************************************************************************/
return NRF_SUCCESS;
}
Service Initialization
// Initialize Connectivity Service init structure to zero.
memset(&Con_Ser_Init, 0, sizeof(Con_Ser_Init));
Con_Ser_Init.evt_handler = on_connectivity_evt;
/*! VarEx Transmission of smartphone CHANNEL \1 */
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&Con_Ser_Init.VarExTXofSm_Ch1_char_attr_md.cccd_write_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&Con_Ser_Init.VarExTXofSm_Ch1_char_attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&Con_Ser_Init.VarExTXofSm_Ch1_char_attr_md.write_perm);
/*! VarEx Transmission of smartphone CHANNEL 1 \ACK */
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&Con_Ser_Init.VarExTXofSm_Ch1_ACK_char_attr_md.cccd_write_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&Con_Ser_Init.VarExTXofSm_Ch1_ACK_char_attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&Con_Ser_Init.VarExTXofSm_Ch1_ACK_char_attr_md.write_perm);
err_code = ble_connectivity_Service_init(&m_connectivity, &Con_Ser_Init);
APP_ERROR_CHECK(err_code);