Mesh: Add mesh model support 12/240012/1
authorAbhay Agarwal <ay.agarwal@samsung.com>
Fri, 31 Jul 2020 03:18:38 +0000 (08:48 +0530)
committerAbhay Agarwal <ay.agarwal@samsung.com>
Fri, 31 Jul 2020 10:36:13 +0000 (16:06 +0530)
This patch add mesh model support in bluetooth service.
This interface can be used for mesh model communications.

Change-Id: I7cf6a2d896cfb06e5b31871eb356b2a0cbdc1bec
Signed-off-by: Abhay Agarwal <ay.agarwal@samsung.com>
bt-service/CMakeLists.txt
bt-service/services/include/bt-service-mesh-model.h [new file with mode: 0644]
bt-service/services/mesh/bt-service-mesh-model.c [new file with mode: 0644]

index 51f5814..71abba0 100644 (file)
@@ -38,6 +38,7 @@ SET(SRCS
 ./services/mesh/bt-service-mesh-network.c
 ./services/mesh/bt-service-mesh-main.c
 ./services/mesh/bt-service-mesh-config-client.c
+./services/mesh/bt-service-mesh-model.c
 )
 
 IF("$ENV{CFLAGS}" MATCHES "-DTIZEN_FEATURE_BT_OBEX")
diff --git a/bt-service/services/include/bt-service-mesh-model.h b/bt-service/services/include/bt-service-mesh-model.h
new file mode 100644 (file)
index 0000000..21da36d
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Abhay Agarwal <ay.agarwal@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *              http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef BT_SERVICE_MESH_MODEL_H_
+#define BT_SERVICE_MESH_MODEL_H_
+
+#include <glib.h>
+#include <sys/types.h>
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include <json-c/json.h>
+#include "oal-mesh.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void _bt_mesh_msg_handler(
+               event_mesh_message_t *event);
+
+int _bt_mesh_node_model_execute_msg(const char *app_cred,
+               const char *sender,
+                       bluetooth_mesh_model_msg_t *req);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* BT_SERVICE_MESH_MODEL_H_*/
diff --git a/bt-service/services/mesh/bt-service-mesh-model.c b/bt-service/services/mesh/bt-service-mesh-model.c
new file mode 100644 (file)
index 0000000..6eebdfd
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Bluetooth-frwk
+ *
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ *
+ * @author: Abhay Agarwal <ay.agarwal@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *              http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <glib.h>
+#include <dlog.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <ell/ell.h>
+
+#include "bt-service-common.h"
+#include "bt-service-core-adapter.h"
+#include "bt-service-event-receiver.h"
+#include "bt-request-handler.h"
+#include "bluetooth-api.h"
+
+#include "bluetooth-api.h"
+#include "bluetooth-mesh-api.h"
+#include "bt-internal-types.h"
+#include "bt-service-util.h"
+#include "bt-service-common.h"
+#include "bt-service-core-adapter.h"
+#include "bt-service-event-receiver.h"
+#include "bt-request-handler.h"
+#include "bluetooth-api.h"
+#include "bt-service-event.h"
+
+#include "bt-service-mesh-network.h"
+#include "bt-service-mesh-cdb.h"
+#include "bt-service-mesh-nodes.h"
+#include "bt-service-mesh-keys.h"
+#include "bt-service-mesh-util.h"
+#include "bt-service-mesh-config-client.h"
+
+#include <oal-hardware.h>
+#include <oal-manager.h>
+#include <oal-event.h>
+#include <oal-adapter-mgr.h>
+#include <oal-device-mgr.h>
+#include <oal-mesh.h>
+
+#include "bt-internal-types.h"
+
+#define MESH_CONFIG_BUFFER_MAX_LEN 100
+
+static void __bt_mesh_handle_pending_msg_request_info(int result,
+               int service_function, void *param,
+                       unsigned int size);
+
+struct mesh_msg_cmd {
+       uint32_t opcode;
+       uint32_t response;
+       const char *descriptor;
+};
+
+static struct l_queue *pending_msg_requests;
+
+struct mesh_pending_request {
+       struct l_timeout *timer;
+       const struct mesh_msg_cmd *cmd;
+       uint8_t net_uuid[16];
+       uint16_t addr;
+       void *data;
+};
+
+static struct mesh_msg_cmd commands[] = {
+       { MESH_OPCODE_MODEL_GENERIC_ONOFF_GET, MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS, "ModelGenericOnoffGet" },
+       { MESH_OPCODE_MODEL_GENERIC_ONOFF_SET, MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS, "ModelGenericOnoffSet" },
+       { MESH_OPCODE_MODEL_GENERIC_ONOFF_SET_UNACK, MESH_RESPONSE_NONE, "ModelGenericOnoffSetUnack" },
+       { MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS, MESH_RESPONSE_NONE, "ModelGenericOnoffStatus" }
+};
+
+
+static const struct mesh_msg_cmd *__mesh_get_command(uint32_t opcode)
+{
+       uint32_t n;
+
+       for (n = 0; n < L_ARRAY_SIZE(commands); n++) {
+               if (opcode == commands[n].opcode)
+                       return &commands[n];
+       }
+
+       return NULL;
+}
+
+static const char *__mesh_get_opcode_string(uint32_t opcode)
+{
+       const struct mesh_msg_cmd *cmd;
+
+       cmd = __mesh_get_command(opcode);
+       if (!cmd)
+               return "Unknown Command Received";
+
+       return cmd->descriptor;
+}
+
+static void __mesh_request_remove(void *a)
+{
+       struct mesh_pending_request *req = a;
+
+       if (req->data)
+               l_free(req->data);
+       l_timeout_remove(req->timer);
+       l_free(req);
+}
+
+static void __bt_mesh_wait_response_timeout(
+               struct l_timeout *timeout, void *user_data)
+{
+       struct mesh_pending_request *req = user_data;
+
+       BT_INFO("Mesh: No response for \"%s\" from %4.4x\n",
+                       req->cmd->descriptor, req->addr);
+
+
+       switch(req->cmd->opcode) {
+       case MESH_OPCODE_MODEL_GENERIC_ONOFF_GET:
+       case MESH_OPCODE_MODEL_GENERIC_ONOFF_SET:
+               /* Send event with timeout */
+                __bt_mesh_handle_pending_msg_request_info(
+                       BLUETOOTH_ERROR_TIMEOUT,
+                               BT_MESH_MODEL_EXECUTE_MSG, req->data,
+                                       sizeof(bluetooth_mesh_model_msg_t));
+               break;
+       default:
+               break;
+       }
+       BT_INFO("Mesh: Number of pending requests [%u] Remove the req",
+               l_queue_length(pending_msg_requests));
+       l_queue_remove(pending_msg_requests, req);
+       __mesh_request_remove(req);
+}
+
+static void __bt_mesh_add_request(uint32_t opcode, uint16_t dest,
+                       uint8_t net_uuid[], void *data)
+{
+       struct mesh_pending_request *req;
+       const struct mesh_msg_cmd *cmd;
+       char uuid_str[33];
+
+       cmd = __mesh_get_command(opcode);
+       if (!cmd)
+               return;
+       _bt_mesh_util_convert_hex_to_string((uint8_t *) net_uuid, 16, uuid_str,
+               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+       BT_INFO("Mesh: Net UUID[%s]",uuid_str);
+
+       BT_INFO("Mesh: Adding command opcode [0x%2.2x] response [0x%2.2x]",
+                       cmd->opcode, cmd->response);
+       req = l_new(struct mesh_pending_request, 1);
+       req->cmd = cmd;
+       req->addr = dest;
+       req->data = data;
+       memcpy(req->net_uuid, net_uuid, 16);
+       req->timer = l_timeout_create(MESH_DEFAULT_RESPONSE_TIMEOUT,
+                       __bt_mesh_wait_response_timeout, req, NULL);
+
+       if (!pending_msg_requests)
+               pending_msg_requests = l_queue_new();
+       l_queue_push_tail(pending_msg_requests, req);
+       BT_INFO("Mesh: Number of pending requests [%u]", l_queue_length(pending_msg_requests));
+}
+
+static struct mesh_pending_request *__bt_mesh_get_request_by_response(
+               uint16_t addr, uint8_t net_uuid[],
+                       uint32_t response)
+{
+       const struct l_queue_entry *entry;
+       char uuid_str[33];
+       char uuid_str1[33];
+
+       BT_INFO("Mesh: Number of pending requests [%u]", l_queue_length(pending_msg_requests));
+       entry = l_queue_get_entries(pending_msg_requests);
+
+       for (; entry; entry = entry->next) {
+               struct mesh_pending_request *req = entry->data;
+
+               /* Test */
+               BT_INFO("Mesh: Req addr [0x%4.4x] req opcode [0x%4.4x] res [0x%4.4x]", req->addr, req->cmd->opcode, req->cmd->response);
+               BT_INFO("Mesh: Current req addr [0x%4.4x] res [0x%4.4x]", addr, response);
+               _bt_mesh_util_convert_hex_to_string((uint8_t *) net_uuid, 16, uuid_str,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+               BT_INFO("Mesh: Net UUID[%s]",uuid_str);
+
+               _bt_mesh_util_convert_hex_to_string((uint8_t *) req->net_uuid, 16, uuid_str1,
+                               BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+               BT_INFO("Mesh: Net UUID1[%s]",uuid_str1);
+               if (!memcmp(net_uuid, req->net_uuid, 16) &&
+                               req->addr == addr &&
+                               req->cmd->response == response)
+                       return req;
+       }
+
+       return NULL;
+}
+
+bool _bt_mesh_check_pending_request(uint32_t opcode,
+               uint16_t dest, uint8_t net_uuid[])
+{
+       const struct mesh_msg_cmd *cmd;
+       cmd = __mesh_get_command(opcode);
+
+       if (!cmd)
+               return false;
+
+       if (__bt_mesh_get_request_by_response(dest,
+                               net_uuid, cmd->response)) {
+               BT_ERR("Mesh:Another command is pending\n");
+               return true;
+       }
+       return false;
+}
+
+static void __bt_mesh_send_model_msg_event(int result,
+               bluetooth_mesh_model_msg_t *evt)
+{
+       GVariant *out_var = NULL, *param = NULL;
+       GArray *info = NULL;
+
+       if (BLUETOOTH_ERROR_NONE == result) {
+               /* Send event */
+               info = g_array_new(FALSE, FALSE, sizeof(gchar));
+               g_array_append_vals(info, evt,
+                               sizeof(bluetooth_mesh_model_msg_t));
+
+               out_var = g_variant_new_from_data((const GVariantType *)"ay",
+                               info->data, info->len,
+                               TRUE, NULL, NULL);
+
+               param = g_variant_new("(iv)", result, out_var);
+               _bt_send_event(BT_MESH_EVENT,
+                               BLUETOOTH_EVENT_MESH_MODEL_MSG_EXECUTED,
+                               param);
+       }
+}
+
+static void __bt_mesh_handle_pending_msg_request_info(int result,
+               int service_function, void *param, unsigned int size)
+{
+       GSList *l;
+       GArray *out_param;
+       invocation_info_t *req_info = NULL;
+
+       for (l = _bt_get_invocation_list(); l != NULL; ) {
+               req_info = l->data;
+               l = g_slist_next(l);
+               if (req_info == NULL ||
+                               req_info->service_function != service_function)
+                       continue;
+
+               switch (service_function) {
+               case BT_MESH_MODEL_EXECUTE_MSG: {
+                       bluetooth_mesh_model_msg_t *event;
+                       bluetooth_mesh_model_msg_t *req;
+
+                       event = (bluetooth_mesh_model_msg_t*) param;
+                       req = (bluetooth_mesh_model_msg_t*)req_info->user_data;
+
+                       BT_DBG("Request Sender: [%s]", req_info->sender);
+                       /* Match Network and Remote Node unicast*/
+                       if (!g_strcmp0(event->net_uuid, req->net_uuid) &&
+                               event->primary_unicast == req->primary_unicast) {
+                               event->elem_index = req->elem_index;
+
+                               /* Send Event */
+                               __bt_mesh_send_model_msg_event(result, event);
+
+                               out_param = g_array_new(FALSE, FALSE, sizeof(gchar));
+                               g_array_append_vals(out_param, event, sizeof(bluetooth_mesh_model_msg_t));
+
+                               /* Return DBUS Invocation*/
+                               _bt_service_method_return(req_info->context, out_param, result);
+                               _bt_free_info_from_invocation_list(req_info);
+                               g_array_free(out_param, TRUE);
+                       }
+                       break;
+                       }
+               default:
+                       BT_DBG("Unknown function(%d)", service_function);
+                       break;
+               }
+       }
+}
+
+void _bt_mesh_msg_handler(event_mesh_message_t *event)
+{
+       uint32_t opcode;
+       uint16_t data_len = event->data_len;
+       uint8_t *data = event->data;
+       int n;
+       const struct mesh_msg_cmd *cmd;
+       struct mesh_pending_request *req;
+
+       int result = BLUETOOTH_ERROR_NONE;
+
+       if (_bt_mesh_util_opcode_get(data, data_len, &opcode, &n)) {
+               BT_INFO("Mesh: Opcode of response data [0x%2.2x], actual data len [%d]", opcode, n);
+               data_len -= n;
+               data += n;
+       } else
+               return;
+
+       for (int msg_idx = 0; msg_idx < data_len; msg_idx++ ) {
+               BT_INFO("Mesh: Message data[%d]: [%2.2X]", msg_idx, data[msg_idx]);
+       }
+
+       BT_INFO("Mesh: Received %s (len %u) opcode [0x%2.2x]",
+               __mesh_get_opcode_string(opcode), data_len, opcode);
+
+       req = __bt_mesh_get_request_by_response(event->source,
+               event->net_uuid.uuid, (opcode & ~MESH_OPCODE_UNRELIABLE));
+
+       if (req) {
+               BT_INFO("Mesh: Got Request");
+               cmd = req->cmd;
+               __mesh_request_remove(req);
+               l_queue_remove(pending_msg_requests, req);
+       } else
+               cmd = NULL;
+
+       bluetooth_mesh_model_msg_t param;
+       memset(&param, 0x00, sizeof(bluetooth_mesh_model_msg_t));
+
+       _bt_mesh_util_convert_hex_to_string(
+               (uint8_t *) event->net_uuid.uuid, 16, param.net_uuid,
+                       BLUETOOTH_MESH_NETWORK_UUID_STRING_LENGTH + 1);
+
+       param.primary_unicast = event->source;
+       param.elem_index = 0;
+       param.appkey_idx = event->key_idx;
+       param.msg_len = data_len*2;
+       _bt_mesh_util_convert_hex_to_string(
+               (uint8_t *) data, data_len, param.msg,
+                       param.msg_len + 1);
+
+       param.appkey_idx = event->key_idx;
+       param.opcode = opcode;
+       BT_INFO("Send response");
+
+       switch (opcode & ~MESH_OPCODE_UNRELIABLE) {
+               default:
+                       return;
+       case MESH_OPCODE_MODEL_GENERIC_ONOFF_STATUS: {
+               BT_INFO("Received Generic On off status");
+
+               BT_INFO("Mesh: Node %4.4x", event->source);
+               if (!cmd) {
+                       BT_INFO("No pending req for this status");
+                       break;
+               }
+               if (cmd->opcode == MESH_OPCODE_MODEL_GENERIC_ONOFF_GET) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_MODEL_GENERIC_ONOFF_GET");
+               } else if (cmd->opcode == MESH_OPCODE_MODEL_GENERIC_ONOFF_SET) {
+                       BT_INFO("Mesh: Resp recvd: MESH_OPCODE_MODEL_GENERIC_ONOFF_SET");
+               } else {
+                       BT_INFO("Request opcode do not match !");
+               }
+       }
+       }
+       __bt_mesh_handle_pending_msg_request_info(result,
+               BT_MESH_MODEL_EXECUTE_MSG, &param,
+               sizeof(bluetooth_mesh_model_msg_t));
+
+}
+
+int _bt_mesh_node_model_execute_msg(const char *app_cred, const char *sender,
+       bluetooth_mesh_model_msg_t *req)
+{
+       int ret = OAL_STATUS_SUCCESS;
+       uint16_t appkey_idx;
+       oal_uuid_t net_uuid;
+       uint16_t data_len;
+       uint32_t opcode = 0;
+       uint8_t buffer[MESH_CONFIG_BUFFER_MAX_LEN];
+       uint8_t msg[BLUETOOTH_MESH_MODEL_MSG_LENGTH_MAX + 1];
+
+       /* If Scanning is going on */
+       if (_bt_mesh_is_provisioning() ||
+                       _bt_mesh_is_scanning()) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       /* Check pending request */
+       opcode = req->opcode;
+       if (_bt_mesh_check_pending_request(opcode, req->primary_unicast,
+               net_uuid.uuid)) {
+               BT_ERR("Device is buzy..");
+               return BLUETOOTH_ERROR_DEVICE_BUSY;
+       }
+
+       _bt_mesh_util_convert_string_to_hex(req->net_uuid, strlen(req->net_uuid), net_uuid.uuid, 16);
+
+       appkey_idx = req->appkey_idx;
+
+       /* Update data buffer */
+       data_len = _bt_mesh_util_opcode_set(req->opcode, buffer);
+
+       BT_DBG("Mesh: Model string msg opcode: 0x%2.2X msg_len: %d",
+               req->opcode, req->msg_len);
+       if (req->msg_len > 0) {
+               /* Convert Mesh msg to hex*/
+               BT_DBG("Mesh: Model string msg opcode: 0x%2.2X msg_len: %d, msg: %s",
+                       req->opcode, strlen(req->msg), req->msg);
+               _bt_mesh_util_convert_string_to_hex(req->msg, strlen(req->msg), msg, (req->msg_len)/2);
+
+               for (int msg_idx = 0; msg_idx < (req->msg_len)/2; msg_idx++)
+                       BT_DBG("Mesh: Model hex msg[%d]: msg: 0x%2.2X", msg_idx, msg[msg_idx]);
+
+               /* Append model msg */
+               if (req->msg_len > 0) {
+                       memcpy(buffer + data_len, msg, req->msg_len);
+                       data_len += req->msg_len;
+               }
+       }
+
+       ret = mesh_model_send_message(&net_uuid, req->primary_unicast, appkey_idx, buffer, data_len);
+
+       if (ret != OAL_STATUS_SUCCESS) {
+               BT_ERR("ret: %d", ret);
+               return BLUETOOTH_ERROR_INTERNAL;
+       }
+
+       /* Queue the request with timeout */
+       __bt_mesh_add_request(opcode, req->primary_unicast, net_uuid.uuid,
+                       g_memdup(req, sizeof(bluetooth_mesh_model_msg_t)));
+
+       return BLUETOOTH_ERROR_NONE;
+}