/* 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-OnOff_srv]" #define LOG_ERROR_ENABLE #define LOG_DEBUG_ENABLE #define LOG_INFO_ENABLE /* #define LOG_DUMP_ENABLE */ #define LOG_CLI_ENABLE #include "debug.h" #if TCFG_AUDIO_ENABLE #include "tone_player.h" #include "media/includes.h" #include "key_event_deal.h" #endif/*TCFG_AUDIO_ENABLE*/ #if (CONFIG_MESH_MODEL == SIG_MESH_GENERIC_ONOFF_SERVER) /** * @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 'O', 'n', 'O', 'f', 'f', '_', 's', 'r', 'v' /** * @brief Conifg MAC of current demo */ /*-----------------------------------------------------------*/ #define CUR_DEVICE_MAC_ADDR 0x852233445567 /* * 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_srv, NULL, 2 + 2); BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0); /* Model Operation Codes */ #define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01) #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 // ----------------------------------------------------------- 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 void gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); static void gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); static void gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf); static void health_attention_on(struct bt_mesh_model *mod); static void health_attention_off(struct bt_mesh_model *mod); static u8_t trans_id; const int config_bt_mesh_features = BT_MESH_FEAT_SUPPORTED; static u8 ble_mesh_adv_name[32 + 2]; const uint8_t mesh_default_name[] = { // Name BYTE_LEN(BLE_DEV_NAME) + 1, BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME, BLE_DEV_NAME, }; static struct onoff_state onoff_state[] = { { .led_gpio_pin = LED0_GPIO_PIN }, }; const u8 led_use_port[] = { IO_PORTA_01, }; static const struct bt_mesh_send_cb rsp_msg_cb = { // .user_intercept = respond_messsage_schedule,//for compiler, not used now. }; static const struct bt_mesh_health_srv_cb health_srv_cb = { .attn_on = health_attention_on, .attn_off = health_attention_off, }; static struct bt_mesh_health_srv health_srv = { .cb = &health_srv_cb, }; /* * OnOff Model Server Op Dispatch Table * */ static const struct bt_mesh_model_op gen_onoff_srv_op[] = { { BT_MESH_MODEL_OP_GEN_ONOFF_GET, BT_MESH_LEN_EXACT(0), gen_onoff_get }, { BT_MESH_MODEL_OP_GEN_ONOFF_SET, BT_MESH_LEN_MIN(2), gen_onoff_set }, { BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, BT_MESH_LEN_MIN(2), gen_onoff_set_unack }, BT_MESH_MODEL_OP_END, }; //----------------------------------------------------------- void get_mesh_adv_name(u8 *len, u8 **data) { //r_printf("==============================%s,%d\n", __FUNCTION__, __LINE__); //put_buf(ble_mesh_adv_name,32); *len = ble_mesh_adv_name[0] + 1; *data = ble_mesh_adv_name; } /* * Generic OnOff Model Server Message Handlers * * Mesh Model Specification 3.1.1 * */ static void respond_messsage_schedule(u16 *delay, u16 *duration, void *cb_data) { /* Mesh_v1.0 <3.7.4.1 Transmitting an access message> * * If the message is sent in response to a received message * that was sent to a unicast address, the node should transmit * the response message with a random delay between 20 and 50 milliseconds. * * If the message is sent in response to a received message * that was sent to a group address or a virtual address, * the node should transmit the response message with * a random delay between 20 and 500 milliseconds. */ u16 delay_ms; u16 dst_addr = (u16)cb_data; pseudo_random_genrate((u8 *)&delay_ms, 2); if (BT_MESH_ADDR_IS_UNICAST(dst_addr)) { delay_ms = btctler_get_rand_from_assign_range(delay_ms, 20, 50); } else { delay_ms = btctler_get_rand_from_assign_range(delay_ms, 20, 200); } *delay = delay_ms; log_info("respond_messsage delay =%u ms", delay_ms); } static void gen_onoff_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { NET_BUF_SIMPLE_DEFINE(msg, 2 + 1 + 4); struct onoff_state *onoff_state = model->rt->user_data; log_info("addr 0x%04x onoff 0x%02x\n", bt_mesh_model_elem(model)->rt->addr, onoff_state->current); bt_mesh_model_msg_init(&msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); buffer_add_u8_at_tail(&msg, onoff_state->current); if (bt_mesh_model_send(model, ctx, &msg, &rsp_msg_cb, (void *)ctx->recv_dst)) { log_info("Unable to send On Off Status response\n"); } } 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->rt->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)->rt->addr, onoff_state->current); /* log_info_hexdump((u8 *)onoff_state, sizeof(*onoff_state)); */ gpio_pin_write(onoff_state->led_gpio_pin, onoff_state->current); #if PACKET_LOSS_RATE_TEST static uint32_t i = 0; i++; log_info(">>> recv num %d ", i); #endif #if 0 /* * If a server has a publish address, it is required to * publish status on a state change * * See Mesh Profile Specification 3.7.6.1.2 * * Only publish if there is an assigned address */ if (onoff_state->previous != onoff_state->current && model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { log_info("publish last 0x%02x cur 0x%02x\n", onoff_state->previous, onoff_state->current); onoff_state->previous = onoff_state->current; bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); buffer_add_u8_at_tail(msg, onoff_state->current); err = bt_mesh_model_publish(model); if (err) { log_info("bt_mesh_model_publish err %d\n", err); } } #endif /* */ } static void gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { log_info("gen_onoff_set\n"); gen_onoff_set_unack(model, ctx, buf); gen_onoff_get(model, ctx, buf); } static void health_attention_on(struct bt_mesh_model *mod) { log_info(">>>>>>>>>>>>>>>>>health_attention_on\n"); for (u8 i = 0; i < sizeof(led_use_port); i++) { led_blink_worker_on(led_use_port[i]); } } static void health_attention_off(struct bt_mesh_model *mod) { log_info(">>>>>>>>>>>>>>>>>health_attention_off\n"); for (u8 i = 0; i < sizeof(led_use_port); i++) { led_blink_worker_off(led_use_port[i]); } } /* * * Element Model Declarations * * Element 0 Root Models */ static struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv, &onoff_state[0]), }; /* * LED to Server Model Assigmnents */ static struct bt_mesh_model *mod_srv_sw[] = { &root_models[2], }; /* * 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 bool server_publish(struct _switch *sw) { 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 unprovisioned, just call the set function. * The intent is to have switch-like behavior * prior to provisioning. Once provisioned, * the button and its corresponding led are no longer * associated and act independently. So, if a button is to * control its associated led after provisioning, the button * must be configured to either publish to the led's unicast * address or a group to which the led is subscribed. */ u16 primary_addr = get_primary_addr(); if (primary_addr == BT_MESH_ADDR_UNASSIGNED) { NET_BUF_SIMPLE_DEFINE(msg, 1); struct bt_mesh_msg_ctx ctx = { .addr = sw->sw_num + primary_addr, }; /* This is a dummy message sufficient * for the led server */ buffer_add_u8_at_tail(&msg, sw->onoff_state); gen_onoff_set_unack(mod_srv, &ctx, &msg); return TRUE; } return FALSE; } /* * 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; } if (server_publish(sw)) { return; } } static void mesh_init(void) { log_info("--func=%s", __FUNCTION__); 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(); } bt_mesh_prov_enable(BT_MESH_PROV_GATT); } void input_key_handler(u8 key_status, u8 key_number) { struct _switch press_switch; log_info("key_number=0x%x", key_number); /*Audio Test Demo*/ #if (TCFG_AUDIO_ENABLE && MESH_AUDIO_TEST) if (key_status == KEY_EVENT_CLICK && key_number == TCFG_ADKEY_VALUE0) { log_info(">>>key0:mic/encode test\n"); //AC695N/AC696N mic test /* extern int audio_adc_open_demo(void); */ /* audio_adc_open_demo(); */ //AD697N/AC897N/AC698N mic test /* extern void audio_adc_mic_demo(u8 mic_idx, u8 gain, u8 mic_2_dac); */ /* audio_adc_mic_demo(1, 1, 1); */ /*encode test*/ /* //AC695N/AC696N/AD697N/AC897N/AC698N 编码测试类型: AUDIO_CODING_OPUS AUDIO_CODING_SPEEX AUDIO_CODING_WAV AUDIO_CODING_LC3 AUDIO_CODING_SBC AUDIO_CODING_MSBC */ /* //AC632N 编码测试类型: AUDIO_CODING_LC3 AUDIO_CODING_USBC */ extern int audio_demo_enc_open(int (*demo_output)(void *priv, void *buf, int len), u32 code_type, u8 ai_type); audio_demo_enc_open(NULL, AUDIO_CODING_USBC, 0); } if (key_status == KEY_EVENT_CLICK && key_number == TCFG_ADKEY_VALUE1) { log_info(">>>key1:tone/decode test\n"); //AC695N/AC696N tone play test /* tone_play_by_path(TONE_NORMAL, 1); */ /* tone_play_by_path(TONE_BT_CONN, 1); */ //AD697N/AC897N/AC698N tone play test /* tone_play(TONE_NUM_8, 1); */ /* tone_play(TONE_SIN_NORMAL, 1); */ // decode test /* //AC695N/AC696N/AD697N/AC897N/AC698N 解码测试类型: AUDIO_CODING_LC3 //AC632N 解码测试类型:(需要在audio_decode.c中配置) AUDIO_CODING_LC3 AUDIO_CODING_USBC */ extern void demo_frame_test(void); demo_frame_test(); } #else 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; } #endif/*TCFG_AUDIO_ENABLE*/ } void bt_ble_init(void) { u8 bt_addr[6] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)}; bt_mac_addr_set(bt_addr); u8 *name_p = &ble_mesh_adv_name[2]; int ret = syscfg_read(CFG_BT_NAME, name_p, 32); if (ret <= 0) { log_info("read bt name err\n"); memcpy(ble_mesh_adv_name, mesh_default_name, sizeof(mesh_default_name)); } else { ble_mesh_adv_name[0] = strlen(name_p) + 1; ble_mesh_adv_name[1] = BLUETOOTH_DATA_TYPE_COMPLETE_LOCAL_NAME; put_buf(name_p, 32); } mesh_set_gap_name(name_p); log_info("mesh_name:%s\n", name_p); mesh_setup(mesh_init); if (BT_MODE_IS(BT_BQB)) { ble_bqb_test_thread_init(); } } #endif /* (CONFIG_MESH_MODEL == SIG_MESH_GENERIC_ONOFF_SERVER) */