#include "btstack/bluetooth.h" #include "system/includes.h" #include "bt_common.h" #include "sha256.h" #include "api/sig_mesh_api.h" #include "model_api.h" #include "unix_timestamp.h" #define LOG_TAG "[Mesh-AliSocket]" #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_MESH_MODEL == SIG_MESH_ALIGENIE_SOCKET) /* * @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 \ ) #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 'A', 'G', '-', 'S', 'o', 'c', 'k', 'e', 't' 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 AliGenie 三元组 * * detail on https://www.aligenie.com/doc/357554/gtgprq */ /*-----------------------------------------------------------*/ #define PID_TO_LITTLE_ENDIAN(x) \ (x & 0xff), \ ((x >> 8) & 0xff), \ ((x >> 16) & 0xff), \ ((x >> 24) & 0xff) #define PID_TO_BIG_ENDIAN(x) \ ((x >> 24) & 0xff), \ ((x >> 16) & 0xff), \ ((x >> 8) & 0xff), \ (x & 0xff) #define PRODUCT_ID_STRING_SIZE (sizeof(Product_ID) * 2) #define MAC_ADDRESS_STRING_SIZE (sizeof(Mac_Address) * 2) #define SECRET_STRING_SIZE (sizeof(Secret) - 1) #define CUR_DEVICE_MAC_ADDR 0x28fa7a42bf14 #define PRODUCT_ID 6001957 #define DEVICE_SECRET "e3a3d73b8ebf93619cdd56ce469d3cb9" #define ALIGENIE_SUB_ADDR_1 0xc002 #define ALIGENIE_SUB_ADDR_2 0xcfff /* * @brief 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); /* * @brief Generic OnOff 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) /* * @brief Vendor Model ID * * Company Identifiers (see Bluetooth Assigned Numbers) * detail on Mesh_v1.0 <3.7.2 Model identifier> * detail on https://www.aligenie.com/doc/357554/iv5it7 */ /*-----------------------------------------------------------*/ #define BT_COMP_ID_LF 0x01A8 // Alibaba #define BT_MESH_VENDOR_MODEL_ID_SRV 0x01A80000 //0x0000 #define BT_MESH_VENDOR_MODEL_ID_CLI 0x01A80001 //0x0001 /* * @brief AliGenie Vendor Model Operation Codes * * detail on Mesh_v1.0 <3.7.3.1 Operation codes> * 扩展消息 detail on https://www.aligenie.com/doc/357554/iv5it7 */ /*-----------------------------------------------------------*/ #define VENDOR_MSG_ATTR_GET BT_MESH_MODEL_OP_3(0xD0, BT_COMP_ID_LF) #define VENDOR_MSG_ATTR_SET BT_MESH_MODEL_OP_3(0xD1, BT_COMP_ID_LF) #define VENDOR_MSG_ATTR_SET_UNACK BT_MESH_MODEL_OP_3(0xD2, BT_COMP_ID_LF) #define VENDOR_MSG_ATTR_STATUS BT_MESH_MODEL_OP_3(0xD3, BT_COMP_ID_LF) #define VENDOR_MSG_ATTR_INDICAT BT_MESH_MODEL_OP_3(0xD4, BT_COMP_ID_LF) #define VENDOR_MSG_ATTR_CONFIRM BT_MESH_MODEL_OP_3(0xD5, BT_COMP_ID_LF) #define VENDOR_MSG_ATTR_TRANSPARENT BT_MESH_MODEL_OP_3(0xCF, BT_COMP_ID_LF) /* * @brief AliGenie Vendor Model Message Struct * * 定时功能 detail on https://www.aligenie.com/doc/357554/ovzn6v */ /*-----------------------------------------------------------*/ #define ATTR_TYPE_UNIX_TIME 0xF01F #define ATTR_TYPE_SET_TIMEOUT 0xF010 #define ATTR_TYPE_SET_PERIOD_TIMEOUT 0xF011 #define ATTR_TYPE_DELETE_TIMEOUT 0xF012 struct __unix_time { u32 Opcode: 24, TID: 8; u16 Attr_Type; u32 time; } _GNU_PACKED_; struct __set_timeout { u32 Opcode: 24, TID: 8; u16 Attr_Type; struct __param { u8 index; u32 time; u16 attr_type; u8 attr_para; } _GNU_PACKED_ param[1] ; } _GNU_PACKED_; struct __set_period_timeout { u32 Opcode: 24, TID: 8; u16 Attr_Type; struct __period_param { u8 index; u16 _24h_timer; u8 schedule; u16 attr_type; u8 attr_para; } _GNU_PACKED_ period_param[1] ; } _GNU_PACKED_; struct __delete_time { u32 Opcode: 24, TID: 8; u16 Attr_Type; u8 index; } _GNU_PACKED_; struct __timer_success { u32 Opcode: 24, TID: 8; u16 Attr_Type; u8 event; u8 index; } _GNU_PACKED_; struct __timer_param { u8 tid; u8 index; u8 timer_cnt; bool onoff; }; struct __onoff_repo { u32 Opcode: 24, TID: 8; u16 Attr_Type; bool OnOff; } _GNU_PACKED_; struct __indicate_msg { u32 Opcode: 24, TID: 8; u16 Attr_Type; u8 Event; u8 EventParam; } _GNU_PACKED_; struct __comfirm_check_param { u8 resend_cnt; u8 timer_cnt; u8 indicate_tid; void *buf; u16 len; }; static bool led_flag = 0; static u8 indicate_tid = 0x80; static u16 timer_index[20]; static struct __timer_param timer_param[20]; static struct __comfirm_check_param comfirm_check_param[20]; static u8 timer_cnt = -1; static struct bt_mesh_model vendor_server_models[]; static bool indicate_flag[256]; /* * @brief 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) /* * @brief Generic OnOff State Set */ /*-----------------------------------------------------------*/ #define LED0_GPIO_PIN 0 #define LED1_GPIO_PIN 1 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 struct onoff_state onoff_state[] = { { .led_gpio_pin = LED0_GPIO_PIN }, }; const u8 led_use_port[] = { IO_PORTA_01, }; /* * @brief 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; //struct bt_mesh_msg_ctx *ctx = cb_data; 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 const struct bt_mesh_send_cb rsp_msg_cb = { // .user_intercept = respond_messsage_schedule, // /* .user_intercept = NULL, */ // }; /* * @brief AliGenie Vendor Model Message Handlers * * 定时功能 detail on https://www.aligenie.com/doc/357554/ovzn6v */ /*-----------------------------------------------------------*/ static void vendor_attr_status_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, void *buf, u16 len) { log_info("ready to send ATTR_TYPE_SET_TIMEOUT status"); NET_BUF_SIMPLE_DEFINE(msg, len + TRANSMIC_SIZE); buffer_memcpy(&msg, buf, len); log_info_hexdump(msg.data, msg.len); if (bt_mesh_model_send(model, ctx, &msg, NULL, NULL)) { log_error("Unable to send Status response\n"); } } void indicate_tid_get(u8 *indicate_tid) { if (*indicate_tid >= 0x80 && *indicate_tid <= 0xbf) { *indicate_tid += 1; } else { *indicate_tid = 0x80; } } void timer_cnt_get(u8 *timer_cnt) { if (*timer_cnt >= -1 && *timer_cnt <= 18) { *timer_cnt += 1; } else { *timer_cnt = 0; } } void comfirm_check(struct __comfirm_check_param *param) { struct bt_mesh_msg_ctx ctx = { .addr = 0xf000, }; if (!indicate_flag[param->indicate_tid]) { param->resend_cnt += 1; if (param->resend_cnt >= 10) { //最多重传75次,即30秒重传时间 sys_timer_remove(timer_index[param->timer_cnt]); log_info("resend msg more than 75 times\r\n"); } log_info("indicate_flag[ %d ] = %d\r\n", param->indicate_tid, indicate_flag[param->indicate_tid]); log_info("\n param->buf.tid = %d, timer_cnt = %d \n", ((struct __onoff_repo *)(param->buf))->TID, param->timer_cnt); vendor_attr_status_send(&vendor_server_models[0], &ctx, param->buf, param->len); } else { sys_timer_remove(timer_index[param->timer_cnt]); } } 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); /* delay for send msg because adv timer duration is 50ms. */ os_time_dly(5); if (bt_mesh_model_send(model, ctx, &msg, NULL/*&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); led_flag = onoff_state->current; log_info("\n tmall set led to %d \n", led_flag); indicate_tid_get(&indicate_tid); timer_cnt_get(&timer_cnt); indicate_flag[indicate_tid] = 0; static struct __onoff_repo onoff_repo_set[10]; static u8 onoff_repo_set_cnt = 0; if (onoff_repo_set_cnt < 9) { onoff_repo_set_cnt ++; } else { onoff_repo_set_cnt = 0; } onoff_repo_set[onoff_repo_set_cnt].Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT); onoff_repo_set[onoff_repo_set_cnt].TID = indicate_tid; onoff_repo_set[onoff_repo_set_cnt].Attr_Type = 0x0100; onoff_repo_set[onoff_repo_set_cnt].OnOff = led_flag; comfirm_check_param[timer_cnt].resend_cnt = 0; comfirm_check_param[timer_cnt].timer_cnt = timer_cnt; comfirm_check_param[timer_cnt].indicate_tid = onoff_repo_set[onoff_repo_set_cnt].TID; comfirm_check_param[timer_cnt].buf = &onoff_repo_set[onoff_repo_set_cnt]; comfirm_check_param[timer_cnt].len = sizeof(onoff_repo_set[onoff_repo_set_cnt]); log_info("\n set unack tid = %d, timer_cnt = %d, param.tid = %d \n", onoff_repo_set[onoff_repo_set_cnt].TID, timer_cnt, comfirm_check_param[timer_cnt].indicate_tid); vendor_attr_status_send(&vendor_server_models[0], ctx, &onoff_repo_set[onoff_repo_set_cnt], sizeof(onoff_repo_set[onoff_repo_set_cnt])); timer_index[timer_cnt] = sys_timer_add(&comfirm_check_param[timer_cnt], comfirm_check, 400); } 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 timer_handler(struct __timer_param *param) { indicate_tid_get(&indicate_tid); static struct __timer_success timer_success; timer_success.Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT); timer_success.TID = indicate_tid; timer_success.Attr_Type = 0xf009; timer_success.event = 0x11; timer_success.index = param->index; indicate_flag[timer_success.TID] = 0; indicate_tid_get(&indicate_tid); static struct __onoff_repo onoff_repo_handle; onoff_repo_handle.Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT); onoff_repo_handle.TID = indicate_tid; onoff_repo_handle.Attr_Type = 0x0100; onoff_repo_handle.OnOff = param->onoff; indicate_flag[onoff_repo_handle.TID] = 0; struct bt_mesh_msg_ctx ctx = { .addr = 0xf000, }; gpio_pin_write(LED0_GPIO_PIN, param->onoff); led_flag = param->onoff; log_info("timer_cnt = %d, timer_index = 0x%x, onoff = %d", param->timer_cnt, timer_index[param->timer_cnt], param->onoff); sys_timer_remove(timer_index[param->timer_cnt]); //timing success msg send and check comfirm timer_cnt_get(&timer_cnt); comfirm_check_param[timer_cnt].resend_cnt = 0; comfirm_check_param[timer_cnt].timer_cnt = timer_cnt; comfirm_check_param[timer_cnt].indicate_tid = indicate_tid; comfirm_check_param[timer_cnt].buf = &timer_success; comfirm_check_param[timer_cnt].len = sizeof(timer_success); vendor_attr_status_send(&vendor_server_models[0], &ctx, &timer_success, sizeof(timer_success)); timer_index[timer_cnt] = sys_timer_add(&comfirm_check_param[timer_cnt], comfirm_check, 400); //onoff_state msg send and check comfirm timer_cnt_get(&timer_cnt); comfirm_check_param[timer_cnt].resend_cnt = 0; comfirm_check_param[timer_cnt].timer_cnt = timer_cnt; comfirm_check_param[timer_cnt].indicate_tid = indicate_tid; comfirm_check_param[timer_cnt].buf = &onoff_repo_handle; comfirm_check_param[timer_cnt].len = sizeof(onoff_repo_handle); vendor_attr_status_send(&vendor_server_models[0], &ctx, &onoff_repo_handle, sizeof(onoff_repo_handle)); timer_index[timer_cnt] = sys_timer_add(&comfirm_check_param[timer_cnt], comfirm_check, 400); } static void set_timer_start(u8 tid, u32 delay_s, u8 index, bool onoff) { timer_cnt_get(&timer_cnt); timer_param[timer_cnt].tid = tid; timer_param[timer_cnt].index = index; timer_param[timer_cnt].onoff = onoff; timer_param[timer_cnt].timer_cnt = timer_cnt; log_info("time_cnt = %d\r\n", timer_cnt); timer_index[timer_cnt] = sys_timer_add(&timer_param[timer_cnt], timer_handler, delay_s * 1000); log_info("timer set delay %d second\r\n", delay_s); } static void vendor_attr_cfm(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { u8 cfm_tid = buffer_pull_u8_from_head(buf); indicate_flag[cfm_tid] = 1; log_info("receice vendor_attr_confirm, indicate_tid = %d\r\n", cfm_tid); } static void vendor_attr_get(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { log_info("receive vendor_attr_get, len except opcode =0x%x", buf->len); log_info_hexdump(buf->data, buf->len); } static void vendor_attr_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct net_buf_simple *buf) { log_info("receive vendor_attr_set, len except opcode =0x%x", buf->len); log_info_hexdump(buf->data, buf->len); static struct UTC_TIME cur_utc; u8 tid = buffer_pull_u8_from_head(buf); u16 Attr_Type = buffer_pull_le16_from_head(buf); switch (Attr_Type) { case ATTR_TYPE_UNIX_TIME: { u32 time = buffer_pull_le32_from_head(buf); cur_utc = unix32_to_UTC_beijing(time); log_info("\n __unix_time BeiJing time: %d/%d/%d %02d:%02d:%02d, weekday %d \n", cur_utc.year, cur_utc.month, cur_utc.day, cur_utc.hour, cur_utc.minute, cur_utc.second, cur_utc.weekday); struct __unix_time unix_time = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_STATUS), .TID = tid, .Attr_Type = Attr_Type, .time = time, }; vendor_attr_status_send(model, ctx, &unix_time, sizeof(unix_time)); } break; case ATTR_TYPE_SET_TIMEOUT: { u8 index = buffer_pull_u8_from_head(buf); u32 time = buffer_pull_le32_from_head(buf); u16 attr_type = buffer_pull_le16_from_head(buf); u8 attr_para = buffer_pull_u8_from_head(buf); struct UTC_TIME set_cur_utc = unix32_to_UTC_beijing(time); log_info("\n __set_timeout BeiJinG time: %d/%d/%d %02d:%02d:%02d, weekday %d\n", set_cur_utc.year, set_cur_utc.month, set_cur_utc.day, set_cur_utc.hour, set_cur_utc.minute, set_cur_utc.second, set_cur_utc.weekday); u32 delay_s = ((set_cur_utc.hour - cur_utc.hour) * 3600) + ((set_cur_utc.minute - cur_utc.minute) * 60) + (set_cur_utc.second - cur_utc.second); log_info("\n delay_s = %d, switch set to %d\n", delay_s, attr_para); set_timer_start(tid, delay_s, index, attr_para); struct __set_timeout set_timeout = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_STATUS), .TID = tid, .Attr_Type = Attr_Type, .param[0] = { .index = index, .time = time, .attr_type = attr_type, .attr_para = attr_para, }, }; vendor_attr_status_send(model, ctx, &set_timeout, sizeof(set_timeout)); } break; case ATTR_TYPE_SET_PERIOD_TIMEOUT: { u8 index = buffer_pull_u8_from_head(buf); u16 _24h_timer = buffer_pull_le16_from_head(buf); u8 schedule = buffer_pull_u8_from_head(buf); u16 attr_type = buffer_pull_le16_from_head(buf); u8 attr_para = buffer_pull_u8_from_head(buf); log_info("\n set_period_timeout BeiJinG time: %02d:%02d, weekday %d\n", (_24h_timer & 0x0fff) / 60, (_24h_timer & 0x0fff) % 60, schedule); struct __set_period_timeout set_period_timeout = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_STATUS), .TID = tid, .Attr_Type = Attr_Type, .period_param[0] = { .index = index, ._24h_timer = _24h_timer, .schedule = schedule, .attr_type = attr_type, .attr_para = attr_para, }, }; log_info("\n time = 0x%x\n", _24h_timer); log_info("\n set_period opcode = 0x%x, Attr_Type = 0x%x, para = 0x%x, index = 0x%x \n", set_period_timeout.Opcode, Attr_Type, attr_para, index); vendor_attr_status_send(model, ctx, &set_period_timeout, sizeof(set_period_timeout)); } break; case ATTR_TYPE_DELETE_TIMEOUT: { u8 index = buffer_pull_u8_from_head(buf); struct __delete_time delete_time = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_STATUS), .TID = tid, .Attr_Type = Attr_Type, .index = index, }; log_info("delete timeout for index = 0x%x\r\n", index); vendor_attr_status_send(model, ctx, &delete_time, sizeof(delete_time)); } break; default : log_info("\n\n\n\n default attr = 0x%x \n\n\n\n", Attr_Type); break; } } /* * @brief OnOff Model Server Op Dispatch Table */ /*-----------------------------------------------------------*/ static const struct bt_mesh_model_op gen_onoff_srv_op[] = { { BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get }, { BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set }, { BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack }, BT_MESH_MODEL_OP_END, }; /* * @brief Vendor Model Server Op Dispatch Table */ /*-----------------------------------------------------------*/ static const struct bt_mesh_model_op vendor_srv_op[] = { { VENDOR_MSG_ATTR_GET, ACCESS_OP_SIZE, vendor_attr_get }, { VENDOR_MSG_ATTR_SET, ACCESS_OP_SIZE, vendor_attr_set }, { VENDOR_MSG_ATTR_CONFIRM, 1, vendor_attr_cfm }, BT_MESH_MODEL_OP_END, }; /* * @brief Element Model Declarations * * Element 0 Root Models */ /*-----------------------------------------------------------*/ static struct bt_mesh_model root_models[] = { BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op, &gen_onoff_pub_srv, &onoff_state[0]), }; 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, NULL, &onoff_state[0]), }; /* * @brief LED to Server Model Assigmnents */ /*-----------------------------------------------------------*/ static struct bt_mesh_model *mod_srv_sw[] = { &root_models[1], }; /* * @brief 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), }; /* * @brief AliGenie UUID格式 * * detail on https://www.aligenie.com/doc/357554/gtgprq <表1:Device UUID格式> */ /*-----------------------------------------------------------*/ static u8 dev_uuid[16] = { 0xA8, 0x01, // CID 0x01 | BIT(4) | BIT(6), // PID PID_TO_LITTLE_ENDIAN(PRODUCT_ID), // ProductID MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR), // MAC BIT(1), //FeatureFlag 0x00, 0x00 // RFU }; /* * @brief AliGenie 设备配网流程 * * detail on https://www.aligenie.com/doc/357554/gtgprq */ /*-----------------------------------------------------------*/ static u8 auth_data[16]; static void hex_to_string(void *in, int in_len, void *out, int out_len) { static const char hex[] = "0123456789abcdef"; u8 *a = in; u8 *b = out; int i; if (in_len > (out_len / 2)) { log_error("\"error: in_len > (out_len / 2)\""); return; } for (i = 0; i < in_len; i++) { b[i * 2] = hex[a[i] >> 4]; b[i * 2 + 1] = hex[a[i] & 0xf]; } } static void static_auth_value_calculate(void) { log_info("--func=%s", __FUNCTION__); const u8 Product_ID[] = { PID_TO_BIG_ENDIAN(PRODUCT_ID) }; const u8 Mac_Address[] = { MAC_TO_BIG_ENDIAN(CUR_DEVICE_MAC_ADDR) }; const u8 Secret[] = { DEVICE_SECRET }; u8 string_buf[PRODUCT_ID_STRING_SIZE + MAC_ADDRESS_STRING_SIZE + SECRET_STRING_SIZE + 2]; u8 *string_p = string_buf; u8 digest[SHA256_DIGEST_SIZE]; //< Product ID hex_to_string(Product_ID, sizeof(Product_ID), string_p, PRODUCT_ID_STRING_SIZE); string_p += PRODUCT_ID_STRING_SIZE; *string_p++ = ','; //< Mac Address hex_to_string(Mac_Address, sizeof(Mac_Address), string_p, MAC_ADDRESS_STRING_SIZE); string_p += MAC_ADDRESS_STRING_SIZE; *string_p++ = ','; //< Secert memcpy(string_p, Secret, SECRET_STRING_SIZE); sha256Compute(string_buf, sizeof(string_buf), digest); memcpy(auth_data, digest, sizeof(auth_data)); log_info("string_buf : %s", string_buf); log_info_hexdump(string_buf, sizeof(string_buf)); log_info_hexdump(auth_data, sizeof(auth_data)); } void auth_data_change(u8 *c_auth_data) { memcpy(auth_data, c_auth_data, sizeof(auth_data)); } static const struct bt_mesh_prov prov = { .uuid = dev_uuid, .static_val = auth_data, .static_val_len = sizeof(auth_data), .output_size = 0, .output_actions = 0, .output_number = 0, .complete = prov_complete, .reset = prov_reset, }; /* * @brief Button Pressed Worker Task */ /*-----------------------------------------------------------*/ 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; } 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; } } void led_set(void) { led_flag = !led_flag; indicate_tid_get(&indicate_tid); timer_cnt_get(&timer_cnt); gpio_pin_write(LED0_GPIO_PIN, led_flag); log_info("state set to %d, indicate_tid now = %d\r\n", led_flag, indicate_tid); if (!bt_mesh_is_provisioned()) { log_info("no provision, not send state indicate\r\n"); return; } struct bt_mesh_msg_ctx ctx = { .addr = 0xf000, }; static struct __onoff_repo onoff_repo; onoff_repo.Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT); onoff_repo.TID = indicate_tid; onoff_repo.Attr_Type = 0x0100; onoff_repo.OnOff = led_flag; indicate_flag[indicate_tid] = 0; comfirm_check_param[timer_cnt].resend_cnt = 0; comfirm_check_param[timer_cnt].timer_cnt = timer_cnt; comfirm_check_param[timer_cnt].indicate_tid = indicate_tid; comfirm_check_param[timer_cnt].buf = &onoff_repo; comfirm_check_param[timer_cnt].len = sizeof(onoff_repo); log_info(" vendor &model = 0x%x, vendor model = 0x%x", &vendor_server_models[0], vendor_server_models[0]); vendor_attr_status_send(&vendor_server_models[0], &ctx, &onoff_repo, sizeof(onoff_repo)); timer_index[timer_cnt] = sys_timer_add(&comfirm_check_param[timer_cnt], comfirm_check, 400); } void iot_reset() { bt_mesh_reset(); p33_soft_reset(); } static u16 blink_id; void led_blink() { static bool blink_flag = 0; static blink_cnt = 0; blink_flag = ~blink_flag; blink_cnt += 1; gpio_pin_write(LED1_GPIO_PIN, blink_flag); if (blink_cnt == 6) { sys_timer_remove(blink_id); } } 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_CLICK)) { log_info("\n \n"); struct __indicate_msg HardReset_msg = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT), .TID = indicate_tid, .Attr_Type = 0xf009, .Event = 0x23, }; struct bt_mesh_msg_ctx ctx = { .addr = 0xf000, }; vendor_attr_status_send(&vendor_server_models[0], &ctx, &HardReset_msg, sizeof(HardReset_msg)); blink_id = sys_timer_add(NULL, led_blink, 300); sys_timer_add(NULL, iot_reset, 1000 * 3); return; } if ((key_number == 1) && (key_status == KEY_EVENT_LONG)) { power_set_soft_poweroff(); return; } if ((key_number == 0) && (key_status == KEY_EVENT_CLICK)) { led_set(); 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; } } static void period_msg(void *empty) { struct bt_mesh_msg_ctx ctx = { .addr = 0xf000, }; struct __onoff_repo period_indicat = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT), .TID = indicate_tid, .Attr_Type = 0x0100, //设备开关状态,与generic onoff绑定 .OnOff = led_flag, }; if (bt_mesh_is_provisioned()) { vendor_attr_status_send(&vendor_server_models[0], &ctx, &period_indicat, sizeof(period_indicat)); } } void iot_init() { if (bt_mesh_is_provisioned()) { indicate_tid_get(&indicate_tid); struct bt_mesh_msg_ctx ctx = { .addr = 0xf000, }; struct __onoff_repo state_msg = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT), .TID = indicate_tid, .Attr_Type = 0x0100, //设备开关状态,与generic onoff绑定 .OnOff = led_flag, }; vendor_attr_status_send(&vendor_server_models[0], &ctx, &state_msg, sizeof(state_msg)); indicate_tid_get(&indicate_tid); struct __indicate_msg indicate_msg = { .Opcode = buffer_head_init(VENDOR_MSG_ATTR_INDICAT), .TID = indicate_tid, .Attr_Type = 0xf009, .Event = 0x03, }; vendor_attr_status_send(&vendor_server_models[0], &ctx, &indicate_msg, sizeof(indicate_msg)); } sys_timer_add(NULL, period_msg, 180 * 1000); } static void aligenie_app_key_set(u16_t app_key) { log_info("aligenie_app_key_set"); mesh_mod_bind(root_models[1], app_key); mesh_mod_bind(vendor_server_models[0], app_key); } static void aligenie_sub_set(struct bt_mesh_model *mod, u16_t sub_addr) { int i = 0; for (i = 0; i < ARRAY_SIZE(mod->groups); i++) { if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) { mod->groups[i] = sub_addr; break; } } if (i != ARRAY_SIZE(mod->groups)) { if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_model_sub_store(mod); } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { bt_mesh_lpn_group_add(sub_addr); } } } static void aligenie_configuration() { aligenie_sub_set(&root_models[1], ALIGENIE_SUB_ADDR_1); aligenie_sub_set(&vendor_server_models[0], ALIGENIE_SUB_ADDR_1); aligenie_sub_set(&root_models[1], ALIGENIE_SUB_ADDR_2); aligenie_sub_set(&vendor_server_models[0], ALIGENIE_SUB_ADDR_2); } /* * @brief Mesh Profile Setup */ /*-----------------------------------------------------------*/ static void mesh_init(void) { log_info("--func=%s", __FUNCTION__); #if (TMALL_UPDATE_TOOL == 0) static_auth_value_calculate(); #endif 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 | BT_MESH_PROV_ADV); mesh_app_key_add_callback_register(aligenie_app_key_set); aligenie_configuration(); iot_init(); //indicate_state } void bt_ble_init(void) { #if (TMALL_UPDATE_TOOL == 0) u8 bt_addr[6] = {MAC_TO_LITTLE_ENDIAN(CUR_DEVICE_MAC_ADDR)}; bt_mac_addr_set(bt_addr); #else void set_triad(u8 * uuid); set_triad(dev_uuid); #endif mesh_setup(mesh_init); } #endif /* (CONFIG_MESH_MODEL == SIG_MESH_ALIGENIE_SOCKET) */