From: Abhay Agarwal Date: Fri, 31 Jul 2020 03:18:38 +0000 (+0530) Subject: Mesh: Add mesh model support X-Git-Tag: accepted/tizen/unified/20200810.123222~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=49d701bde3261ff21c0a4a5e45f6f64363bf9fc8;p=platform%2Fcore%2Fconnectivity%2Fbluetooth-frwk.git Mesh: Add mesh model support 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 --- diff --git a/bt-service/CMakeLists.txt b/bt-service/CMakeLists.txt index 51f5814..71abba0 100644 --- a/bt-service/CMakeLists.txt +++ b/bt-service/CMakeLists.txt @@ -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 index 0000000..21da36d --- /dev/null +++ b/bt-service/services/include/bt-service-mesh-model.h @@ -0,0 +1,46 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * @author: Abhay Agarwal + * + * 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 +#include +#include "bluetooth-api.h" +#include "bluetooth-mesh-api.h" +#include +#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 index 0000000..6eebdfd --- /dev/null +++ b/bt-service/services/mesh/bt-service-mesh-model.c @@ -0,0 +1,450 @@ +/* + * Bluetooth-frwk + * + * Copyright (c) 2020 Samsung Electronics Co., Ltd. + * + * @author: Abhay Agarwal + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + +#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(¶m, 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, ¶m, + 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; +}