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

pc-ble-driver NRF_ERROR_SVC_HANDLER_MISSING

Hi when I try to run the HRM collector the scan start fails with error code 12289 I am using visual studio and C++

What am I missing? I downloaded "connectivity_115k2_with_s130_1.0.0" to a nrf58122 qfac usb dongle (PCA10031)

#include "stdafx.h"
#include "nrf_error.h"
#include "ble.h"
#include "ble_types.h"
#include "sd_rpc.h"
#include <string.h>
#include <stdbool.h>
#include <stdio.h>

#define UART_PORT_NAME "COM48"

#define ADVERTISING_INTERVAL_40_MS  64 // * 0.625 ms = 40 ms
#define ADVERTISING_TIMEOUT_3_MIN   180 // * 1 sec = 3 min

enum
{
	UNIT_0_625_MS = 625,                                /**< Number of microseconds in 0.625 milliseconds. */
	UNIT_1_25_MS = 1250,                               /**< Number of microseconds in 1.25 milliseconds. */
	UNIT_10_MS = 10000                               /**< Number of microseconds in 10 milliseconds. */
};

#define MSEC_TO_UNITS(TIME, RESOLUTION) (((TIME) * 1000) / (RESOLUTION))

#define SCAN_INTERVAL                    0x00A0                                         /**< Determines scan interval in units of 0.625 millisecond. */
#define SCAN_WINDOW                      0x0050                                         /**< Determines scan window in units of 0.625 millisecond. */

#define MIN_CONNECTION_INTERVAL          MSEC_TO_UNITS(30, UNIT_1_25_MS)                /**< Determines maximum connection interval in millisecond. */
#define MAX_CONNECTION_INTERVAL          MSEC_TO_UNITS(60, UNIT_1_25_MS)                /**< Determines maximum connection interval in millisecond. */
#define SLAVE_LATENCY                    0                                              /**< Determines slave latency in counts of connection events. */
#define SUPERVISION_TIMEOUT              MSEC_TO_UNITS(4000, UNIT_10_MS)                /**< Determines supervision time-out in units of 10 millisecond. */

#define TARGET_DEV_NAME                  "HRM Example"                                      /**< Target device name that application is looking for. */
#define MAX_PEER_COUNT                   1                                              /**< Maximum number of peer's application intends to manage. */

#define HRM_SERVICE_UUID                 0x180D
#define HRM_MEAS_CHAR_UUID               0x2A37
#define CCCD_UUID                        0x2902
#define CCCD_NOTIFY                      0x01

#define STRING_BUFFER_SIZE               50

typedef struct
{
	uint8_t     * p_data;                                                      /**< Pointer to data. */
	uint16_t      data_len;                                                    /**< Length of data. */
} data_t;

static uint8_t  m_connected_devices = 0;
static uint16_t m_connection_handle = 0;
static uint16_t m_service_start_handle = 0;
static uint16_t m_service_end_handle = 0;
static uint16_t m_hrm_char_handle = 0;
static uint16_t m_hrm_cccd_handle = 0;
static bool     m_connection_is_in_progress = false;

static const ble_gap_scan_params_t m_scan_param =
{
	0,                       // Active scanning set.
	0,                       // Selective scanning not set.
	NULL,                    // White-list not set.
	(uint16_t)SCAN_INTERVAL, // Scan interval.
	(uint16_t)SCAN_WINDOW,   // Scan window.
	0                        // Never stop scanning unless explicit asked to.
};

static const ble_gap_conn_params_t m_connection_param =
{
	(uint16_t)MIN_CONNECTION_INTERVAL,   // Minimum connection
	(uint16_t)MAX_CONNECTION_INTERVAL,   // Maximum connection
	0,                                   // Slave latency
	(uint16_t)SUPERVISION_TIMEOUT        // Supervision time-out
};


/* Local function declarations */
static void log_handler(sd_rpc_log_severity_t severity, const char * message);
static uint32_t ble_stack_init();
static void on_connected(const ble_gap_evt_t * const p_ble_gap_evt);
static void on_adv_report(const ble_gap_evt_t * const p_ble_gap_evt);
static void on_timeout(const ble_gap_evt_t * const p_ble_gap_evt);
static void on_service_discovery_response(const ble_gattc_evt_t * const p_ble_gattc_evt);
static void on_characteristic_discover_response(const ble_gattc_evt_t * const p_ble_gattc_evt);
static void on_descriptor_discover_response(const ble_gattc_evt_t * const p_ble_gattc_evt);
static void on_write_response(const ble_gattc_evt_t * const p_ble_gattc_evt);
static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata);
static uint32_t scan_start();
static uint32_t service_discovery_start();
static uint32_t char_discovery_start();
static uint32_t descr_discovery_start();
static uint32_t hrm_cccd_set(uint8_t value);
static void ble_address_to_string_convert(ble_gap_addr_t address, uint8_t * string_buffer);


static void log_handler(sd_rpc_log_severity_t severity, const char * message)
{
	switch (severity)
	{
	case LOG_ERROR:
		printf("Error: %s\n", message); fflush(stdout);
		break;

	case LOG_WARNING:
		printf("Warning: %s\n", message); fflush(stdout);
		break;

	default:
		printf("Log: %s\n", message); fflush(stdout);
		break;
	}
}

static void on_connected(const ble_gap_evt_t * const p_ble_gap_evt)
{
	printf("Connection established\n"); fflush(stdout);
	m_connected_devices++;
	m_connection_handle = p_ble_gap_evt->conn_handle;
	m_connection_is_in_progress = false;
	service_discovery_start();
}

static void on_adv_report(const ble_gap_evt_t * const p_ble_gap_evt)
{
	uint32_t    err_code;
	data_t      adv_data;
	data_t      type_data;
	uint8_t     str[STRING_BUFFER_SIZE] = { 0 };

	ble_address_to_string_convert(p_ble_gap_evt->params.adv_report.peer_addr, str);
	printf("Received advertisment report, address: 0x%s\n", str); fflush(stdout);

	adv_data.p_data = (uint8_t *)(p_ble_gap_evt->params.adv_report.data);
	adv_data.data_len = p_ble_gap_evt->params.adv_report.dlen;

	err_code = adv_report_parse(BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME,
		&adv_data,
		&type_data);
	if (err_code != NRF_SUCCESS)
	{
		// Compare short local name in case complete name does not match.
		err_code = adv_report_parse(BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME,
			&adv_data,
			&type_data);

		if (err_code != NRF_SUCCESS)
		{
			return;
		}
	}

	if (0 == memcmp(TARGET_DEV_NAME, type_data.p_data, strlen(TARGET_DEV_NAME)))
	{
		if (m_connected_devices >= MAX_PEER_COUNT)
		{
			return;
		}

		if (m_connection_is_in_progress)
		{
			return;
		}

		err_code = sd_ble_gap_connect(&(p_ble_gap_evt->params.adv_report.peer_addr),
			&m_scan_param,
			&m_connection_param);

		if (err_code != NRF_SUCCESS)
		{
			printf("Connection Request Failed, reason %d\n", err_code); fflush(stdout);
			return;
		}

		m_connection_is_in_progress = true;
	}
}

static void on_timeout(const ble_gap_evt_t * const p_ble_gap_evt)
{
	if (p_ble_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_CONN)
	{
		m_connection_is_in_progress = false;
	}
	else if (p_ble_gap_evt->params.timeout.src == BLE_GAP_TIMEOUT_SRC_SCAN)
	{
		scan_start();
	}
}

static void on_service_discovery_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	int count;
	int service_index;
	const ble_gattc_service_t * service;

	if (p_ble_gattc_evt->gatt_status != NRF_SUCCESS)
	{
		printf("Error. Service discovery failed. Error code 0x%X\n",
			p_ble_gattc_evt->gatt_status);
		fflush(stdout);
		return;
	}

	count = p_ble_gattc_evt->params.prim_srvc_disc_rsp.count;

	if (count == 0)
	{
		printf("Error. Service not found\n"); fflush(stdout);
		return;
	}

	printf("Received service discovery response\n"); fflush(stdout);

	service_index = 0; /* We specifically requested to discover Heart Rate service, so we can
					   * safely select the first returned service. */

	service = &(p_ble_gattc_evt->params.prim_srvc_disc_rsp.services[service_index]);

	m_service_start_handle = service->handle_range.start_handle;
	m_service_end_handle = service->handle_range.end_handle;

	printf("UUID: 0x%04X, start handle: 0x%04X, end handle: 0x%04X\n",
		service->uuid.uuid, m_service_start_handle, m_service_end_handle);
	fflush(stdout);

	char_discovery_start();
}

static void on_characteristic_discover_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	int i;
	int count;
	ble_gattc_char_t * p_characteristic;

	if (p_ble_gattc_evt->gatt_status != NRF_SUCCESS)
	{
		printf("Error. Characteristic discovery failed. Error code 0x%X\n",
			p_ble_gattc_evt->gatt_status);
		fflush(stdout);
		return;
	}

	count = p_ble_gattc_evt->params.char_disc_rsp.count;

	printf("Received characteristic discovery response, characteristics count: %d\n", count);
	fflush(stdout);

	for (i = 0; i < count; i++)
	{
		p_characteristic = (ble_gattc_char_t *)&(p_ble_gattc_evt->params.char_disc_rsp.chars[i]);
		printf("Handle: 0x%04X, UUID: 0x%04X\n",
			p_characteristic->handle_decl,
			p_characteristic->uuid.uuid);
		fflush(stdout);

		if (p_characteristic->uuid.uuid == HRM_MEAS_CHAR_UUID)
		{
			m_hrm_char_handle = p_characteristic->handle_decl;
		}
	}

	descr_discovery_start();
}

static void on_descriptor_discover_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	int i;
	int count;
	ble_gattc_desc_t * p_descriptor;

	if (p_ble_gattc_evt->gatt_status != NRF_SUCCESS)
	{
		printf("Error. Descriptor discovery failed. Error code 0x%X\n",
			p_ble_gattc_evt->gatt_status);
		fflush(stdout);
		return;
	}

	count = p_ble_gattc_evt->params.desc_disc_rsp.count;

	printf("Received descriptor discovery response, descriptor count: %d\n", count);
	fflush(stdout);

	for (i = 0; i < count; i++)
	{
		p_descriptor = (ble_gattc_desc_t *)&(p_ble_gattc_evt->params.desc_disc_rsp.descs[i]);
		printf("Handle: 0x%04X, UUID: 0x%04X\n", p_descriptor->handle, p_descriptor->uuid.uuid);
		fflush(stdout);

		if (p_descriptor->uuid.uuid == CCCD_UUID)
		{
			m_hrm_cccd_handle = p_descriptor->handle;
		}
	}

	printf("Press enter to toggle notifications\n"); fflush(stdout);
}

static void on_write_response(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	printf("Received write response.\n"); fflush(stdout);

	if (p_ble_gattc_evt->gatt_status != NRF_SUCCESS)
	{
		printf("Error. Write operation failed. Error code 0x%X\n",
			p_ble_gattc_evt->gatt_status);
		fflush(stdout);
		return;
	}
}

static void on_hvx(const ble_gattc_evt_t * const p_ble_gattc_evt)
{
	int i = 0;
	int length = p_ble_gattc_evt->params.hvx.len;

	printf("Received handle value notification, handle: 0x%04X, value: 0x",
		p_ble_gattc_evt->params.hvx.handle);
	fflush(stdout);

	for (i = 0; i < length; i++)
	{
		printf("%02X", p_ble_gattc_evt->params.hvx.data[i]);
		fflush(stdout);
	}

	printf("\n"); fflush(stdout);
}

static void ble_address_to_string_convert(ble_gap_addr_t address, uint8_t * string_buffer)
{
	const int address_length = 6;
	char temp_str[3];
	int i = 0;

	for (i = address_length - 1; i >= 0; --i)
	{
		snprintf(temp_str, sizeof(temp_str), "%02X", address.addr[i]);
		strncat_s((char *)string_buffer, STRING_BUFFER_SIZE, temp_str,sizeof(temp_str));
	}
}

static uint32_t adv_report_parse(uint8_t type, data_t * p_advdata, data_t * p_typedata)
{
	uint8_t * p_data;
	uint32_t  index;

	p_data = p_advdata->p_data;
	index = 0;

	while (index < p_advdata->data_len)
	{
		uint8_t field_length = p_data[index];
		uint8_t field_type = p_data[index + 1];

		if (field_type == type)
		{
			p_typedata->p_data = &p_data[index + 2];
			p_typedata->data_len = field_length - 1;
			return NRF_SUCCESS;
		}
		index += field_length + 1;
	}
	return NRF_ERROR_NOT_FOUND;
}

static uint32_t ble_stack_init()
{
	uint32_t err_code;
	ble_enable_params_t ble_enable_params;

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

	ble_enable_params.gatts_enable_params.attr_tab_size = BLE_GATTS_ATTR_TAB_SIZE_DEFAULT;
	ble_enable_params.gatts_enable_params.service_changed = false;

	err_code = sd_ble_enable(&ble_enable_params);

	if (err_code == NRF_SUCCESS)
	{
		return err_code;
	}

	if (err_code == NRF_ERROR_INVALID_STATE)
	{
		printf("BLE stack already enabled\n"); fflush(stdout);
		return NRF_SUCCESS;
	}

	printf("Failed to enable BLE stack.\n"); fflush(stdout);
	return err_code;
}

static uint32_t scan_start()
{
	uint32_t error_code = sd_ble_gap_scan_start(&m_scan_param);

	if (error_code != NRF_SUCCESS)
	{
		printf("Scan start failed\n"); fflush(stdout);
		return error_code;
	}

	printf("Scan started\n"); fflush(stdout);

	return NRF_SUCCESS;
}

static uint32_t service_discovery_start()
{
	uint16_t start_handle;
	uint32_t err_code;
	ble_uuid_t srvc_uuid;

	printf("Discovering primary services\n"); fflush(stdout);
	start_handle = 0x0001;

	srvc_uuid.type = BLE_UUID_TYPE_BLE;
	srvc_uuid.uuid = HRM_SERVICE_UUID;

	err_code = sd_ble_gattc_primary_services_discover(m_connection_handle, start_handle,
		&srvc_uuid);
	if (err_code != NRF_SUCCESS)
	{
		printf("Failed to discover primary services\n"); fflush(stdout);
		return err_code;
	}

	return NRF_SUCCESS;
}

static uint32_t char_discovery_start()
{
	uint32_t err_code;
	ble_gattc_handle_range_t handle_range;

	printf("Discovering characteristics\n"); fflush(stdout);

	handle_range.start_handle = m_service_start_handle;
	handle_range.end_handle = m_service_end_handle;

	err_code = sd_ble_gattc_characteristics_discover(m_connection_handle, &handle_range);

	return err_code;
}

static uint32_t descr_discovery_start()
{
	uint32_t err_code;
	ble_gattc_handle_range_t handle_range;

	printf("Discovering descriptors\n"); fflush(stdout);

	if (m_hrm_char_handle == 0)
	{
		printf("Error. No HRM characteristic handle has been found\n"); fflush(stdout);
		return NRF_ERROR_INVALID_STATE;
	}

	handle_range.start_handle = m_hrm_char_handle;
	handle_range.end_handle = m_service_end_handle;

	err_code = sd_ble_gattc_descriptors_discover(m_connection_handle, &handle_range);
	return err_code;
}

static uint32_t hrm_cccd_set(uint8_t value)
{
	uint32_t err_code;
	ble_gattc_write_params_t write_params;
	uint8_t cccd_value[2] = { value, 0 };

	printf("Setting HRM CCCD\n"); fflush(stdout);

	if (m_hrm_cccd_handle == 0)
	{
		printf("Error. No CCCD handle has been found\n"); fflush(stdout);
		return NRF_ERROR_INVALID_STATE;
	}

	write_params.handle = m_hrm_cccd_handle;
	write_params.len = 2;
	write_params.p_value = cccd_value;
	write_params.write_op = BLE_GATT_OP_WRITE_REQ;
	write_params.offset = 0;
	err_code = sd_ble_gattc_write(m_connection_handle, &write_params);

	return err_code;
}

static void ble_evt_dispatch(ble_evt_t * p_ble_evt)
{
	if (p_ble_evt == NULL)
	{
		printf("Received empty ble_event\n"); fflush(stdout);
		return;
	}

	switch (p_ble_evt->header.evt_id)
	{
	case BLE_GAP_EVT_CONNECTED:
		on_connected(&(p_ble_evt->evt.gap_evt));
		break;

	case BLE_GAP_EVT_DISCONNECTED:
		printf("Disconnected, reason: 0x%02X\n", p_ble_evt->evt.gap_evt.params.disconnected.reason);
		fflush(stdout);
		m_connected_devices--;
		m_connection_handle = 0;
		break;

	case BLE_GAP_EVT_ADV_REPORT:
		on_adv_report(&(p_ble_evt->evt.gap_evt));
		break;

	case BLE_GAP_EVT_TIMEOUT:
		on_timeout(&(p_ble_evt->evt.gap_evt));
		break;

	case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
		on_service_discovery_response(&(p_ble_evt->evt.gattc_evt));
		break;

	case BLE_GATTC_EVT_CHAR_DISC_RSP:
		on_characteristic_discover_response(&(p_ble_evt->evt.gattc_evt));
		break;

	case BLE_GATTC_EVT_DESC_DISC_RSP:
		on_descriptor_discover_response(&(p_ble_evt->evt.gattc_evt));
		break;

	case BLE_GATTC_EVT_WRITE_RSP:
		on_write_response(&(p_ble_evt->evt.gattc_evt));
		break;

	case BLE_GATTC_EVT_HVX:
		on_hvx(&(p_ble_evt->evt.gattc_evt));
		break;

	default:
		printf("Unhandled event with ID: %d\n", p_ble_evt->header.evt_id); fflush(stdout);
		break;
	}
}


int main(int argc, char * argv[])
{
	uint32_t error_code;
	uint8_t cccd_value;
	char *   serial_port;

	serial_port = UART_PORT_NAME;

	printf("Serial port used: %s\n", serial_port); fflush(stdout);

	sd_rpc_serial_port_name_set(serial_port);

	sd_rpc_serial_baud_rate_set(115200);

	sd_rpc_log_handler_set(log_handler);

	sd_rpc_evt_handler_set(ble_evt_dispatch);

	error_code = sd_rpc_open();

	if (error_code != NRF_SUCCESS)
	{
		printf("Failed to open the nRF51 BLE Driver. Error code: 0x%02X\n", error_code);
		fflush(stdout);
		return error_code;
	}

	scan_start();

	while (true)
	{
		getchar();
		cccd_value ^= CCCD_NOTIFY;
		hrm_cccd_set(cccd_value);
	}

	error_code = sd_rpc_close();

	if (error_code != NRF_SUCCESS)
	{
		printf("Failed to close the nRF51 BLE Driver. Error code: 0x%02X\n", error_code);
		fflush(stdout);
		return error_code;
	}

	printf("Closed\n"); fflush(stdout);

    return 0;
}

edit: Moved all the code into preformatted text. -Terje

Related