/* Bluetooth Mesh */ /* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include "btstack/bluetooth.h" #include "system/includes.h" #include "bt_common.h" #include "api/sig_mesh_api.h" #include "model_api.h" #include "feature_correct.h" #define LOG_TAG "[Mesh-vendor_srv]" #define LOG_INFO_ENABLE #define LOG_DEBUG_ENABLE #define LOG_DUMP_ENABLE #define LOG_ERROR_ENABLE #include "debug.h" #if (CONFIG_MESH_MODEL == SIG_MESH_VENDOR_SERVER) #define SERVER_PUBLISH_EN 0 /** * @brief Config current node features(Relay/Proxy/Friend/Low Power) */ /*-----------------------------------------------------------*/ #define BT_MESH_FEAT_SUPPORTED_TEMP ( \ BT_MESH_FEAT_RELAY | \ BT_MESH_FEAT_PROXY | \ 0 \ ) /** * @brief Conifg complete local name */ /*-----------------------------------------------------------*/ #define BLE_DEV_NAME 'V', 'd', '_','s', 'r', 'v' /** * @brief Conifg MAC of current demo */ /*-----------------------------------------------------------*/ #define CUR_DEVICE_MAC_ADDR 0x442233445566 const int config_bt_mesh_features = BT_MESH_FEAT_SUPPORTED; /** * @brief Config proxy connectable adv hardware param */ /*-----------------------------------------------------------*/ #if BT_MESH_FEATURES_GET(BT_MESH_FEAT_LOW_POWER) const u16 config_bt_mesh_proxy_node_adv_interval = ADV_SCAN_UNIT(3000); // unit: ms #else const u16 config_bt_mesh_proxy_node_adv_interval = ADV_SCAN_UNIT(300); // unit: ms #endif /* BT_MESH_FEATURES_GET(BT_MESH_FEAT_LOW_POWER) */ /** * @brief Config adv cache buffer */ /*-----------------------------------------------------------*/ #define MESH_ADV_BUFFER_COUNT 4 const u8 config_bt_mesh_adv_buf_count = MESH_ADV_BUFFER_COUNT; #if (MESH_ADV_BUFFER_COUNT < 4) // base on "config_bt_mesh_node_msg_adv_duration = 100" #error " current MESH_ADV_BUFFER_COUNT must >= 4 " #endif /* Company Identifiers (see Bluetooth Assigned Numbers) */ #define BT_COMP_ID_LF 0x05D6 // Zhuhai Jieli technology Co.,Ltd /* * Vendor Model ID * detail on Mesh_v1.0 <3.7.2 Model identifier> */ #define BT_MESH_VENDOR_MODEL_ID_SRV 0x0001 /* * Vendor Model Operation Codes * detail on Mesh_v1.0 <3.7.3.1 Operation codes> */ #define BT_MESH_VENDOR_MODEL_OP_SET BT_MESH_MODEL_OP_3(0x01, BT_COMP_ID_LF) #define BT_MESH_VENDOR_MODEL_OP_STATUS BT_MESH_MODEL_OP_3(0x02, BT_COMP_ID_LF) /* * Access payload fields * detail on Mesh_v1.0 <3.7.3 Access payload> */ #define TRANSMIC_SIZE 4 #define MAX_USEFUL_ACCESS_PAYLOAD_SIZE 11 // 32 bit TransMIC (unsegmented) #define ACCESS_OP_SIZE 3 #define ACCESS_PARAM_SIZE (MAX_USEFUL_ACCESS_PAYLOAD_SIZE - ACCESS_OP_SIZE) /* test data */ #define LED_STATE_LEN 1 #define REMAIN_DATA_LEN (ACCESS_PARAM_SIZE - LED_STATE_LEN) #define REMAIN_DATA_VALUE 0x02 /* LED NUMBER */ #define LED0_GPIO_PIN 0 /* * Publication Declarations * * The publication messages are initialized to the * the size of the opcode + content * * For publication, the message must be in static or global as * it is re-transmitted several times. This occurs * after the function that called bt_mesh_model_publish() has * exited and the stack is no longer valid. * * Note that the additional 4 bytes for the AppMIC is not needed * because it is added to a stack variable at the time a * transmission occurs. * */ BT_MESH_MODEL_PUB_DEFINE(vendor_pub_srv, NULL, MAX_USEFUL_ACCESS_PAYLOAD_SIZE); #define NODE_ADDR 0x0002 #define GROUP_ADDR 0xc000 #define OP_VENDOR_BUTTON BT_MESH_MODEL_OP_3(0x00, BT_COMP_ID_LF) struct _switch { u8_t sw_num; u8_t onoff_state; }; struct onoff_state { u8_t onoff; u8_t led_gpio_pin; }; static void vendor_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); static const u16_t net_idx; static const u16_t app_idx; static const u32_t iv_index; static u8_t flags; static u16_t node_addr = NODE_ADDR; static const u8_t net_key[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; static const u8_t dev_key[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; static const u8_t app_key[16] = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, }; const uint8_t mesh_name[] = { // Name BYTE_LEN(BLE_DEV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, BLE_DEV_NAME, }; void get_mesh_adv_name(u8 *len, u8 **data) { *len = sizeof(mesh_name); *data = mesh_name; } static struct onoff_state onoff_state[] = { { .led_gpio_pin = LED0_GPIO_PIN }, }; const u8 led_use_port[1] = { IO_PORTA_01, }; /* * Models in an element must have unique op codes. * * The mesh stack dispatches a message to the first model in an element * that is also bound to an app key and supports the op code in the * received message. * */ /* * Vendor Model Server Op Dispatch Table */ static const struct bt_mesh_model_op vendor_srv_op[] = { { BT_MESH_VENDOR_MODEL_OP_SET, ACCESS_OP_SIZE, vendor_set }, BT_MESH_MODEL_OP_END, }; /* * Client Configuration Declaration */ static struct bt_mesh_cfg_cli cfg_cli; /* * * Element Model Declarations * * Element 0 Root Models */ static struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV,// default for root model BT_MESH_MODEL_CFG_CLI(&cfg_cli), // default for self-configuration network }; static struct bt_mesh_model vendor_server_models[] = { BT_MESH_MODEL_VND(BT_COMP_ID_LF, BT_MESH_VENDOR_MODEL_ID_SRV, vendor_srv_op, &vendor_pub_srv, &onoff_state[0]), }; /* * LED to Server Model Assigmnents */ static struct bt_mesh_model *mod_srv_sw[] = { &vendor_server_models[0], }; /* * Root and Secondary Element Declarations */ static struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, vendor_server_models), }; static const struct bt_mesh_comp composition = { .cid = BT_COMP_ID_LF, .elem = elements, .elem_count = ARRAY_SIZE(elements), }; static u8_t dev_uuid[16] = { 0xdd, 0xdd }; static const struct bt_mesh_prov prov = { .uuid = dev_uuid, .output_size = 0, .output_actions = 0, .output_number = 0, .complete = prov_complete, .reset = prov_reset, }; static void vendor_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { log_info("receive message len except opcode =0x%x", buf->len); log_info_hexdump(buf->data, buf->len); struct net_buf_simple *msg = model->pub->msg; struct onoff_state *onoff_state = model->rt->user_data; //< set led onoff onoff_state->onoff = buffer_pull_u8_from_head(buf); log_info("Local Node 0x%02x shoult set led to 0x%02x\n", bt_mesh_model_elem(model)->rt->addr, onoff_state->onoff); gpio_pin_write(onoff_state->led_gpio_pin, onoff_state->onoff); //< Ack to client with the same receive data NET_BUF_SIMPLE_DEFINE(ack_msg, MAX_USEFUL_ACCESS_PAYLOAD_SIZE + TRANSMIC_SIZE); bt_mesh_model_msg_init(&ack_msg, BT_MESH_VENDOR_MODEL_OP_STATUS); // Opcode: 3 octets buffer_add_u8_at_tail(&ack_msg, onoff_state->onoff); // onoff state: 1 octets buffer_memset(&ack_msg, buffer_pull_u8_from_head(buf) + 1, REMAIN_DATA_LEN); log_info_hexdump(ack_msg.data, MAX_USEFUL_ACCESS_PAYLOAD_SIZE); if (bt_mesh_model_send(model, ctx, &ack_msg, NULL, NULL)) { log_info("Unable to send Status response\n"); } } #if SERVER_PUBLISH_EN static void server_publish(struct _switch *sw) { int err; struct bt_mesh_model *mod_srv; struct bt_mesh_model_pub *pub_srv; mod_srv = mod_srv_sw[sw->sw_num]; pub_srv = mod_srv->pub; if (pub_srv->addr == BT_MESH_ADDR_UNASSIGNED) { log_info("pub_srv->addr == BT_MESH_ADDR_UNASSIGNED"); return; } log_info("publish to Remote 0x%04x onoff 0x%04x sw_num 0x%04x\n", pub_srv->addr, sw->onoff_state, sw->sw_num); bt_mesh_model_msg_init(pub_srv->msg, BT_MESH_VENDOR_MODEL_OP_SET); buffer_add_u8_at_tail(pub_srv->msg, sw->onoff_state); buffer_memset(pub_srv->msg, REMAIN_DATA_VALUE, REMAIN_DATA_LEN); err = bt_mesh_model_publish(mod_srv); if (err) { log_info("bt_mesh_model_publish err %d\n", err); } log_info_hexdump(pub_srv->msg->data, MAX_USEFUL_ACCESS_PAYLOAD_SIZE); } /* * Button Pressed Worker Task */ static void button_pressed_worker(struct _switch *sw) { if (sw->sw_num >= composition.elem_count) { log_info("sw_num over elem_count"); return; } server_publish(sw); } #endif /* SERVER_PUBLISH_EN */ void bind_mode_mod_sub_set() { u16_t elem_addr = node_addr; u16 dst_addr = GROUP_ADDR; /* Bind to vendor server model */ log_info("bt_mesh_cfg_mod_app_bind_vnd server"); bt_mesh_cfg_mod_app_bind_vnd(net_idx, node_addr, elem_addr, app_idx, BT_MESH_VENDOR_MODEL_ID_SRV, BT_COMP_ID_LF, NULL); /* Add model subscription */ log_info("bt_mesh_cfg_mod_sub_add_vnd server"); bt_mesh_cfg_mod_sub_add_vnd(net_idx, node_addr, elem_addr, dst_addr, BT_MESH_VENDOR_MODEL_ID_SRV, BT_COMP_ID_LF, NULL); #if SERVER_PUBLISH_EN /* Add model publish */ struct bt_mesh_cfg_cli_mod_pub pub; pub.addr = dst_addr; pub.app_idx = app_idx; pub.cred_flag = 0; pub.ttl = 7; pub.period = 0; /* pub.transmit = 0b00100001; */ pub.transmit = 0; log_info("bt_mesh_cfg_mod_pub_set_vnd server"); bt_mesh_cfg_mod_pub_set_vnd(net_idx, node_addr, elem_addr, BT_MESH_VENDOR_MODEL_ID_SRV, BT_COMP_ID_LF, &pub, NULL); #endif /* SERVER_PUBLISH_EN */ } static void configure(void) { log_info("Configuring..."); log_info("node_addr=0x%x, net_idx=0x%x, app_idx=0x%x", node_addr, net_idx, app_idx); /* Add Application Key */ log_info("bt_mesh_cfg_cli_app_key_add"); bt_mesh_cfg_cli_app_key_add(net_idx, node_addr, net_idx, app_idx, app_key, NULL); /* Bind to vendor server model should be tasked until app key add*/ sys_timeout_add(NULL, bind_mode_mod_sub_set, 100); log_info("Configuration complete"); } void input_key_handler(u8 key_status, u8 key_number) { struct _switch press_switch; log_info("key_number=0x%x", key_number); if ((key_number == 2) && (key_status == KEY_EVENT_LONG)) { log_info("\n \n"); bt_mesh_reset(); return; } switch (key_status) { case KEY_EVENT_CLICK: log_info(" [KEY_EVENT_CLICK] "); #if SERVER_PUBLISH_EN press_switch.sw_num = key_number; press_switch.onoff_state = 1; button_pressed_worker(&press_switch); #endif /* SERVER_PUBLISH_EN */ break; case KEY_EVENT_LONG: log_info(" [KEY_EVENT_LONG] "); break; case KEY_EVENT_HOLD: log_info(" [KEY_EVENT_HOLD] "); break; default : return; } } static void mesh_init(void) { bt_conn_cb_register(bt_conn_get_callbacks()); int err = bt_mesh_init(&prov, &composition); if (err) { log_error("Initializing mesh failed (err %d)\n", err); return; } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { settings_load(); } err = bt_mesh_provision(net_key, net_idx, flags, iv_index, node_addr, dev_key); if (err) { log_info("Using stored settings\n"); } else { log_info("Provisioning completed\n"); configure(); } } void bt_ble_init(void) { u8 bt_addr[6] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)}; bt_mac_addr_set(bt_addr); mesh_setup(mesh_init); } /********************************************************************************/ /* * Mesh API Example */ /* * note: Each model only support one publish address. * But support more subscribe address list, base on CONFIG_BT_MESH_MODEL_GROUP_COUNT. */ void example_node_subscribe_address_overwrite(void) { //< overwrite root element subscribe address to 0xc001 (group address) u16_t elem_addr = node_addr; u16 dst_addr = 0xc001; // new dst address bt_mesh_cfg_mod_sub_overwrite_vnd(net_idx, node_addr, elem_addr, dst_addr, BT_MESH_VENDOR_MODEL_ID_SRV, BT_COMP_ID_LF, NULL); } void example_node_subscribe_address_delete(void) { //< delete initial subscribe address u16_t elem_addr = node_addr; u16 initial_addr = GROUP_ADDR; // initial address bt_mesh_cfg_mod_sub_del_vnd(net_idx, node_addr, elem_addr, initial_addr, BT_MESH_VENDOR_MODEL_ID_SRV, BT_COMP_ID_LF, NULL); } void example_node_subscribe_address_add(void) { //< add new subscribe address u16_t elem_addr = node_addr; u16 new_addr = 0xc002; // new add address bt_mesh_cfg_mod_sub_add_vnd(net_idx, node_addr, elem_addr, new_addr, BT_MESH_VENDOR_MODEL_ID_SRV, BT_COMP_ID_LF, NULL); } void example_node_relay_character_set(void) { //< BT_MESH_RELAY_DISABLED / BT_MESH_RELAY_ENABLED u8 relay_attr = BT_MESH_RELAY_DISABLED; u8 relay_retransmit = BT_MESH_TRANSMIT(2, 20); bt_mesh_cfg_relay_set(net_idx, node_addr, relay_attr, relay_retransmit, NULL, NULL); } void example_node_reset(void) { //< reset the node to an unprovisioned device bt_mesh_reset(); } #endif /* (CONFIG_MESH_MODEL == SIG_MESH_VENDOR_SERVER) */