Re: [PATCH BlueZ v2] tools/mesh: Add basic sensor model

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Andri,

On Fri, 2018-08-17 at 14:35 +0000, Andri Yngvason wrote:
> This is an incomplete implementation of the sensor model. Only "get" and
> "status" are supported.
> ---
> v2:
> * Fix style issues.
> * Add length check to decode_tlv_head().
> 
>  Makefile.tools            |   3 +-
>  tools/mesh/sensor-model.c | 255 ++++++++++++++++++++++++++++++++++++++
>  tools/mesh/sensor-model.h |  36 ++++++
>  tools/meshctl.c           |   4 +
>  4 files changed, 297 insertions(+), 1 deletion(-)
>  create mode 100644 tools/mesh/sensor-model.c
>  create mode 100644 tools/mesh/sensor-model.h
> 
> diff --git a/Makefile.tools b/Makefile.tools
> index f81fd0a4c..76e37fc0d 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -308,7 +308,8 @@ tools_meshctl_SOURCES = tools/meshctl.c \
>  				tools/mesh/prov-db.h tools/mesh/prov-db.c \
>  				tools/mesh/config-model.h tools/mesh/config-client.c \
>  				tools/mesh/config-server.c \
> -				tools/mesh/onoff-model.h tools/mesh/onoff-model.c
> +				tools/mesh/onoff-model.h tools/mesh/onoff-model.c \
> +				tools/mesh/sensor-model.h tools/mesh/sensor-model.c
>  tools_meshctl_LDADD = gdbus/libgdbus-internal.la src/libshared-glib.la \
>  				lib/libbluetooth-internal.la \
>  				@GLIB_LIBS@ @DBUS_LIBS@ -ljson-c -lreadline
> diff --git a/tools/mesh/sensor-model.c b/tools/mesh/sensor-model.c
> new file mode 100644
> index 000000000..37ca55631
> --- /dev/null
> +++ b/tools/mesh/sensor-model.c
> @@ -0,0 +1,255 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2017  Intel Corporation. All rights reserved.
> + *  Copyright (C) 2018  Andri Yngvason <andri@xxxxxxxxxxx>
> + *
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, see <http://www.gnu.org/licenses/>.

Let's stay consistent with the rest of bluez and not introduce new
style for the license text.

> + *
> + */
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <inttypes.h>
> +#include <glib.h>
> +
> +#include "src/shared/shell.h"
> +#include "src/shared/util.h"
> +#include "tools/mesh/mesh-net.h"
> +#include "tools/mesh/node.h"
> +#include "tools/mesh/net.h"
> +#include "tools/mesh/util.h"
> +#include "tools/mesh/sensor-model.h"
> +
> +static uint16_t sensor_app_idx = APP_IDX_INVALID;
> +
> +static int client_bind(uint16_t app_idx, int action)
> +{
> +	if (action == ACTION_ADD) {
> +		if (sensor_app_idx != APP_IDX_INVALID)
> +			return MESH_STATUS_INSUFF_RESOURCES;
> +
> +		sensor_app_idx = app_idx;
> +		bt_shell_printf("Sensor client model: new binding %4.4x\n",
> +				app_idx);
> +	} else {
> +		if (sensor_app_idx == app_idx)
> +			sensor_app_idx = APP_IDX_INVALID;
> +	}
> +
> +	return MESH_STATUS_SUCCESS;
> +}
> +
> +static ssize_t decode_tlv_head(uint16_t *property_id, size_t *value_index,
> +					const void *data, size_t max_size)
> +{
> +	ssize_t len;
> +	const uint8_t *b = data;
> +
> +	if (max_size == 0)
> +		return -1;
> +
> +	if (b[0] & 1) {
> +
> +		if (max_size < 3)
> +			return -1;
> +
> +		len = b[0] >> 1;
> +		*property_id = b[1] | b[2] << 8;
> +		*value_index = 3;
> +	} else {
> +
> +		if (max_size < 2)
> +			return -1;
> +
> +		len = (b[0] >> 1) & 7;
> +		*property_id = b[0] >> 4 | b[1];
> +		*value_index = 2;
> +	}
> +
> +	return max_size >= *value_index + len ? len : -1;
> +}
> +
> +/*
> + * TODO: The sensor value size, signedness and multiplier should be based on the
> + * property id.
> + */
> +static int32_t convert_sensor_value(const void *data, size_t len)
> +{
> +	const uint8_t *b = data;
> +
> +	switch (len) {
> +	case 1: return (int8_t)b[0];
> +	case 2: return (int16_t)(b[0] | b[1] << 8);
> +	case 4: return (int32_t)(b[0] | b[1] << 8 | b[2] << 16 | b[3] << 24);
> +	}
> +
> +	return 0;
> +}
> +
> +static void interpret_sensor_status(const void *data, size_t size)
> +{
> +	ssize_t len;
> +	size_t i;
> +	size_t value_index = 0;
> +	const uint8_t *b = data;
> +
> +	for (i = 0; i < size; i += len + value_index) {
> +		uint16_t property_id = 0;
> +		const char *property_name;
> +		int32_t value;
> +
> +		len = decode_tlv_head(&property_id, &value_index, &b[i],
> +								size - i);
> +
> +		if (len < 0)
> +			return;
> +
> +		property_name = bt_uuid16_to_str(property_id);
> +		value = convert_sensor_value(&b[i + value_index], len);
> +
> +		if (property_name)
> +			bt_shell_printf("%s: %" PRIi32 "\n", property_name,
> +					value);
> +		else
> +			bt_shell_printf("%x: %" PRIi32 "\n", property_id,
> +					value);
> +	}
> +}
> +
> +static bool client_msg_received(uint16_t src, uint8_t *data, uint16_t len,
> +				void *userdata)
> +{
> +	uint32_t opcode;
> +	int n;
> +
> +	if (!mesh_opcode_get(data, len, &opcode, &n))
> +		return false;
> +
> +	len -= n;
> +	data += n;
> +
> +	bt_shell_printf("Sensor Model Message received (%d) opcode %x\n",
> +			len, opcode);
> +
> +	print_byte_array("\t", data, len);
> +
> +	switch (opcode & ~OP_UNRELIABLE) {
> +	default:
> +		return false;
> +
> +	case OP_SENSOR_STATUS:
> +		bt_shell_printf("Node %4.4x:\n", src);
> +		interpret_sensor_status(data, len);
> +		break;
> +	}
> +
> +	return true;
> +}
> +
> +static uint32_t target;
> +
> +static bool send_cmd(uint8_t *buf, uint16_t len)
> +{
> +	struct mesh_node *node = node_get_local_node();
> +	uint8_t ttl;
> +
> +	if (!node)
> +		return false;
> +
> +	ttl = node_get_default_ttl(node);
> +
> +	return net_access_layer_send(ttl, node_get_primary(node),
> +					target, sensor_app_idx, buf, len);
> +}
> +
> +static void cmd_set_node(int argc, char *argv[])
> +{
> +	uint32_t dst;
> +	char *end;
> +
> +	dst = strtol(argv[1], &end, 16);
> +
> +	if (end == (argv[1] + 4)) {
> +		bt_shell_printf("Controlling sensor for node %4.4x\n", dst);
> +		target = dst;
> +		set_menu_prompt("sensor", argv[1]);
> +		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
> +	}
> +
> +	bt_shell_printf("Bad unicast address %s: expected format 4 digit hex\n",
> +			argv[1]);
> +	target = UNASSIGNED_ADDRESS;
> +	return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +}
> +
> +/* TODO: Requesting a specific profile id is not supported.  */
> +static void cmd_get(int argc, char *argv[])
> +{
> +	uint16_t n;
> +	uint8_t msg[32];
> +	struct mesh_node *node;
> +
> +	if (IS_UNASSIGNED(target)) {
> +		bt_shell_printf("Destination not set\n");
> +		return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +	}
> +
> +	node = node_find_by_addr(target);
> +
> +	if (!node)
> +		return;
> +
> +	n = mesh_opcode_set(OP_SENSOR_GET, msg);
> +
> +	if (!send_cmd(msg, n)) {
> +		bt_shell_printf("Failed to send \"SENSOR GET\"\n");
> +		return bt_shell_noninteractive_quit(EXIT_FAILURE);
> +	}
> +
> +	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
> +}
> +
> +static const struct bt_shell_menu sensor_menu = {
> +	.name = "sensor",
> +	.desc = "Sensor Model Submenu",
> +	.entries = {
> +		{ "target", "<unicast>", cmd_set_node,
> +						"Set node to configure" },
> +		{ "get", NULL, cmd_get, "Get sensor status" },
> +		{ }
> +	},
> +};
> +
> +static struct mesh_model_ops client_cbs = {
> +	client_msg_received,
> +	client_bind,
> +	NULL,
> +	NULL,
> +};
> +
> +bool sensor_client_init(uint8_t element)
> +{
> +	if (!node_local_model_register(element, SENSOR_CLIENT_MODEL_ID,
> +				       &client_cbs, NULL))
> +		return false;
> +
> +	bt_shell_add_submenu(&sensor_menu);
> +
> +	return true;
> +}
> diff --git a/tools/mesh/sensor-model.h b/tools/mesh/sensor-model.h
> new file mode 100644
> index 000000000..0c8d88a52
> --- /dev/null
> +++ b/tools/mesh/sensor-model.h
> @@ -0,0 +1,36 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2018  Andri Yngvason <andri@xxxxxxxxxxx>
> + *
> + *
> + *  This library is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU Lesser General Public
> + *  License as published by the Free Software Foundation; either
> + *  version 2.1 of the License, or (at your option) any later version.
> + *
> + *  This library is distributed in the hope that it will be useful,
> + *  but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + *  Lesser General Public License for more details.
> + *
> + *  You should have received a copy of the GNU Lesser General Public
> + *  License along with this library; if not, see <http://www.gnu.org/licenses/>.

Same here: Let's stay consistent with the rest of bluez.

> + *
> + */
> +
> +#define SENSOR_SERVER_MODEL_ID 0x1100
> +#define SENSOR_CLIENT_MODEL_ID 0x1102
> +
> +#define OP_SENSOR_DESCRIPTOR_GET 0x8230
> +#define OP_SENSOR_DESCRIPTOR_STATUS 0x51
> +#define OP_SENSOR_GET 0x8231
> +#define OP_SENSOR_STATUS 0x52
> +#define OP_SENSOR_COLUMN_GET 0x8232
> +#define OP_SENSOR_COLUMN_STATUS 0x53
> +#define OP_SENSOR_SERIES_GET 0x8233
> +#define OP_SENSOR_SERIES_STATUS 0x54
> +
> +void sensor_set_node(const char *args);
> +bool sensor_client_init(uint8_t element);
> diff --git a/tools/meshctl.c b/tools/meshctl.c
> index 3e1484f61..08bba9a13 100644
> --- a/tools/meshctl.c
> +++ b/tools/meshctl.c
> @@ -58,6 +58,7 @@
>  #include "mesh/prov-db.h"
>  #include "mesh/config-model.h"
>  #include "mesh/onoff-model.h"
> +#include "mesh/sensor-model.h"
>  
>  /* String display constants */
>  #define COLORED_NEW	COLOR_GREEN "NEW" COLOR_OFF
> @@ -1990,6 +1991,9 @@ int main(int argc, char *argv[])
>  	if (!onoff_client_init(PRIMARY_ELEMENT_IDX))
>  		g_printerr("Failed to initialize mesh generic On/Off client\n");
>  
> +	if (!sensor_client_init(PRIMARY_ELEMENT_IDX))
> +		g_printerr("Failed to initialize mesh sensor client\n");
> +

I suggest that you add the model id for sensor client to the device
composition section in local_node.json. 
Otherwise, meshctl will print the above error and fail to initialize
sensor menu. 


>  	status = bt_shell_run();
>  
>  	g_dbus_client_unref(client);
> 

Regards,
Inga




[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux