diff mbox series

[BlueZ,5/6] tools/mesh-gatt: Add generic level model support

Message ID 20211207225604.35156-6-daniele.biagetti@cblelectronics.com
State New
Headers show
Series tools/mesh-gatt meshctl tool improvements | expand

Commit Message

Daniele Biagetti Dec. 7, 2021, 10:56 p.m. UTC
---
 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 mbox series

Patch

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.json b/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);