[PATCH 5/6] tools/mesh-gatt: Add generic level model support
From: <hidden>
Date: 2021-12-03 16:09:55
Subsystem:
the rest · Maintainer:
Linus Torvalds
--- Makefile.tools | 4 +- tools/mesh-gatt/level-model.c | 288 ++++++++++++++++++++++++++++++++ tools/mesh-gatt/level-model.h | 21 +++ tools/mesh-gatt/local_node.json | 6 +- tools/meshctl.c | 4 + 5 files changed, 321 insertions(+), 2 deletions(-) create mode 100644 tools/mesh-gatt/level-model.c create mode 100644 tools/mesh-gatt/level-model.h
diff --git a/Makefile.tools b/Makefile.tools
index c7bdff83f..c0d2e27de 100644
--- a/Makefile.tools
+++ b/Makefile.tools@@ -331,7 +331,9 @@ tools_meshctl_SOURCES = tools/meshctl.c \ tools/mesh-gatt/config-client.c \ tools/mesh-gatt/config-server.c \ tools/mesh-gatt/onoff-model.h \ - tools/mesh-gatt/onoff-model.c + tools/mesh-gatt/onoff-model.c \ + tools/mesh-gatt/level-model.h \ + tools/mesh-gatt/level-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-gatt/level-model.c b/tools/mesh-gatt/level-model.c
new file mode 100644
index 000000000..6feb89d5d
--- /dev/null
+++ b/tools/mesh-gatt/level-model.c@@ -0,0 +1,288 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdbool.h> +#include <inttypes.h> +#include <stdbool.h> +#include <sys/uio.h> +#include <wordexp.h> +#include <readline/readline.h> +#include <readline/history.h> +#include <glib.h> + +#include "src/shared/shell.h" +#include "src/shared/util.h" + +#include "tools/mesh-gatt/mesh-net.h" +#include "tools/mesh-gatt/keys.h" +#include "tools/mesh-gatt/net.h" +#include "tools/mesh-gatt/node.h" +#include "tools/mesh-gatt/prov-db.h" +#include "tools/mesh-gatt/util.h" +#include "tools/mesh-gatt/level-model.h" + +static uint8_t trans_id; +static uint16_t level_app_idx = APP_IDX_INVALID; +static int client_bind(uint16_t app_idx, int action) +{ + if (action == ACTION_ADD) { + if (level_app_idx != APP_IDX_INVALID) { + return MESH_STATUS_INSUFF_RESOURCES; + } else { + level_app_idx = app_idx; + bt_shell_printf("Level client model: new binding" + " %4.4x\n", app_idx); + } + } else { + if (level_app_idx == app_idx) + level_app_idx = APP_IDX_INVALID; + } + return MESH_STATUS_SUCCESS; +} +static void print_remaining_time(uint8_t remaining_time) +{ + uint8_t step = (remaining_time & 0xc0) >> 6; + uint8_t count = remaining_time & 0x3f; + int secs = 0, msecs = 0, minutes = 0, hours = 0; + switch (step) { + case 0: + msecs = 100 * count; + secs = msecs / 1000; + msecs -= (secs * 1000); + break; + case 1: + secs = 1 * count; + minutes = secs / 60; + secs -= (minutes * 60); + break; + case 2: + secs = 10 * count; + minutes = secs / 60; + secs -= (minutes * 60); + break; + case 3: + minutes = 10 * count; + hours = minutes / 60; + minutes -= (hours * 60); + break; + default: + break; + } + bt_shell_printf("\n\t\tRemaining time: %d hrs %d mins %d secs %d" + " msecs\n", hours, minutes, secs, msecs); +} +static bool client_msg_recvd(uint16_t src, uint8_t *data, + uint16_t len, void *user_data) +{ + uint32_t opcode; + int n; + uint8_t *p; + int16_t lev; + char s[128]; + + if (mesh_opcode_get(data, len, &opcode, &n)) { + len -= n; + data += n; + } else + return false; + + switch (opcode) { + default: + return false; + case OP_GENERIC_LEVEL_STATUS: + bt_shell_printf("Level Model Message received (%d) opcode
%x\n",
+ len, opcode);
+ print_byte_array("\t",data, len);
+
+ if (len != 2 && len != 4 && len != 5)
+ break;
+ lev = 0;
+ p = (uint8_t *)&lev;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ p[0] = data[0];
+ p[1] = data[1];
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ p[1] = data[0];
+ p[0] = data[1];
+#else
+#error "Unknown byte order"
+#error Processor endianness unknown!
+#endif
+ sprintf(s, "Node %4.4x: Level Status present = %d",
+ src, lev);
+ if (len >= 4) {
+ lev = (int16_t)(((uint16_t)data[3] << 8) |
(uint16_t)data[2]);
+ sprintf(s, ", target = %d",
+ lev);
+ }
+ bt_shell_printf("%s\n", s);
+ if(len == 5){
+ print_remaining_time(data[4]);
+ }
+ break;
+ }
+ return true;
+}
+static uint32_t target;
+static int32_t parms[8];
+static uint32_t read_input_parameters(int argc, char *argv[])
+{
+ uint32_t i;
+ if (!argc)
+ return 0;
+ --argc;
+ ++argv;
+ if (!argc || argv[0][0] == '\0')
+ return 0;
+ for (i = 0; i < sizeof(parms)/sizeof(parms[0]) && i < (unsigned)
argc;
+ i++) {
+ if(sscanf(argv[i], "%d", &parms[i]) <= 0)
+ break;
+ }
+ return i;
+}
+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("Bad unicast address %s: "
+ "expected format 4 digit hex\n", argv[1]);
+ target = UNASSIGNED_ADDRESS;
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ } else {
+ bt_shell_printf("Controlling Level for node %4.4x\n", dst);
+ target = dst;
+ set_menu_prompt("Level", argv[1]);
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+ }
+}
+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, level_app_idx, buf, len);
+}
+static void cmd_get_status(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){
+ bt_shell_printf("Warning: node %4.4x not found in
database\n",target);
+ }
+
+ n = mesh_opcode_set(OP_GENERIC_LEVEL_GET, msg);
+ if (!send_cmd(msg, n)) {
+ bt_shell_printf("Failed to send \"GENERIC LEVEL GET\"\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+}
+static void cmd_set(int argc, char *argv[])
+{
+ uint16_t n;
+ uint8_t msg[32];
+ struct mesh_node *node;
+ uint8_t *p;
+ int np;
+ uint32_t opcode;
+ int16_t level;
+
+ 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){
+ bt_shell_printf("Warning: node %4.4x not found in
database\n",target);
+ }
+
+ np = read_input_parameters(argc, argv);
+ if ((np != 1) && (np != 2) &&
+ parms[0] < -32768 && parms[0] > 32767 &&
+ parms[1] != 0 && parms[1] != 1) {
+ bt_shell_printf("Bad arguments: Expecting an integer "
+ "-32768 to 32767 and an optional 0 or 1 as
unack\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+
+ if( (np==2) && parms[1] ){
+ opcode = OP_GENERIC_LEVEL_SET_UNACK;
+ }else{
+ opcode = OP_GENERIC_LEVEL_SET;
+ }
+
+ n = mesh_opcode_set(opcode, msg);
+ level = (int16_t)parms[0];
+ p = (uint8_t *)&level;
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ msg[n++] = p[0];
+ msg[n++] = p[1];
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ msg[n++] = p[1];
+ msg[n++] = p[0];
+#else
+#error "Unknown byte order"
+#error Processor endianness unknown!
+#endif
+ msg[n++] = trans_id++;
+ if (!send_cmd(msg, n)) {
+ bt_shell_printf("Failed to send \"GENERIC LEVEL SET\"\n");
+ return bt_shell_noninteractive_quit(EXIT_FAILURE);
+ }
+ return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+}
+static const struct bt_shell_menu level_menu = {
+ .name = "level",
+ .desc = "Level Model Submenu",
+ .entries = {
+ {"target", "<unicast>",
cmd_set_node,
+ "Set node to configure"},
+ {"get", NULL,
cmd_get_status,
+ "Get Level status"},
+ {"level", "<-32768/+32767> [unack]",
cmd_set,
+ "Send \"SET Level\" command"},
+ {} },
+};
+static struct mesh_model_ops client_cbs = {
+ client_msg_recvd,
+ client_bind,
+ NULL,
+ NULL
+};
+bool level_client_init(uint8_t ele)
+{
+ if (!node_local_model_register(ele, GENERIC_LEVEL_CLIENT_MODEL_ID,
+ &client_cbs, NULL))
+ return false;
+ bt_shell_add_submenu(&level_menu);
+ return true;
+}diff --git a/tools/mesh-gatt/level-model.h b/tools/mesh-gatt/level-model.h
new file mode 100644
index 000000000..1c8b5f72e
--- /dev/null
+++ b/tools/mesh-gatt/level-model.h@@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * + * BlueZ - Bluetooth protocol stack for Linux + * + * Copyright (C) 2017 Intel Corporation. All rights reserved. + * + * + */ +#define GENERIC_LEVEL_SERVER_MODEL_ID 0x1002 +#define GENERIC_LEVEL_CLIENT_MODEL_ID 0x1003 +#define OP_GENERIC_LEVEL_GET 0x8205 +#define OP_GENERIC_LEVEL_SET 0x8206 +#define OP_GENERIC_LEVEL_SET_UNACK 0x8207 +#define OP_GENERIC_LEVEL_STATUS 0x8208 +#define OP_GENERIC_DELTA_SET 0x8209 +#define OP_GENERIC_DELTA_SET_UNACK 0x820A +#define OP_GENERIC_MOVE_SET 0x820B +#define OP_GENERIC_MOVE_SET_UNACK 0x820C +void level_set_node(const char *args); +bool level_client_init(uint8_t ele);
diff --git a/tools/mesh-gatt/local_node.jsonb/tools/mesh-gatt/local_node.json index 5ffa7ada1..462cd815d 100644
--- a/tools/mesh-gatt/local_node.json
+++ b/tools/mesh-gatt/local_node.json@@ -36,7 +36,7 @@ { "elementIndex": 0, "location": "0001", - "models": ["0000", "0001", "1001"] + "models": ["0000", "0001", "1001", "1003"] } ] },
@@ -52,6 +52,10 @@ { "modelId": "1001", "bind": [1] + }, + { + "modelId": "1003", + "bind": [1] } ] }
diff --git a/tools/meshctl.c b/tools/meshctl.c
index 18e20c40d..69f8d412f 100644
--- a/tools/meshctl.c
+++ b/tools/meshctl.c@@ -48,6 +48,7 @@ #include "mesh-gatt/util.h" #include "mesh-gatt/prov-db.h" #include "mesh-gatt/onoff-model.h" +#include "mesh-gatt/level-model.h" /* String display constants */ #define COLORED_NEW COLOR_GREEN "NEW" COLOR_OFF
@@ -1999,6 +2000,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 (!level_client_init(PRIMARY_ELEMENT_IDX))
+ g_printerr("Failed to initialize mesh generic level
client\n");
+
status = bt_shell_run();
g_dbus_client_unref(client);
--
2.25.1