Hello, I have custom BLE service and characteristic as below image.

I wanted to discover them in ble central mode. I have modified ble_hrc_c.c to validate but central not able to discover. Can anyone suggest? Also attaching code.


Hello, I have custom BLE service and characteristic as below image.

I wanted to discover them in ble central mode. I have modified ble_hrc_c.c to validate but central not able to discover. Can anyone suggest? Also attaching code.


#include "sdk_common.h"
#include "ble_house_keeping_client.h"
#include "ble_db_discovery.h"
#include "ble_types.h"
#include "ble_srv_common.h"
#include "ble_gattc.h"
#include "app_error.h"
#define NRF_LOG_MODULE_NAME ble_hrs_c
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define HRM_FLAG_MASK_HR_16BIT (0x01 << 0) /**< Bit mask used to extract the type of heart rate value. This is used to find if the received heart rate is a 16 bit value or an 8 bit value. */
#define HRM_FLAG_MASK_HR_RR_INT (0x01 << 4) /**< Bit mask used to extract the presence of RR_INTERVALS. This is used to find if the received measurement includes RR_INTERVALS. */
#define TX_BUFFER_MASK 0x07 /**< TX Buffer mask, must be a mask of continuous zeroes, followed by continuous sequence of ones: 000...111. */
#define TX_BUFFER_SIZE (TX_BUFFER_MASK + 1) /**< Size of send buffer, which is 1 higher than the mask. */
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
#define WRITE_MESSAGE_LENGTH BLE_CCCD_VALUE_LEN /**< Length of the write message for CCCD. */
typedef enum
{
READ_REQ, /**< Type identifying that this tx_message is a read request. */
WRITE_REQ /**< Type identifying that this tx_message is a write request. */
} tx_request_t;
/**@brief Structure for writing a message to the peer, i.e. CCCD.
*/
typedef struct
{
uint8_t gattc_value[WRITE_MESSAGE_LENGTH]; /**< The message to write. */
ble_gattc_write_params_t gattc_params; /**< GATTC parameters for this message. */
} write_params_t;
/**@brief Structure for holding data to be transmitted to the connected central.
*/
typedef struct
{
uint16_t conn_handle; /**< Connection handle to be used when transmitting this message. */
tx_request_t type; /**< Type of this message, i.e. read or write message. */
union
{
uint16_t read_handle; /**< Read request message. */
write_params_t write_req; /**< Write request message. */
} req;
} tx_message_t;
static tx_message_t m_tx_buffer[TX_BUFFER_SIZE]; /**< Transmit buffer for messages to be transmitted to the central. */
static uint32_t m_tx_insert_index = 0; /**< Current index in the transmit buffer where the next message should be inserted. */
static uint32_t m_tx_index = 0; /**< Current index in the transmit buffer from where the next message to be transmitted resides. */
/**@brief Function for passing any pending request from the buffer to the stack.
*/
static void tx_buffer_process(void)
{
if (m_tx_index != m_tx_insert_index)
{
uint32_t err_code;
if (m_tx_buffer[m_tx_index].type == READ_REQ)
{
err_code = sd_ble_gattc_read(m_tx_buffer[m_tx_index].conn_handle,
m_tx_buffer[m_tx_index].req.read_handle,
0);
}
else
{
err_code = sd_ble_gattc_write(m_tx_buffer[m_tx_index].conn_handle,
&m_tx_buffer[m_tx_index].req.write_req.gattc_params);
}
if (err_code != NRF_SUCCESS)
{
NRF_LOG_DEBUG("SD Read/Write API returns error. This message sending will be "
"attempted again..");
}
}
}
/**@brief Function for handling write response events.
*
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_write_rsp(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event if on the link for this instance
if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
return;
}
if ((p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION) ||
(p_ble_evt->evt.gattc_evt.gatt_status == BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION))
{
// Do nothing to reattempt write.
}
else
{
m_tx_index++;
m_tx_index &= TX_BUFFER_MASK;
}
// Check if there is any message to be sent across to the peer and send it.
tx_buffer_process();
}
/**@brief Function for handling Handle Value Notification received from the SoftDevice.
*
* @details This function will uses the Handle Value Notification received from the SoftDevice
* and checks if it is a notification of the heart rate measurement from the peer. If
* it is, this function will decode the heart rate measurement and send it to the
* application.
*
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_hvx(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
// Check if the event is on the link for this instance
if (p_ble_hrs_c->conn_handle != p_ble_evt->evt.gattc_evt.conn_handle)
{
NRF_LOG_DEBUG("Received HVX on link 0x%x, not associated to this instance, ignore",
p_ble_evt->evt.gattc_evt.conn_handle);
return;
}
NRF_LOG_DEBUG("Received HVX on link 0x%x, hrm_handle 0x%x",
p_ble_evt->evt.gattc_evt.params.hvx.handle,
p_ble_hrs_c->peer_hrs_db.hrm_handle);
// Check if this is a heart rate notification.
if (p_ble_evt->evt.gattc_evt.params.hvx.handle == p_ble_hrs_c->peer_hrs_db.hrm_handle)
{
ble_hrs_c_evt_t ble_hrs_c_evt;
uint32_t index = 0;
ble_hrs_c_evt.evt_type = BLE_HRS_C_EVT_HRM_NOTIFICATION;
ble_hrs_c_evt.conn_handle = p_ble_hrs_c->conn_handle;
ble_hrs_c_evt.params.hrm.rr_intervals_cnt = 0;
if (!(p_ble_evt->evt.gattc_evt.params.hvx.data[index++] & HRM_FLAG_MASK_HR_16BIT))
{
// 8 Bit heart rate value received.
ble_hrs_c_evt.params.hrm.hr_value = p_ble_evt->evt.gattc_evt.params.hvx.data[index++]; //lint !e415 suppress Lint Warning 415: Likely access out of bond
}
else
{
// 16 bit heart rate value received.
ble_hrs_c_evt.params.hrm.hr_value =
uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
index += sizeof(uint16_t);
}
if ((p_ble_evt->evt.gattc_evt.params.hvx.data[0] & HRM_FLAG_MASK_HR_RR_INT))
{
uint32_t i;
/*lint --e{415} --e{416} --e{662} --e{661} -save suppress Warning 415: possible access out of bond */
for (i = 0; i < BLE_HRS_C_RR_INTERVALS_MAX_CNT; i ++)
{
if (index >= p_ble_evt->evt.gattc_evt.params.hvx.len)
{
break;
}
ble_hrs_c_evt.params.hrm.rr_intervals[i] =
uint16_decode(&(p_ble_evt->evt.gattc_evt.params.hvx.data[index]));
index += sizeof(uint16_t);
}
/*lint -restore*/
ble_hrs_c_evt.params.hrm.rr_intervals_cnt = (uint8_t)i;
}
p_ble_hrs_c->evt_handler(p_ble_hrs_c, &ble_hrs_c_evt);
}
}
/**@brief Function for handling Disconnected event received from the SoftDevice.
*
* @details This function check if the disconnect event is happening on the link
* associated with the current instance of the module, if so it will set its
* conn_handle to invalid.
*
* @param[in] p_ble_hrs_c Pointer to the Heart Rate Client structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
static void on_disconnected(ble_hrs_c_t * p_ble_hrs_c, const ble_evt_t * p_ble_evt)
{
if (p_ble_hrs_c->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
{
p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
}
}
#define BLE_UUID_HOUSE_KEEPING_CLIENT_SERVICE 0xC201
#define BLE_UUID_HOUSE_KEEPING_CLIENT_MEASUREMENT_CHAR 0x483E
//#define BLE_UUID_HEART_RATE_SERVICE 0x180D /**< Heart Rate service UUID. */
//#define BLE_UUID_HEART_RATE_MEASUREMENT_CHAR 0x2A37 /**< Heart Rate Measurement characteristic UUID. */
void ble_hrs_on_db_disc_evt(ble_hrs_c_t * p_ble_hrs_c, const ble_db_discovery_evt_t * p_evt)
{
// Check if the Heart Rate Service was discovered.
if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE// &&
/* p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_HEART_RATE_SERVICE &&
p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE*/
//p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_HOUSE_KEEPING_CLIENT_SERVICE &&
// p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE
)
{
// Find the CCCD Handle of the Heart Rate Measurement characteristic.
uint32_t i;
ble_hrs_c_evt_t evt;
evt.evt_type = BLE_HRS_C_EVT_DISCOVERY_COMPLETE;
evt.conn_handle = p_evt->conn_handle;
for (i = 0; i < p_evt->params.discovered_db.char_count; i++)
{
if (p_evt->params.discovered_db.charateristics[i].characteristic.uuid.uuid ==
BLE_UUID_HOUSE_KEEPING_CLIENT_MEASUREMENT_CHAR)
{
// Found Heart Rate characteristic. Store CCCD handle and break.
evt.params.peer_db.hrm_cccd_handle =
p_evt->params.discovered_db.charateristics[i].cccd_handle;
evt.params.peer_db.hrm_handle =
p_evt->params.discovered_db.charateristics[i].characteristic.handle_value;
break;
}
}
NRF_LOG_DEBUG("Heart Rate Service discovered at peer.");
//If the instance has been assigned prior to db_discovery, assign the db_handles
if (p_ble_hrs_c->conn_handle != BLE_CONN_HANDLE_INVALID)
{
if ((p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle == BLE_GATT_HANDLE_INVALID)&&
(p_ble_hrs_c->peer_hrs_db.hrm_handle == BLE_GATT_HANDLE_INVALID))
{
p_ble_hrs_c->peer_hrs_db = evt.params.peer_db;
}
}
p_ble_hrs_c->evt_handler(p_ble_hrs_c, &evt);
}
}
//4fafc201-1fb5-459e-8fcc-c5c9c331914b
//
//#define SERVICE_UUID_BASE {0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15, \
// 0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00}
uint32_t ble_hrs_c_init(ble_hrs_c_t * p_ble_hrs_c, ble_hrs_c_init_t * p_ble_hrs_c_init)
{
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c_init);
ble_uuid128_t service_base_uuid = {0x4b, 0x91, 0x31, 0xc3, 0xc9, 0xc5, 0xcc, 0x8f,
0x9e, 0x45, 0xb5, 0x1f, 0x00, 0x00, 0xaf, 0x4f};
ble_uuid128_t characteristic_base_uuid = {0xa8, 0x26, 0x1b, 0x36, 0x07, 0xea, 0xf5, 0xb7,
0x88, 0x46, 0xe1, 0x36, 0x00, 0x00, 0xb5, 0xbe};
ble_uuid_t hrs_uuid;
// ble_uuid128_t hrs_base_uuid = {LBS_UUID_BASE};
p_ble_hrs_c->service_uuid_type = BLE_UUID_TYPE_VENDOR_BEGIN;
APP_ERROR_CHECK(sd_ble_uuid_vs_add(&service_base_uuid, &p_ble_hrs_c->service_uuid_type));
APP_ERROR_CHECK(sd_ble_uuid_vs_add(&characteristic_base_uuid, &p_ble_hrs_c->characteristic_uuid_type));
hrs_uuid.type = BLE_UUID_TYPE_BLE;
hrs_uuid.uuid = BLE_UUID_HOUSE_KEEPING_CLIENT_SERVICE;
p_ble_hrs_c->evt_handler = p_ble_hrs_c_init->evt_handler;
p_ble_hrs_c->conn_handle = BLE_CONN_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle = BLE_GATT_HANDLE_INVALID;
p_ble_hrs_c->peer_hrs_db.hrm_handle = BLE_GATT_HANDLE_INVALID;
return ble_db_discovery_evt_register(&hrs_uuid);
}
void ble_hrs_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
{
ble_hrs_c_t * p_ble_hrs_c = (ble_hrs_c_t *)p_context;
if ((p_ble_hrs_c == NULL) || (p_ble_evt == NULL))
{
return;
}
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_HVX:
on_hvx(p_ble_hrs_c, p_ble_evt);
break;
case BLE_GATTC_EVT_WRITE_RSP:
on_write_rsp(p_ble_hrs_c, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_ble_hrs_c, p_ble_evt);
break;
default:
break;
}
}
/**@brief Function for creating a message for writing to the CCCD.
*/
static uint32_t cccd_configure(uint16_t conn_handle, uint16_t handle_cccd, bool enable)
{
NRF_LOG_DEBUG("Configuring CCCD. CCCD Handle = %d, Connection Handle = %d",
handle_cccd,conn_handle);
tx_message_t * p_msg;
uint16_t cccd_val = enable ? BLE_GATT_HVX_NOTIFICATION : 0;
p_msg = &m_tx_buffer[m_tx_insert_index++];
m_tx_insert_index &= TX_BUFFER_MASK;
p_msg->req.write_req.gattc_params.handle = handle_cccd;
p_msg->req.write_req.gattc_params.len = WRITE_MESSAGE_LENGTH;
p_msg->req.write_req.gattc_params.p_value = p_msg->req.write_req.gattc_value;
p_msg->req.write_req.gattc_params.offset = 0;
p_msg->req.write_req.gattc_params.write_op = BLE_GATT_OP_WRITE_REQ;
p_msg->req.write_req.gattc_value[0] = LSB_16(cccd_val);
p_msg->req.write_req.gattc_value[1] = MSB_16(cccd_val);
p_msg->conn_handle = conn_handle;
p_msg->type = WRITE_REQ;
tx_buffer_process();
return NRF_SUCCESS;
}
uint32_t ble_hrs_c_hrm_notif_enable(ble_hrs_c_t * p_ble_hrs_c)
{
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
return cccd_configure(p_ble_hrs_c->conn_handle,
p_ble_hrs_c->peer_hrs_db.hrm_cccd_handle,
true);
}
uint32_t ble_hrs_c_handles_assign(ble_hrs_c_t * p_ble_hrs_c,
uint16_t conn_handle,
const hrs_db_t * p_peer_hrs_handles)
{
VERIFY_PARAM_NOT_NULL(p_ble_hrs_c);
p_ble_hrs_c->conn_handle = conn_handle;
if (p_peer_hrs_handles != NULL)
{
p_ble_hrs_c->peer_hrs_db = *p_peer_hrs_handles;
}
return NRF_SUCCESS;
}
Hi,
have custom BLE service and characteristic
I wanted to discover them in ble central mode. I have modified ble_hrc_c.c to validate but central not able to discover.
Since you are using a custom service/characteristic, I recommend taking a look at the central examples that also uses custom/vendor specific service/characteristic, e.g. the ble_app_uart_c and ble_app_blinky_c
Yes, I checked, But I am unable to make it work. I pasted my code too. I am not able to find mistakes in my code.
E.g. the type you passed to ble_db_discovery_evt_register() is wrong, it should be BLE_UUID_TYPE_VENDOR_BEGIN. Again, since you are using a custom service/characteristic, I recommend taking a look at the central examples that also uses custom/vendor specific service/characteristic, e.g. the ble_app_uart_c and ble_app_blinky_c.
I have updated but still not working. Looking into the ble_app_uart_c and ble_app_blinky_c tooo