/* Bluetooth Mesh */ /* * Copyright (c) 2017 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #include "btstack/bluetooth.h" #include "bt_common.h" #include "api/sig_mesh_api.h" #include "../model_api.h" #include "provisioner_config.h" #include "device/gpio.h" #include "event/key_event.h" #define LOG_TAG "[Mesh-OnOff_cli]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE /* #define LOG_DUMP_ENABLE */ #define LOG_CLI_ENABLE #include "debug.h" #if CONFIG_BLE_MESH_ENABLE && (CONFIG_MESH_MODEL == SIG_MESH_ONOFF_TOBE_PROV) extern u16_t primary_addr; extern void mesh_setup(void (*init_cb)(void)); extern void bt_mac_addr_set(u8 *bt_addr); extern void prov_complete(u16_t net_idx, u16_t addr); extern void prov_reset(void); /** * @brief Config current node features(Relay/Proxy/Friend/Low Power) */ /*-----------------------------------------------------------*/ #define BT_MESH_FEAT_SUPPORTED_TEMP ( \ 0 \ ) #include "../feature_correct.h" 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 Conifg complete local name */ /*-----------------------------------------------------------*/ #define BLE_DEV_NAME 'O', 'n', 'O', 'f', 'f', '_', 'c', 'l', 'i' 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; } /** * @brief Conifg MAC of current demo */ /*-----------------------------------------------------------*/ #define CUR_DEVICE_MAC_ADDR 0x112233445566 /* * 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(gen_onoff_pub_cli, NULL, 2 + 2); /* Model Operation Codes */ #define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02) #define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03) #define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04) /* Company Identifiers (see Bluetooth Assigned Numbers) */ #define BT_COMP_ID_LF 0x05D6 // Zhuhai Jieli technology Co.,Ltd /* LED NUMBER */ #define LED0_GPIO_PIN 0 /* * Server Configuration Declaration */ static struct bt_mesh_cfg_srv cfg_srv = { .relay = BT_MESH_FEATURES_GET(BT_MESH_FEAT_RELAY), .frnd = BT_MESH_FEATURES_GET(BT_MESH_FEAT_FRIEND), .gatt_proxy = BT_MESH_FEATURES_GET(BT_MESH_FEAT_PROXY), .beacon = BT_MESH_BEACON_ENABLED, .default_ttl = 7, }; static struct bt_mesh_cfg_cli cfg_cli; struct onoff_state { u8_t current; u8_t previous; u8_t led_gpio_pin; }; struct _switch { u8_t sw_num; u8_t onoff_state; }; static u8_t trans_id; static struct onoff_state onoff_state[] = { { .led_gpio_pin = LED0_GPIO_PIN }, }; const u8 led_use_port[1] = { IO_PORTA_03, }; /* * 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. * */ static void gen_onoff_status(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { u8_t state; state = buffer_pull_u8_from_head(buf); log_info("Node 0x%04x OnOff status from 0x%04x with state 0x%02x\n", bt_mesh_model_elem(model)->addr, ctx->addr, state); } /* * OnOff Model Client Op Dispatch Table */ static const struct bt_mesh_model_op gen_onoff_cli_op[] = { { BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status }, BT_MESH_MODEL_OP_END, }; /* * Generic OnOff Model Server Message Handlers * * Mesh Model Specification 3.1.1 */ static void gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { struct net_buf_simple *msg = model->pub->msg; struct onoff_state *onoff_state = model->user_data; int err; onoff_state->current = buffer_pull_u8_from_head(buf); log_info("addr 0x%02x state 0x%02x\n", bt_mesh_model_elem(model)->addr, onoff_state->current); /* log_info_hexdump((u8 *)onoff_state, sizeof(*onoff_state)); */ gpio_direction_output(onoff_state->led_gpio_pin, onoff_state->current); } /* * * Element Model Declarations * * Element 0 Root Models */ static struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV(&cfg_srv), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, &gen_onoff_pub_cli, &onoff_state[0]), }; /* * Button to Client Model Assignments */ static struct bt_mesh_model *mod_cli_sw[] = { &root_models[1], }; /* * LED to Server Model Assigmnents */ static struct bt_mesh_model *mod_srv_sw[] = { &root_models[1], }; /* * Root and Secondary Element Declarations */ static struct bt_mesh_elem elements[] = { BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE), }; static const struct bt_mesh_comp composition = { .cid = BT_COMP_ID_LF, .elem = elements, .elem_count = ARRAY_SIZE(elements), }; static const u8_t dev_uuid[16] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)}; static const struct bt_mesh_prov prov = { .uuid = dev_uuid, #if 0 .output_size = 6, .output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING), .output_number = output_number, .output_string = output_string, #else .output_size = 0, .output_actions = 0, .output_number = 0, #endif .complete = prov_complete, .reset = prov_reset, }; static void client_publish(struct _switch *sw) { int err; struct bt_mesh_model *mod_cli; struct bt_mesh_model_pub *pub_cli; mod_cli = mod_cli_sw[sw->sw_num]; pub_cli = mod_cli->pub; if (pub_cli->addr == BT_MESH_ADDR_UNASSIGNED) { return; } log_info("publish to 0x%04x onoff 0x%04x sw->sw_num 0x%04x\n", pub_cli->addr, sw->onoff_state, sw->sw_num); bt_mesh_model_msg_init(pub_cli->msg, BT_MESH_MODEL_OP_GEN_ONOFF_SET); buffer_add_u8_at_tail(pub_cli->msg, sw->onoff_state); buffer_add_u8_at_tail(pub_cli->msg, trans_id++); err = bt_mesh_model_publish(mod_cli); if (err) { log_error("bt_mesh_model_publish err %d\n", err); } } /* * Button Pressed Worker Task */ static void button_pressed_worker(struct _switch *sw) { if (sw->sw_num >= composition.elem_count) { log_error("sw_num over elem_count"); return; } client_publish(sw); } static void mesh_init(void) { int err = bt_mesh_init(&prov, &composition); if (err) { log_error("Initializing mesh failed (err %d)\n", err); return; } settings_load(); bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV); } 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] "); press_switch.sw_num = key_number; press_switch.onoff_state = 1; button_pressed_worker(&press_switch); break; case KEY_EVENT_LONG: log_info(" [KEY_EVENT_LONG] "); press_switch.sw_num = key_number; press_switch.onoff_state = 0; button_pressed_worker(&press_switch); break; case KEY_EVENT_HOLD: log_info(" [KEY_EVENT_HOLD] "); break; default : return; } } void bt_ble_mesh_init(void) { u8 bt_addr[6] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)}; bt_mac_addr_set(bt_addr); mesh_setup(mesh_init); } #endif /* (CONFIG_MESH_MODEL == SIG_MESH_ONOFF_TOBE_PROV) */