All of lore.kernel.org
 help / color / mirror / Atom feed
From: Daniele Biagetti <dbiagio79@gmail.com>
To: linux-bluetooth@vger.kernel.org
Cc: Daniele Biagetti <daniele.biagetti@cblelectronics.com>
Subject: [PATCH BlueZ 5/6] tools/mesh-gatt: Add generic level model support
Date: Tue,  7 Dec 2021 23:56:03 +0100	[thread overview]
Message-ID: <20211207225604.35156-6-daniele.biagetti@cblelectronics.com> (raw)
In-Reply-To: <20211207225604.35156-1-daniele.biagetti@cblelectronics.com>

---
 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.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);
-- 
2.25.1


  parent reply	other threads:[~2021-12-07 22:56 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-07 22:55 [PATCH BlueZ 0/6] tools/mesh-gatt meshctl tool improvements Daniele Biagetti
2021-12-07 22:55 ` [PATCH BlueZ 1/6] tools/mesh-gatt: Add onoff set unack message to onoff client model Daniele Biagetti
2021-12-07 23:39   ` tools/mesh-gatt meshctl tool improvements bluez.test.bot
2021-12-07 22:56 ` [PATCH BlueZ 2/6] tools/mesh-gatt: Fix status messages processing Daniele Biagetti
2021-12-07 22:56 ` [PATCH BlueZ 3/6] tools/mesh-gatt: Fix unwanted return in onoff client model Daniele Biagetti
2021-12-07 22:56 ` [PATCH BlueZ 4/6] tools/mesh-gatt: Add subscription delete message to config " Daniele Biagetti
2021-12-07 22:56 ` Daniele Biagetti [this message]
2021-12-07 22:56 ` [PATCH BlueZ 6/6] tools/mesh-gatt: Add generic power onoff " Daniele Biagetti
2021-12-09 20:15 ` [PATCH BlueZ 0/6] tools/mesh-gatt meshctl tool improvements Tedd Ho-Jeong An

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20211207225604.35156-6-daniele.biagetti@cblelectronics.com \
    --to=dbiagio79@gmail.com \
    --cc=daniele.biagetti@cblelectronics.com \
    --cc=linux-bluetooth@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.