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

Mesh Opcodes and linking them to the handler in the access layer

I've been writing a vendor model for Bluetooth mesh based on the light lightness model in the SDK. I'm extending the generic level model into my model - a window openess level model. It's far complete, but it's to the point where I want to be able to receive generic level model messages from the NRF Mesh app. I've been investigating what happens when I receive a mesh message and how it propagates to the user call backs.

I'm developing on a Windows 10 machine, using SES 4.52c using SDK 16.0 and Mesh SDK 4.1.0.

I get my mesh message and it arrives in access.c. On line 1070 the opcode handler is called, but that it where the program dead ends and never calls into my model. I'm not sure what I am missing that links the opcodes to the function in my model.

static const access_opcode_handler_t m_opcode_handlers[] =
{
	{ACCESS_OPCODE_VENDOR(WINDOW_CONTROL_OPCODE_SET, ACCESS_COMPANY_ID_NORDIC), handle_default_set},
	{ACCESS_OPCODE_VENDOR(WINDOW_CONTROL_OPCODE_SET_UNACKNOWLEDGED, ACCESS_COMPANY_ID_NORDIC), handle_default_set},
	{ACCESS_OPCODE_VENDOR(WINDOW_CONTROL_OPCODE_GET, ACCESS_COMPANY_ID_NORDIC), handle_default_set},
	{ACCESS_OPCODE_VENDOR(WINDOW_CONTROL_OPCODE_STATUS, ACCESS_COMPANY_ID_NORDIC), handle_default_set},
};

I have a function handle_default_set() that is never called (right now all opcodes refer to the same handle_default_set(), even the get functions).

The block of code that should establish the link to these opcode function as far as I understand it is this:

static uint32_t window_control_server_init(window_ctrl_server_t * p_server,
													uint8_t element_index)
{
	uint32_t status;

	if (!(p_server
		&& p_server->settings.p_callbacks
		&& p_server->settings.p_callbacks->window_control_cbs.set_cb
		&& p_server->settings.p_callbacks->window_control_cbs.get_cb))
	{
		return NRF_ERROR_NULL;
	}

	if (m_total_wc_instances >= WINDOW_CONTROL_SETUP_SERVER_INSTANCES_MAX)
	{
		return NRF_ERROR_RESOURCES;
	}

	p_server->settings.element_index = element_index;

	/* Initialize parent model instances - Generic Level */
	p_server->generic_level_srv.settings.p_callbacks = &m_level_srv_cbs;


	do
	{
		if (NRF_SUCCESS != (status = generic_level_server_init(&p_server->generic_level_srv, element_index)))
		{
			break;
		}

		if (NRF_SUCCESS != (status = access_model_subscription_list_dealloc(p_server->generic_level_srv.model_handle)))
		{
			break;
		}

		/* Add this window control server model to the mesh */
		access_model_add_params_t init_params =
			{
				.model_id = ACCESS_MODEL_VENDOR(WINDOW_CONTROL_SERVER_MODEL_ID, ACCESS_COMPANY_ID_NORDIC),
				.element_index =  element_index,
				.p_opcode_handlers = &m_opcode_handlers[0],
				.opcode_count = ARRAY_SIZE(m_opcode_handlers),
				.p_args = p_server,
			};

		if (NRF_SUCCESS != (status = access_model_add(&init_params, &p_server->model_handle)))
		{
			break;
		}

		/* Window control Server sets up its subscription list, then
		 * shares it wiS != (status = access_model_subscription_list_alloc(p_server->model_handle)))
		{th each of its extended models */
		if (NRF_SUCCES
			break;
		}
		if (NRF_SUCCESS != (status = access_model_subscription_lists_share(p_server->model_handle,
											p_server->generic_level_srv.model_handle)))
		{
			break;
		}
	} while (0);

	if (NRF_SUCCESS == status)
	{
		m_total_wc_instances++;
	}

	return status;
}

access_model_add()  should register the opcodes and handlers with the access layer and allow my handle_default_set() to be called from line 1070 in access.c. I appear to be missing something else to establish that link. Where should I look?

/* Vendor client opcodes must follow this format: 0b11xxxxxx */
typedef enum
{
	WINDOW_CONTROL_OPCODE_SET					=	0xC0,
	WINDOW_CONTROL_OPCODE_SET_UNACKNOWLEDGED	=	0xC1,
	WINDOW_CONTROL_OPCODE_GET					=	0xC2,
	WINDOW_CONTROL_OPCODE_STATUS				=	0xC3,
} window_control_opcode_t;

Above is my opcode enumeration.

  • It turns out that my issue was that I was not looking in the right place. I figured that as soon as i posted something I'd get a lead on a new idea.  I was actually getting a callback from the generic level model, but it was linked to a stub function I had made in my new model. I had the regular level callbacks with a proto-implementation, not for the delta level callbacks. It appears that the app sends level commands for the generic lever server as a change in level (delta) rather than a set to a specific level. Now I can see that callback and I am stitching it into my normal window controller callback, so the issue is solved.

Related