#include "btstack/bluetooth.h" #include "system/includes.h" #include "bt_common.h" #include "api/sig_mesh_api.h" #include "model_api.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 (CONFIG_BT_MESH_GEN_ONOFF_SRV) extern uint32_t btctler_get_rand_from_assign_range(uint32_t rand, uint32_t min, uint32_t max); extern void pseudo_random_genrate(uint8_t *dest, unsigned size); extern void gpio_pin_write(u8_t led_index, u8_t onoff); /* * 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); /* 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) #define LED0_GPIO_PIN 0 static struct onoff_state { u8_t current; u8_t previous; u8_t led_gpio_pin; }; struct onoff_state dev_onoff_state[] = { { .led_gpio_pin = LED0_GPIO_PIN }, }; const u8 led_use_port[] = { IO_PORTA_01, }; /* * 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 const struct bt_mesh_send_cb rsp_msg_cb = { // .user_intercept = respond_messsage_schedule, }; 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 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); } /* * OnOff Model Server Op Dispatch Table * */ 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, }; #endif