diff --git a/apps/blemesh_models_example_2/README.md b/apps/blemesh_models_example_2/README.md index 87de52ac4..7bec909e8 100644 --- a/apps/blemesh_models_example_2/README.md +++ b/apps/blemesh_models_example_2/README.md @@ -10,6 +10,8 @@ which Root element has following models - Generic OnOff Client - Generic Level Server - Generic Level Client +- Generic Default Transition Time Server +- Generic Default Transition Time Client - Generic Power OnOff Server - Generic Power OnOff Setup Server - Generic Power OnOff Client @@ -23,8 +25,6 @@ which Root element has following models And Secondary element has following models -- Generic OnOff Server -- Generic OnOff Client - Generic Level Server - Generic Level Client - Light CTL Temperature Server diff --git a/apps/blemesh_models_example_2/pkg.yml b/apps/blemesh_models_example_2/pkg.yml index 79f04e1e3..ee2be6da2 100644 --- a/apps/blemesh_models_example_2/pkg.yml +++ b/apps/blemesh_models_example_2/pkg.yml @@ -27,6 +27,8 @@ pkg.deps: - "@apache-mynewt-core/sys/console/full" - "@apache-mynewt-core/sys/log/full" - "@apache-mynewt-core/sys/stats/full" + - "@apache-mynewt-core/encoding/base64" + - "@apache-mynewt-core/sys/config" - nimble/controller - nimble/host - nimble/host/services/gap diff --git a/apps/blemesh_models_example_2/src/app_gpio.c b/apps/blemesh_models_example_2/src/app_gpio.c new file mode 100644 index 000000000..0dba0e396 --- /dev/null +++ b/apps/blemesh_models_example_2/src/app_gpio.c @@ -0,0 +1,76 @@ +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "bsp/bsp.h" +#include "console/console.h" +#include "hal/hal_gpio.h" +#include "mesh/mesh.h" + +#include "app_gpio.h" +#include "publisher.h" + +int button_device[] = { + BUTTON_1, + BUTTON_2, + BUTTON_3, + BUTTON_4, +}; + +int led_device[] = { + LED_1, + LED_2, + LED_3, + LED_4, +}; + +static struct ble_npl_callout button_work; + +static void button_pressed(struct os_event *ev) +{ + k_work_submit(&button_work); +} + +static struct os_event button_event; + +static void gpio_irq_handler(void *arg) +{ + button_event.ev_arg = arg; + os_eventq_put(os_eventq_dflt_get(), &button_event); +} + +void app_gpio_init(void) +{ + /* LEDs configiuratin & setting */ + + hal_gpio_init_out(led_device[0], 1); + hal_gpio_init_out(led_device[1], 1); + hal_gpio_init_out(led_device[2], 1); + hal_gpio_init_out(led_device[3], 1); + + /* Buttons configiuratin & setting */ + + k_work_init(&button_work, publish); + + button_event.ev_cb = button_pressed; + + hal_gpio_irq_init(button_device[0], gpio_irq_handler, NULL, + HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); + hal_gpio_irq_enable(button_device[0]); + + hal_gpio_irq_init(button_device[1], gpio_irq_handler, NULL, + HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); + hal_gpio_irq_enable(button_device[1]); + + hal_gpio_irq_init(button_device[2], gpio_irq_handler, NULL, + HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); + hal_gpio_irq_enable(button_device[2]); + + hal_gpio_irq_init(button_device[3], gpio_irq_handler, NULL, + HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); + hal_gpio_irq_enable(button_device[3]); +} + diff --git a/apps/blemesh_models_example_2/src/app_gpio.h b/apps/blemesh_models_example_2/src/app_gpio.h new file mode 100644 index 000000000..a92932a49 --- /dev/null +++ b/apps/blemesh_models_example_2/src/app_gpio.h @@ -0,0 +1,17 @@ +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _APP_GPIO_H +#define _APP_GPIO_H + +/* GPIO */ +extern int button_device[]; +extern int led_device[]; + +void app_gpio_init(void); + +#endif diff --git a/apps/blemesh_models_example_2/src/ble_mesh.c b/apps/blemesh_models_example_2/src/ble_mesh.c index 7145e0835..096cce394 100644 --- a/apps/blemesh_models_example_2/src/ble_mesh.c +++ b/apps/blemesh_models_example_2/src/ble_mesh.c @@ -7,6 +7,7 @@ #include "console/console.h" +#include "common.h" #include "ble_mesh.h" #include "device_composition.h" @@ -30,6 +31,7 @@ static int output_string(const char *str) static void prov_complete(u16_t net_idx, u16_t addr) { + printk("Local node provisioned, primary address 0x%04x\n", addr); } static void prov_reset(void) @@ -90,4 +92,6 @@ void blemesh_on_sync(void) bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV); console_printf("Mesh initialized\n"); + + bt_initialized(); } diff --git a/apps/blemesh_models_example_2/src/ble_mesh.h b/apps/blemesh_models_example_2/src/ble_mesh.h index fe43dff8d..409b36b2e 100644 --- a/apps/blemesh_models_example_2/src/ble_mesh.h +++ b/apps/blemesh_models_example_2/src/ble_mesh.h @@ -26,6 +26,26 @@ #define BT_MESH_MODEL_OP_GEN_MOVE_SET BT_MESH_MODEL_OP_2(0x82, 0x0B) #define BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0C) +#define BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS BT_MESH_MODEL_OP_2(0x82, 0x10) + +#define BT_MESH_MODEL_GEN_ONPOWERUP_STATUS BT_MESH_MODEL_OP_2(0x82, 0x12) + +#define BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS BT_MESH_MODEL_OP_2(0x82, 0x4E) +#define BT_MESH_MODEL_LIGHT_LIGHTNESS_LINEAR_STATUS \ + BT_MESH_MODEL_OP_2(0x82, 0x52) +#define BT_MESH_MODEL_LIGHT_LIGHTNESS_LAST_STATUS \ + BT_MESH_MODEL_OP_2(0x82, 0x54) +#define BT_MESH_MODEL_LIGHT_LIGHTNESS_DEFAULT_STATUS \ + BT_MESH_MODEL_OP_2(0x82, 0x56) +#define BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS \ + BT_MESH_MODEL_OP_2(0x82, 0x58) + +#define BT_MESH_MODEL_LIGHT_CTL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x60) +#define BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS \ + BT_MESH_MODEL_OP_2(0x82, 0x63) +#define BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS BT_MESH_MODEL_OP_2(0x82, 0x66) +#define BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS BT_MESH_MODEL_OP_2(0x82, 0x68) + void blemesh_on_reset(int reason); void blemesh_on_sync(void); void init_pub(void); diff --git a/apps/blemesh_models_example_2/src/common.h b/apps/blemesh_models_example_2/src/common.h index 8a104012a..3d42d2471 100644 --- a/apps/blemesh_models_example_2/src/common.h +++ b/apps/blemesh_models_example_2/src/common.h @@ -8,9 +8,7 @@ #ifndef _COMMON_H #define _COMMON_H -extern int button_device[]; -extern int led_device[]; - void update_light_state(void); +void bt_initialized(void); #endif diff --git a/apps/blemesh_models_example_2/src/device_composition.c b/apps/blemesh_models_example_2/src/device_composition.c index a19674d70..3e6b3832c 100644 --- a/apps/blemesh_models_example_2/src/device_composition.c +++ b/apps/blemesh_models_example_2/src/device_composition.c @@ -7,15 +7,18 @@ #include "console/console.h" #include "hal/hal_gpio.h" +#include "mesh/mesh.h" + +#include "app_gpio.h" +#include "storage.h" -#include "common.h" #include "ble_mesh.h" #include "device_composition.h" #include "state_binding.h" #include "transition.h" static struct bt_mesh_cfg_srv cfg_srv = { - .relay = BT_MESH_RELAY_DISABLED, + .relay = BT_MESH_RELAY_ENABLED, .beacon = BT_MESH_BEACON_ENABLED, #if defined(CONFIG_BT_MESH_FRIEND) @@ -32,15 +35,16 @@ static struct bt_mesh_cfg_srv cfg_srv = { .default_ttl = 7, - /* 3 transmissions with 20ms interval */ + /* 2 transmissions with 20ms interval */ .net_transmit = BT_MESH_TRANSMIT(2, 20), - .relay_retransmit = BT_MESH_TRANSMIT(2, 20), + + /* 3 transmissions with 20ms interval */ + .relay_retransmit = BT_MESH_TRANSMIT(3, 20), }; static struct bt_mesh_health_srv health_srv = { }; - static struct bt_mesh_model_pub health_pub; static struct bt_mesh_model_pub gen_onoff_srv_pub_root; @@ -56,8 +60,6 @@ static struct bt_mesh_model_pub light_lightness_cli_pub; static struct bt_mesh_model_pub light_ctl_srv_pub; static struct bt_mesh_model_pub light_ctl_cli_pub; static struct bt_mesh_model_pub vnd_pub; -static struct bt_mesh_model_pub gen_onoff_srv_pub_s0; -static struct bt_mesh_model_pub gen_onoff_cli_pub_s0; static struct bt_mesh_model_pub gen_level_srv_pub_s0; static struct bt_mesh_model_pub gen_level_cli_pub_s0; @@ -76,8 +78,6 @@ static struct os_mbuf *bt_mesh_pub_msg_light_lightness_cli_pub; static struct os_mbuf *bt_mesh_pub_msg_light_ctl_srv_pub; static struct os_mbuf *bt_mesh_pub_msg_light_ctl_cli_pub; static struct os_mbuf *bt_mesh_pub_msg_vnd_pub; -static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_srv_pub_s0; -static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_cli_pub_s0; static struct os_mbuf *bt_mesh_pub_msg_gen_level_srv_pub_s0; static struct os_mbuf *bt_mesh_pub_msg_gen_level_cli_pub_s0; @@ -98,8 +98,6 @@ void init_pub(void) bt_mesh_pub_msg_light_ctl_srv_pub = NET_BUF_SIMPLE(2 + 9); bt_mesh_pub_msg_light_ctl_cli_pub = NET_BUF_SIMPLE(2 + 9); bt_mesh_pub_msg_vnd_pub = NET_BUF_SIMPLE(3 + 6); - bt_mesh_pub_msg_gen_onoff_srv_pub_s0 = NET_BUF_SIMPLE(2 + 3); - bt_mesh_pub_msg_gen_onoff_cli_pub_s0 = NET_BUF_SIMPLE(2 + 4); bt_mesh_pub_msg_gen_level_srv_pub_s0 = NET_BUF_SIMPLE(2 + 5); bt_mesh_pub_msg_gen_level_cli_pub_s0 = NET_BUF_SIMPLE(2 + 7); @@ -118,30 +116,36 @@ void init_pub(void) light_ctl_srv_pub.msg = bt_mesh_pub_msg_light_ctl_srv_pub; light_ctl_cli_pub.msg = bt_mesh_pub_msg_light_ctl_cli_pub; vnd_pub.msg = bt_mesh_pub_msg_vnd_pub; - gen_onoff_srv_pub_s0.msg = bt_mesh_pub_msg_gen_onoff_srv_pub_s0; - gen_onoff_cli_pub_s0.msg = bt_mesh_pub_msg_gen_onoff_cli_pub_s0; gen_level_srv_pub_s0.msg = bt_mesh_pub_msg_gen_level_srv_pub_s0; gen_level_cli_pub_s0.msg = bt_mesh_pub_msg_gen_level_cli_pub_s0; } /* Definitions of models user data (Start) */ -struct generic_onoff_state gen_onoff_srv_root_user_data; +struct generic_onoff_state gen_onoff_srv_root_user_data = { + .transition = &lightness_transition, +}; -struct generic_level_state gen_level_srv_root_user_data; +struct generic_level_state gen_level_srv_root_user_data = { + .transition = &lightness_transition, +}; struct gen_def_trans_time_state gen_def_trans_time_srv_user_data; struct generic_onpowerup_state gen_power_onoff_srv_user_data; -struct light_lightness_state light_lightness_srv_user_data; +struct light_lightness_state light_lightness_srv_user_data = { + .transition = &lightness_transition, +}; -struct light_ctl_state light_ctl_srv_user_data; +struct light_ctl_state light_ctl_srv_user_data = { + .transition = &lightness_transition, +}; struct vendor_state vnd_user_data; -struct generic_onoff_state gen_onoff_srv_s0_user_data; - -struct generic_level_state gen_level_srv_s0_user_data; +struct generic_level_state gen_level_srv_s0_user_data = { + .transition = &temp_transition, +}; /* Definitions of models user data (End) */ static struct bt_mesh_elem elements[]; @@ -159,106 +163,177 @@ static void gen_onoff_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); net_buf_simple_add_u8(msg, state->onoff); - if (state->is_optional_para_available) { + if (state->transition->counter) { + calculate_rt(state->transition); net_buf_simple_add_u8(msg, state->target_onoff); - net_buf_simple_add_u8(msg, state->tt); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x00; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send GEN_ONOFF_SRV Status response\n"); } + + os_mbuf_free_chain(msg); } -static bool gen_onoff_setunack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +void gen_onoff_publish(struct bt_mesh_model *model) { - u8_t tid, onoff; - s64_t now; + int err; struct os_mbuf *msg = model->pub->msg; struct generic_onoff_state *state = model->user_data; - onoff = net_buf_simple_pull_u8(buf); - tid = net_buf_simple_pull_u8(buf); - - if (onoff > STATE_ON) { - return false; + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; } - now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && - (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return true; + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); + net_buf_simple_add_u8(msg, state->onoff); + + if (state->transition->counter) { + calculate_rt(state->transition); + net_buf_simple_add_u8(msg, state->target_onoff); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x01; - - switch (buf->om_len) { - case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; - break; - case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); - break; - default: - return false; + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); } - - enable_transition = DISABLE_TRANSITION; - - state->last_tid = tid; - state->last_tx_addr = ctx->addr; - state->last_msg_timestamp = now; - state->target_onoff = onoff; - - onoff_tt_values(state); - - if (state->tt_counter == 0) { - state->onoff = onoff; - } - - if (bt_mesh_model_elem(model)->addr == elements[0].addr) { - /* Root element */ - onoff_handler(state); - } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { - /* Secondary element */ - printk("Hello World\n"); - } - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS); - net_buf_simple_add_u8(msg, state->onoff); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } - - return true; } static void gen_onoff_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - gen_onoff_setunack(model, ctx, buf); + u8_t tid, onoff, tt, delay; + s64_t now; + struct generic_onoff_state *state = model->user_data; + + onoff = net_buf_simple_pull_u8(buf); + tid = net_buf_simple_pull_u8(buf); + + if (onoff > STATE_ON) { + return; + } + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->target_onoff = onoff; + + if (state->target_onoff != state->onoff) { + onoff_tt_values(state, tt, delay); + } else { + gen_onoff_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->onoff = state->target_onoff; + } + + state->transition->just_started = true; + gen_onoff_publish(model); + onoff_handler(state); } static void gen_onoff_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - if (gen_onoff_setunack(model, ctx, buf) == true) { - gen_onoff_get(model, ctx, buf); + u8_t tid, onoff, tt, delay; + s64_t now; + struct generic_onoff_state *state = model->user_data; + + onoff = net_buf_simple_pull_u8(buf); + tid = net_buf_simple_pull_u8(buf); + + if (onoff > STATE_ON) { + return; } + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + gen_onoff_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->target_onoff = onoff; + + if (state->target_onoff != state->onoff) { + onoff_tt_values(state, tt, delay); + } else { + gen_onoff_get(model, ctx, buf); + gen_onoff_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->onoff = state->target_onoff; + } + + state->transition->just_started = true; + gen_onoff_get(model, ctx, buf); + gen_onoff_publish(model); + onoff_handler(state); } /* Generic OnOff Client message handlers */ @@ -286,158 +361,244 @@ static void gen_level_get(struct bt_mesh_model *model, bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); net_buf_simple_add_le16(msg, state->level); - if (state->is_optional_para_available == 0x01) { + if (state->transition->counter) { + calculate_rt(state->transition); net_buf_simple_add_le16(msg, state->target_level); - net_buf_simple_add_u8(msg, state->tt); - } else if (state->is_optional_para_available == 0x02) { - - if (state->last_delta < 0) { - net_buf_simple_add_le16(msg, INT16_MIN); - } else if (state->last_delta > 0) { - net_buf_simple_add_le16(msg, INT16_MAX); - } - - net_buf_simple_add_u8(msg, state->tt); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x00; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send GEN_LEVEL_SRV Status response\n"); } + + os_mbuf_free_chain(msg); +} + +void gen_level_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct generic_level_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); + net_buf_simple_add_le16(msg, state->level); + + if (state->transition->counter) { + calculate_rt(state->transition); + net_buf_simple_add_le16(msg, state->target_level); + net_buf_simple_add_u8(msg, state->transition->rt); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } } static void gen_level_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - u8_t tid; + u8_t tid, tt, delay; s16_t level; s64_t now; - struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; level = (s16_t) net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { return; } - state->is_optional_para_available = 0x01; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; state->target_level = level; - level_tt_values(state); - - if (state->tt_counter == 0) { - state->level = level; + if (state->target_level != state->level) { + level_tt_values(state, tt, delay); + } else { + gen_level_publish(model); + return; } + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->level = state->target_level; + } + + state->transition->just_started = true; + gen_level_publish(model); + if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ - enable_transition = LEVEL_TT; + transition_type = LEVEL_TT; level_lightness_handler(state); } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { /* Secondary element */ - enable_transition = LEVEL_TEMP_TT; + transition_type = LEVEL_TEMP_TT; level_temp_handler(state); } - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); - net_buf_simple_add_le16(msg, state->level); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } } static void gen_level_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - gen_level_set_unack(model, ctx, buf); + u8_t tid, tt, delay; + s16_t level; + s64_t now; + struct generic_level_state *state = model->user_data; + + level = (s16_t) net_buf_simple_pull_le16(buf); + tid = net_buf_simple_pull_u8(buf); + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + gen_level_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->target_level = level; + + if (state->target_level != state->level) { + level_tt_values(state, tt, delay); + } else { + gen_level_get(model, ctx, buf); + gen_level_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->level = state->target_level; + } + + state->transition->just_started = true; gen_level_get(model, ctx, buf); + gen_level_publish(model); + + if (bt_mesh_model_elem(model)->addr == elements[0].addr) { + /* Root element */ + transition_type = LEVEL_TT; + level_lightness_handler(state); + } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { + /* Secondary element */ + transition_type = LEVEL_TEMP_TT; + level_temp_handler(state); + } } static void gen_delta_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - u8_t tid; + u8_t tid, tt, delay; s32_t tmp32, delta; s64_t now; - struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; delta = (s32_t) net_buf_simple_pull_le32(buf); tid = net_buf_simple_pull_u8(buf); now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr) { + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { - if (now - state->last_msg_timestamp <= K_SECONDS(6)) { - if (state->last_delta == delta) { - return; - } - tmp32 = state->last_level + delta; - } else { + if (state->last_delta == delta) { return; } + tmp32 = state->last_level + delta; } else { state->last_level = state->level; tmp32 = state->level + delta; } - state->is_optional_para_available = 0x01; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); - state->last_delta = delta; state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; + state->last_delta = delta; if (tmp32 < INT16_MIN) { tmp32 = INT16_MIN; @@ -447,85 +608,226 @@ static void gen_delta_set_unack(struct bt_mesh_model *model, state->target_level = tmp32; - delta_level_tt_values(state); - - if (state->tt_counter_delta == 0) { - state->level = tmp32; + if (state->target_level != state->level) { + level_tt_values(state, tt, delay); + } else { + gen_level_publish(model); + return; } + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->level = state->target_level; + } + + state->transition->just_started = true; + gen_level_publish(model); + if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ - enable_transition = LEVEL_TT_DELTA; + transition_type = LEVEL_TT_DELTA; level_lightness_handler(state); - } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { + } else if (bt_mesh_model_elem(model)->addr == + elements[1].addr) { /* Secondary element */ - enable_transition = LEVEL_TEMP_TT_DELTA; + transition_type = LEVEL_TEMP_TT_DELTA; level_temp_handler(state); } - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); - net_buf_simple_add_le16(msg, state->level); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } } static void gen_delta_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - gen_delta_set_unack(model, ctx, buf); + u8_t tid, tt, delay; + s32_t tmp32, delta; + s64_t now; + struct generic_level_state *state = model->user_data; + + delta = (s32_t) net_buf_simple_pull_le32(buf); + tid = net_buf_simple_pull_u8(buf); + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + + if (state->last_delta == delta) { + gen_level_get(model, ctx, buf); + return; + } + tmp32 = state->last_level + delta; + + } else { + state->last_level = state->level; + tmp32 = state->level + delta; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->last_delta = delta; + + if (tmp32 < INT16_MIN) { + tmp32 = INT16_MIN; + } else if (tmp32 > INT16_MAX) { + tmp32 = INT16_MAX; + } + + state->target_level = tmp32; + + if (state->target_level != state->level) { + level_tt_values(state, tt, delay); + } else { + gen_level_get(model, ctx, buf); + gen_level_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->level = state->target_level; + } + + state->transition->just_started = true; gen_level_get(model, ctx, buf); + gen_level_publish(model); + + if (bt_mesh_model_elem(model)->addr == elements[0].addr) { + /* Root element */ + transition_type = LEVEL_TT_DELTA; + level_lightness_handler(state); + } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { + /* Secondary element */ + transition_type = LEVEL_TEMP_TT_DELTA; + level_temp_handler(state); + } +} + +static void gen_level_move_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); + struct generic_level_state *state = model->user_data; + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); + net_buf_simple_add_le16(msg, state->level); + + if (state->transition->counter) { + if (state->last_delta < 0) { + net_buf_simple_add_le16(msg, INT16_MIN); + } else { /* 0 should not be possible */ + net_buf_simple_add_le16(msg, INT16_MAX); + } + + net_buf_simple_add_u8(msg, UNKNOWN_VALUE); + } + + if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + printk("Unable to send GEN_LEVEL_SRV Status response\n"); + } + + os_mbuf_free_chain(msg); +} + +static void gen_level_move_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct generic_level_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); + net_buf_simple_add_le16(msg, state->level); + + if (state->transition->counter) { + if (state->last_delta < 0) { + net_buf_simple_add_le16(msg, INT16_MIN); + } else { /* 0 should not be possible */ + net_buf_simple_add_le16(msg, INT16_MAX); + } + + net_buf_simple_add_u8(msg, UNKNOWN_VALUE); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } } static void gen_move_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - u8_t tid; + u8_t tid, tt, delay; s16_t delta; s32_t tmp32; s64_t now; - struct os_mbuf *msg = model->pub->msg; struct generic_level_state *state = model->user_data; delta = (s16_t) net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { return; } - state->is_optional_para_available = 0x02; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); - state->last_delta = delta; state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; + state->last_delta = delta; tmp32 = state->level + delta; if (tmp32 < INT16_MIN) { @@ -536,36 +838,28 @@ static void gen_move_set_unack(struct bt_mesh_model *model, state->target_level = tmp32; - move_level_tt_values(state); + if (state->target_level != state->level) { + level_tt_values(state, tt, delay); + } else { + gen_level_move_publish(model); + return; + } + + if (state->transition->counter == 0) { + return; + } + + state->transition->just_started = true; + gen_level_move_publish(model); if (bt_mesh_model_elem(model)->addr == elements[0].addr) { /* Root element */ - if (delta == 0) { - ble_npl_callout_stop(&level_lightness_transition_timer); - } else { - enable_transition = LEVEL_TT_MOVE; - level_lightness_handler(state); - } + transition_type = LEVEL_TT_MOVE; + level_lightness_handler(state); } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { /* Secondary element */ - if (delta == 0) { - ble_npl_callout_stop(&level_temp_transition_timer); - } else { - enable_transition = LEVEL_TEMP_TT_MOVE; - level_temp_handler(state); - } - } - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_LEVEL_STATUS); - net_buf_simple_add_le16(msg, state->level); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } + transition_type = LEVEL_TEMP_TT_MOVE; + level_temp_handler(state); } } @@ -573,8 +867,84 @@ static void gen_move_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - gen_move_set_unack(model, ctx, buf); - gen_level_get(model, ctx, buf); + u8_t tid, tt, delay; + s16_t delta; + s32_t tmp32; + s64_t now; + struct generic_level_state *state = model->user_data; + + delta = (s16_t) net_buf_simple_pull_le16(buf); + tid = net_buf_simple_pull_u8(buf); + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + gen_level_move_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->last_delta = delta; + + tmp32 = state->level + delta; + if (tmp32 < INT16_MIN) { + tmp32 = INT16_MIN; + } else if (tmp32 > INT16_MAX) { + tmp32 = INT16_MAX; + } + + state->target_level = tmp32; + + if (state->target_level != state->level) { + level_tt_values(state, tt, delay); + } else { + gen_level_move_get(model, ctx, buf); + gen_level_move_publish(model); + return; + } + + if (state->transition->counter == 0) { + return; + } + + state->transition->just_started = true; + gen_level_move_get(model, ctx, buf); + gen_level_move_publish(model); + + if (bt_mesh_model_elem(model)->addr == elements[0].addr) { + /* Root element */ + transition_type = LEVEL_TT_MOVE; + level_lightness_handler(state); + } else if (bt_mesh_model_elem(model)->addr == elements[1].addr) { + /* Secondary element */ + transition_type = LEVEL_TEMP_TT_MOVE; + level_temp_handler(state); + } } /* Generic Level Client message handlers */ @@ -599,12 +969,33 @@ static void gen_def_trans_time_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4); struct gen_def_trans_time_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x10)); + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS); net_buf_simple_add_u8(msg, state->tt); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send GEN_DEF_TT_SRV Status response\n"); } + + os_mbuf_free_chain(msg); +} + +static void gen_def_trans_time_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct gen_def_trans_time_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_DEF_TRANS_TIME_STATUS); + net_buf_simple_add_u8(msg, state->tt); + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } } static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, @@ -612,7 +1003,6 @@ static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, struct os_mbuf *buf) { u8_t tt; - struct os_mbuf *msg = model->pub->msg; struct gen_def_trans_time_state *state = model->user_data; tt = net_buf_simple_pull_u8(buf); @@ -623,21 +1013,11 @@ static bool gen_def_trans_time_setunack(struct bt_mesh_model *model, return false; } - state->tt = tt; - default_tt = tt; + if (state->tt != tt) { + state->tt = tt; + default_tt = tt; - /* Do some work here to save value of state->tt on SoC flash */ - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x10)); - net_buf_simple_add_u8(msg, state->tt); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } + save_on_flash(GEN_DEF_TRANS_TIME_STATE); } return true; @@ -647,7 +1027,9 @@ static void gen_def_trans_time_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - gen_def_trans_time_setunack(model, ctx, buf); + if (gen_def_trans_time_setunack(model, ctx, buf) == true) { + gen_def_trans_time_publish(model); + } } static void gen_def_trans_time_set(struct bt_mesh_model *model, @@ -656,6 +1038,7 @@ static void gen_def_trans_time_set(struct bt_mesh_model *model, { if (gen_def_trans_time_setunack(model, ctx, buf) == true) { gen_def_trans_time_get(model, ctx, buf); + gen_def_trans_time_publish(model); } } @@ -676,12 +1059,14 @@ static void gen_onpowerup_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4); struct generic_onpowerup_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x12)); + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_ONPOWERUP_STATUS); net_buf_simple_add_u8(msg, state->onpowerup); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send GEN_POWER_ONOFF_SRV Status response\n"); } + + os_mbuf_free_chain(msg); } /* Generic Power OnOff Client message handlers */ @@ -694,12 +1079,31 @@ static void gen_onpowerup_status(struct bt_mesh_model *model, } /* Generic Power OnOff Setup Server message handlers */ + +static void gen_onpowerup_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct generic_onpowerup_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_GEN_ONPOWERUP_STATUS); + net_buf_simple_add_u8(msg, state->onpowerup); + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } +} + static bool gen_onpowerup_setunack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { u8_t onpowerup; - struct os_mbuf *msg = model->pub->msg; struct generic_onpowerup_state *state = model->user_data; onpowerup = net_buf_simple_pull_u8(buf); @@ -709,20 +1113,11 @@ static bool gen_onpowerup_setunack(struct bt_mesh_model *model, if (onpowerup > STATE_RESTORE) { return false; } - state->onpowerup = onpowerup; - /* Do some work here to save value of state->onpowerup on SoC flash */ + if (state->onpowerup != onpowerup) { + state->onpowerup = onpowerup; - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x12)); - net_buf_simple_add_u8(msg, state->onpowerup); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } + save_on_flash(GEN_ONPOWERUP_STATE); } return true; @@ -732,7 +1127,9 @@ static void gen_onpowerup_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - gen_onpowerup_setunack(model, ctx, buf); + if (gen_onpowerup_setunack(model, ctx, buf) == true) { + gen_onpowerup_publish(model); + } } static void gen_onpowerup_set(struct bt_mesh_model *model, @@ -741,6 +1138,7 @@ static void gen_onpowerup_set(struct bt_mesh_model *model, { if (gen_onpowerup_setunack(model, ctx, buf) == true) { gen_onpowerup_get(model, ctx, buf); + gen_onpowerup_publish(model); } } @@ -752,14 +1150,18 @@ static void vnd_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(3 + 6 + 4); struct vendor_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME)); + /* This is dummy response for demo purpose */ + state->response = 0xA578FEB3; + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x04, CID_RUNTIME)); net_buf_simple_add_le16(msg, state->current); net_buf_simple_add_le32(msg, state->response); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send VENDOR Status response\n"); } + + os_mbuf_free_chain(msg); } static void vnd_set_unack(struct bt_mesh_model *model, @@ -775,19 +1177,19 @@ static void vnd_set_unack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && - (now - state->last_msg_timestamp <= 6000)) { + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { return; } state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; state->current = current; - /* This is dummy response for demo purpose */ - state->response = 0xA578FEB3; - printk("Vendor model message = %04x\n", state->current); if (state->current == STATE_ON) { @@ -824,60 +1226,90 @@ static void light_lightness_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct light_lightness_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x4E)); + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS); net_buf_simple_add_le16(msg, state->actual); - if (state->is_optional_para_available) { + if (state->transition->counter) { + calculate_rt(state->transition); net_buf_simple_add_le16(msg, state->target_actual); - net_buf_simple_add_u8(msg, state->tt); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x00; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightLightnessAct Status response\n"); } + + os_mbuf_free_chain(msg); +} + +void light_lightness_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_lightness_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_STATUS); + net_buf_simple_add_le16(msg, state->actual); + + if (state->transition->counter) { + calculate_rt(state->transition); + net_buf_simple_add_le16(msg, state->target_actual); + net_buf_simple_add_u8(msg, state->transition->rt); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } } static void light_lightness_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - u8_t tid; + u8_t tid, tt, delay; u16_t actual; s64_t now; - struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; actual = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { return; } - state->is_optional_para_available = 0x01; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; if (actual > 0 && actual < state->light_range_min) { @@ -888,33 +1320,94 @@ static void light_lightness_set_unack(struct bt_mesh_model *model, state->target_actual = actual; - light_lightnes_actual_tt_values(state); - - if (state->tt_counter_actual == 0) { - state->actual = actual; + if (state->target_actual != state->actual) { + light_lightness_actual_tt_values(state, tt, delay); + } else { + light_lightness_publish(model); + return; } + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->actual = state->target_actual; + } + + state->transition->just_started = true; + light_lightness_publish(model); light_lightness_actual_handler(state); - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x4E)); - net_buf_simple_add_le16(msg, state->actual); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } } static void light_lightness_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_lightness_set_unack(model, ctx, buf); + u8_t tid, tt, delay; + u16_t actual; + s64_t now; + struct light_lightness_state *state = model->user_data; + + actual = net_buf_simple_pull_le16(buf); + tid = net_buf_simple_pull_u8(buf); + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + light_lightness_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + + if (actual > 0 && actual < state->light_range_min) { + actual = state->light_range_min; + } else if (actual > state->light_range_max) { + actual = state->light_range_max; + } + + state->target_actual = actual; + + if (state->target_actual != state->actual) { + light_lightness_actual_tt_values(state, tt, delay); + } else { + light_lightness_get(model, ctx, buf); + light_lightness_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->actual = state->target_actual; + } + + state->transition->just_started = true; light_lightness_get(model, ctx, buf); + light_lightness_publish(model); + light_lightness_actual_handler(state); } static void light_lightness_linear_get(struct bt_mesh_model *model, @@ -924,90 +1417,176 @@ static void light_lightness_linear_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct light_lightness_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x52)); + bt_mesh_model_msg_init(msg, + BT_MESH_MODEL_LIGHT_LIGHTNESS_LINEAR_STATUS); net_buf_simple_add_le16(msg, state->linear); - if (state->is_optional_para_available) { + if (state->transition->counter) { + calculate_rt(state->transition); net_buf_simple_add_le16(msg, state->target_linear); - net_buf_simple_add_u8(msg, state->tt); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x00; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightLightnessLin Status response\n"); } + + os_mbuf_free_chain(msg); +} + +void light_lightness_linear_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_lightness_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, + BT_MESH_MODEL_LIGHT_LIGHTNESS_LINEAR_STATUS); + net_buf_simple_add_le16(msg, state->linear); + + if (state->transition->counter) { + calculate_rt(state->transition); + net_buf_simple_add_le16(msg, state->target_linear); + net_buf_simple_add_u8(msg, state->transition->rt); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } } static void light_lightness_linear_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - u8_t tid; + u8_t tid, tt, delay; u16_t linear; s64_t now; - struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; linear = net_buf_simple_pull_le16(buf); tid = net_buf_simple_pull_u8(buf); now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { return; } - state->is_optional_para_available = 0x01; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; state->target_linear = linear; - light_lightnes_linear_tt_values(state); - - if (state->tt_counter_linear == 0) { - state->linear = linear; + if (state->target_linear != state->linear) { + light_lightness_linear_tt_values(state, tt, delay); + } else { + light_lightness_linear_publish(model); + return; } + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->linear = state->target_linear; + } + + state->transition->just_started = true; + light_lightness_linear_publish(model); light_lightness_linear_handler(state); - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x52)); - net_buf_simple_add_le16(msg, state->linear); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } } static void light_lightness_linear_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_lightness_linear_set_unack(model, ctx, buf); + u8_t tid, tt, delay; + u16_t linear; + s64_t now; + struct light_lightness_state *state = model->user_data; + + linear = net_buf_simple_pull_le16(buf); + tid = net_buf_simple_pull_u8(buf); + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + light_lightness_linear_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->target_linear = linear; + + if (state->target_linear != state->linear) { + light_lightness_linear_tt_values(state, tt, delay); + } else { + light_lightness_linear_get(model, ctx, buf); + light_lightness_linear_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->linear = state->target_linear; + } + + state->transition->just_started = true; light_lightness_linear_get(model, ctx, buf); + light_lightness_linear_publish(model); + light_lightness_linear_handler(state); } static void light_lightness_last_get(struct bt_mesh_model *model, @@ -1017,13 +1596,14 @@ static void light_lightness_last_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4); struct light_lightness_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x54)); - + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_LAST_STATUS); net_buf_simple_add_le16(msg, state->last); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightLightnessLast Status response\n"); } + + os_mbuf_free_chain(msg); } static void light_lightness_default_get(struct bt_mesh_model *model, @@ -1033,13 +1613,15 @@ static void light_lightness_default_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4); struct light_lightness_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x56)); - + bt_mesh_model_msg_init(msg, + BT_MESH_MODEL_LIGHT_LIGHTNESS_DEFAULT_STATUS); net_buf_simple_add_le16(msg, state->def); if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightLightnessDef Status response\n"); } + + os_mbuf_free_chain(msg); } static void light_lightness_range_get(struct bt_mesh_model *model, @@ -1049,8 +1631,9 @@ static void light_lightness_range_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct light_lightness_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x58)); + state->status_code = RANGE_SUCCESSFULLY_UPDATED; + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS); net_buf_simple_add_u8(msg, state->status_code); net_buf_simple_add_le16(msg, state->light_range_min); net_buf_simple_add_le16(msg, state->light_range_max); @@ -1059,34 +1642,50 @@ static void light_lightness_range_get(struct bt_mesh_model *model, printk("Unable to send LightLightnessRange Status response\n"); } - state->status_code = RANGE_SUCCESSFULLY_UPDATED; + os_mbuf_free_chain(msg); } /* Light Lightness Setup Server message handlers */ + +static void light_lightness_default_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_lightness_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, + BT_MESH_MODEL_LIGHT_LIGHTNESS_DEFAULT_STATUS); + net_buf_simple_add_le16(msg, state->def); + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } +} + static void light_lightness_default_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - struct os_mbuf *msg = model->pub->msg; + u16_t lightness; struct light_lightness_state *state = model->user_data; - state->def = net_buf_simple_pull_le16(buf); + lightness = net_buf_simple_pull_le16(buf); /* Here, Model specification is silent about tid implementation */ - /* Do some work here to save value of state->def on SoC flash */ + if (state->def != lightness) { + state->def = lightness; + light_ctl_srv_user_data.lightness_def = state->def; - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x56)); - net_buf_simple_add_le16(msg, state->def); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } + save_on_flash(LIGHTNESS_TEMP_DEF_STATE); } + + light_lightness_default_publish(model); } static void light_lightness_default_set(struct bt_mesh_model *model, @@ -1095,14 +1694,35 @@ static void light_lightness_default_set(struct bt_mesh_model *model, { light_lightness_default_set_unack(model, ctx, buf); light_lightness_default_get(model, ctx, buf); + light_lightness_default_publish(model); +} + +static void light_lightness_range_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_lightness_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_LIGHTNESS_RANGE_STATUS); + net_buf_simple_add_u8(msg, state->status_code); + net_buf_simple_add_le16(msg, state->light_range_min); + net_buf_simple_add_le16(msg, state->light_range_max); + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } } static bool light_lightness_range_setunack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) + struct os_mbuf *buf) { u16_t min, max; - struct os_mbuf *msg = model->pub->msg; struct light_lightness_state *state = model->user_data; min = net_buf_simple_pull_le16(buf); @@ -1116,14 +1736,14 @@ static bool light_lightness_range_setunack(struct bt_mesh_model *model, if (min <= max) { state->status_code = RANGE_SUCCESSFULLY_UPDATED; - state->light_range_min = min; - state->light_range_max = max; + if (state->light_range_min != min || + state->light_range_max != max) { - /* Do some work here to save values of - * state->light_range_min & - * state->light_range_max - * on SoC flash - */ + state->light_range_min = min; + state->light_range_max = max; + + save_on_flash(LIGHTNESS_RANGE); + } } else { /* The provided value for Range Max cannot be set */ state->status_code = CANNOT_SET_RANGE_MAX; @@ -1131,20 +1751,6 @@ static bool light_lightness_range_setunack(struct bt_mesh_model *model, } } - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x58)); - net_buf_simple_add_u8(msg, state->status_code); - net_buf_simple_add_le16(msg, state->light_range_min); - net_buf_simple_add_le16(msg, state->light_range_max); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } - return true; } @@ -1152,7 +1758,9 @@ static void light_lightness_range_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_lightness_range_setunack(model, ctx, buf); + if (light_lightness_range_setunack(model, ctx, buf) == true) { + light_lightness_range_publish(model); + } } static void light_lightness_range_set(struct bt_mesh_model *model, @@ -1161,6 +1769,7 @@ static void light_lightness_range_set(struct bt_mesh_model *model, { if (light_lightness_range_setunack(model, ctx, buf) == true) { light_lightness_range_get(model, ctx, buf); + light_lightness_range_publish(model); } } @@ -1227,32 +1836,63 @@ static void light_ctl_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4); struct light_ctl_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x60)); + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_STATUS); net_buf_simple_add_le16(msg, state->lightness); net_buf_simple_add_le16(msg, state->temp); - if (state->is_optional_para_available) { + if (state->transition->counter) { + calculate_rt(state->transition); net_buf_simple_add_le16(msg, state->target_lightness); net_buf_simple_add_le16(msg, state->target_temp); - net_buf_simple_add_u8(msg, state->tt); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x00; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightCTL Status response\n"); } + + os_mbuf_free_chain(msg); } -static bool light_ctl_setunack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +void light_ctl_publish(struct bt_mesh_model *model) { - u8_t tid; + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_ctl_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_STATUS); + + /* Here, as per Model specification, status should be + * made up of lightness & temperature values only + */ + net_buf_simple_add_le16(msg, state->lightness); + net_buf_simple_add_le16(msg, state->temp); + + if (state->transition->counter) { + calculate_rt(state->transition); + net_buf_simple_add_le16(msg, state->target_lightness); + net_buf_simple_add_le16(msg, state->target_temp); + net_buf_simple_add_u8(msg, state->transition->rt); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } +} + +static void light_ctl_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + u8_t tid, tt, delay; s16_t delta_uv; u16_t lightness, temp; s64_t now; - struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; lightness = net_buf_simple_pull_le16(buf); @@ -1261,35 +1901,40 @@ static bool light_ctl_setunack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return false; + return; } now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return true; + return; } - state->is_optional_para_available = 0x01; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: - return false; + return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; state->target_lightness = lightness; @@ -1302,50 +1947,111 @@ static bool light_ctl_setunack(struct bt_mesh_model *model, state->target_temp = temp; state->target_delta_uv = delta_uv; - light_ctl_tt_values(state); - - if (state->tt_counter == 0) { - state->lightness = lightness; - state->temp = temp; - state->delta_uv = delta_uv; + if (state->target_lightness != state->lightness || + state->target_temp != state->temp || + state->target_delta_uv != state->delta_uv) { + light_ctl_tt_values(state, tt, delay); + } else { + light_ctl_publish(model); + return; } + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->lightness = state->target_lightness; + state->temp = state->target_temp; + state->delta_uv = state->target_delta_uv; + } + + state->transition->just_started = true; + light_ctl_publish(model); light_ctl_handler(state); - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x60)); - - /* Here, as per Model specification, status should be - * made up of lightness & temperature values only - */ - net_buf_simple_add_le16(msg, state->lightness); - net_buf_simple_add_le16(msg, state->temp); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } - - return true; -} - -static void light_ctl_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - light_ctl_setunack(model, ctx, buf); } static void light_ctl_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - if (light_ctl_setunack(model, ctx, buf) == true) { - light_ctl_get(model, ctx, buf); + u8_t tid, tt, delay; + s16_t delta_uv; + u16_t lightness, temp; + s64_t now; + struct light_ctl_state *state = model->user_data; + + lightness = net_buf_simple_pull_le16(buf); + temp = net_buf_simple_pull_le16(buf); + delta_uv = (s16_t) net_buf_simple_pull_le16(buf); + tid = net_buf_simple_pull_u8(buf); + + if (temp < TEMP_MIN || temp > TEMP_MAX) { + return; } + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + light_ctl_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->target_lightness = lightness; + + if (temp < state->temp_range_min) { + temp = state->temp_range_min; + } else if (temp > state->temp_range_max) { + temp = state->temp_range_max; + } + + state->target_temp = temp; + state->target_delta_uv = delta_uv; + + if (state->target_lightness != state->lightness || + state->target_temp != state->temp || + state->target_delta_uv != state->delta_uv) { + light_ctl_tt_values(state, tt, delay); + } else { + light_ctl_get(model, ctx, buf); + light_ctl_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->lightness = state->target_lightness; + state->temp = state->target_temp; + state->delta_uv = state->target_delta_uv; + } + + state->transition->just_started = true; + light_ctl_get(model, ctx, buf); + light_ctl_publish(model); + light_ctl_handler(state); } static void light_ctl_temp_range_get(struct bt_mesh_model *model, @@ -1355,7 +2061,9 @@ static void light_ctl_temp_range_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); struct light_ctl_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x63)); + state->status_code = RANGE_SUCCESSFULLY_UPDATED; + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS); net_buf_simple_add_u8(msg, state->status_code); net_buf_simple_add_le16(msg, state->temp_range_min); net_buf_simple_add_le16(msg, state->temp_range_max); @@ -1364,7 +2072,7 @@ static void light_ctl_temp_range_get(struct bt_mesh_model *model, printk("Unable to send LightCTL Temp Range Status response\n"); } - state->status_code = RANGE_SUCCESSFULLY_UPDATED; + os_mbuf_free_chain(msg); } static void light_ctl_default_get(struct bt_mesh_model *model, @@ -1374,7 +2082,7 @@ static void light_ctl_default_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 6 + 4); struct light_ctl_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x68)); + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS); net_buf_simple_add_le16(msg, state->lightness_def); net_buf_simple_add_le16(msg, state->temp_def); net_buf_simple_add_le16(msg, state->delta_uv_def); @@ -1382,16 +2090,39 @@ static void light_ctl_default_get(struct bt_mesh_model *model, if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightCTL Default Status response\n"); } + + os_mbuf_free_chain(msg); } /* Light CTL Setup Server message handlers */ + +static void light_ctl_default_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_ctl_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_DEFAULT_STATUS); + net_buf_simple_add_le16(msg, state->lightness_def); + net_buf_simple_add_le16(msg, state->temp_def); + net_buf_simple_add_le16(msg, state->delta_uv_def); + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } +} + static bool light_ctl_default_setunack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { u16_t lightness, temp; s16_t delta_uv; - struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; lightness = net_buf_simple_pull_le16(buf); @@ -1410,27 +2141,13 @@ static bool light_ctl_default_setunack(struct bt_mesh_model *model, temp = state->temp_range_max; } - state->lightness_def = lightness; - state->temp_def = temp; - state->delta_uv_def = delta_uv; + if (state->lightness_def != lightness || state->temp_def != temp || + state->delta_uv_def != delta_uv) { + state->lightness_def = lightness; + state->temp_def = temp; + state->delta_uv_def = delta_uv; - /* Do some work here to save values of - * state->lightness_def, state->temp_Def & state->delta_uv_def - * on SoC flash - */ - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x68)); - net_buf_simple_add_le16(msg, state->lightness_def); - net_buf_simple_add_le16(msg, state->temp_def); - net_buf_simple_add_le16(msg, state->delta_uv_def); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } + save_on_flash(LIGHTNESS_TEMP_DEF_STATE); } return true; @@ -1440,7 +2157,9 @@ static void light_ctl_default_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_ctl_default_setunack(model, ctx, buf); + if (light_ctl_default_setunack(model, ctx, buf) == true) { + light_ctl_default_publish(model); + } } static void light_ctl_default_set(struct bt_mesh_model *model, @@ -1449,6 +2168,28 @@ static void light_ctl_default_set(struct bt_mesh_model *model, { if (light_ctl_default_setunack(model, ctx, buf) == true) { light_ctl_default_get(model, ctx, buf); + light_ctl_default_publish(model); + } +} + +static void light_ctl_temp_range_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_ctl_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_RANGE_STATUS); + net_buf_simple_add_u8(msg, state->status_code); + net_buf_simple_add_le16(msg, state->temp_range_min); + net_buf_simple_add_le16(msg, state->temp_range_max); + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); } } @@ -1457,7 +2198,6 @@ static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, struct os_mbuf *buf) { u16_t min, max; - struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; min = net_buf_simple_pull_le16(buf); @@ -1473,33 +2213,21 @@ static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, if (min <= max) { state->status_code = RANGE_SUCCESSFULLY_UPDATED; - state->temp_range_min = min; - state->temp_range_max = max; - /* Do some work here to save values of - * state->temp_range_min & state->temp_range_min - * on SoC flash - */ + if (state->temp_range_min != min || + state->temp_range_max != max) { + + state->temp_range_min = min; + state->temp_range_max = max; + + save_on_flash(TEMPERATURE_RANGE); + } } else { /* The provided value for Range Max cannot be set */ state->status_code = CANNOT_SET_RANGE_MAX; return false; } - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x63)); - net_buf_simple_add_u8(msg, state->status_code); - net_buf_simple_add_le16(msg, state->temp_range_min); - net_buf_simple_add_le16(msg, state->temp_range_max); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } - return true; } @@ -1507,7 +2235,9 @@ static void light_ctl_temp_range_set_unack(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - light_ctl_temp_range_setunack(model, ctx, buf); + if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { + light_ctl_temp_range_publish(model); + } } static void light_ctl_temp_range_set(struct bt_mesh_model *model, @@ -1516,6 +2246,7 @@ static void light_ctl_temp_range_set(struct bt_mesh_model *model, { if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { light_ctl_temp_range_get(model, ctx, buf); + light_ctl_temp_range_publish(model); } } @@ -1585,33 +2316,59 @@ static void light_ctl_temp_get(struct bt_mesh_model *model, struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4); struct light_ctl_state *state = model->user_data; - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x66)); + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS); net_buf_simple_add_le16(msg, state->temp); net_buf_simple_add_le16(msg, state->delta_uv); - if (state->is_optional_para_available) { + if (state->transition->counter) { + calculate_rt(state->transition); net_buf_simple_add_le16(msg, state->target_temp); net_buf_simple_add_le16(msg, state->target_delta_uv); - net_buf_simple_add_u8(msg, state->tt); + net_buf_simple_add_u8(msg, state->transition->rt); } - state->is_optional_para_available = 0x00; - if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { printk("Unable to send LightCTL Temp. Status response\n"); } + + os_mbuf_free_chain(msg); } -static bool light_ctl_temp_setunack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) +void light_ctl_temp_publish(struct bt_mesh_model *model) { - u8_t tid; + int err; + struct os_mbuf *msg = model->pub->msg; + struct light_ctl_state *state = model->user_data; + + if (model->pub->addr == BT_MESH_ADDR_UNASSIGNED) { + return; + } + + bt_mesh_model_msg_init(msg, BT_MESH_MODEL_LIGHT_CTL_TEMP_STATUS); + net_buf_simple_add_le16(msg, state->temp); + net_buf_simple_add_le16(msg, state->delta_uv); + + if (state->transition->counter) { + calculate_rt(state->transition); + net_buf_simple_add_le16(msg, state->target_temp); + net_buf_simple_add_le16(msg, state->target_delta_uv); + net_buf_simple_add_u8(msg, state->transition->rt); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } +} + +static void light_ctl_temp_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + u8_t tid, tt, delay; s16_t delta_uv; u16_t temp; s64_t now; - - struct os_mbuf *msg = model->pub->msg; struct light_ctl_state *state = model->user_data; temp = net_buf_simple_pull_le16(buf); @@ -1619,35 +2376,40 @@ static bool light_ctl_temp_setunack(struct bt_mesh_model *model, tid = net_buf_simple_pull_u8(buf); if (temp < TEMP_MIN || temp > TEMP_MAX) { - return false; + return; } now = k_uptime_get(); - if (state->last_tid == tid && state->last_tx_addr == ctx->addr && + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && (now - state->last_msg_timestamp <= K_SECONDS(6))) { - return true; + return; } - state->is_optional_para_available = 0x01; - switch (buf->om_len) { case 0x00: /* No optional fields are available */ - state->tt = default_tt; - state->delay = 0; - state->is_optional_para_available = 0x00; + tt = default_tt; + delay = 0; break; case 0x02: /* Optional fields are available */ - state->tt = net_buf_simple_pull_u8(buf); - state->delay = net_buf_simple_pull_u8(buf); + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); break; default: - return false; + return; } - enable_transition = DISABLE_TRANSITION; + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); state->last_tid = tid; - state->last_tx_addr = ctx->addr; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; state->last_msg_timestamp = now; if (temp < state->temp_range_min) { @@ -1659,45 +2421,105 @@ static bool light_ctl_temp_setunack(struct bt_mesh_model *model, state->target_temp = temp; state->target_delta_uv = delta_uv; - light_ctl_temp_tt_values(state); - - if (state->tt_counter_temp == 0) { - state->temp = temp; - state->delta_uv = delta_uv; + if (state->target_temp != state->temp || + state->target_delta_uv != state->delta_uv) { + light_ctl_temp_tt_values(state, tt, delay); + } else { + light_ctl_temp_publish(model); + return; } + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->temp = state->target_temp; + state->delta_uv = state->target_delta_uv; + } + + state->transition->just_started = true; + light_ctl_temp_publish(model); light_ctl_temp_handler(state); - - if (model->pub->addr != BT_MESH_ADDR_UNASSIGNED) { - int err; - - bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x66)); - net_buf_simple_add_le16(msg, state->temp); - net_buf_simple_add_le16(msg, state->delta_uv); - - err = bt_mesh_model_publish(model); - if (err) { - printk("bt_mesh_model_publish err %d\n", err); - } - } - - return true; -} - -static void light_ctl_temp_set_unack(struct bt_mesh_model *model, - struct bt_mesh_msg_ctx *ctx, - struct os_mbuf *buf) -{ - light_ctl_temp_setunack(model, ctx, buf); } static void light_ctl_temp_set(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx, struct os_mbuf *buf) { - if (light_ctl_temp_setunack(model, ctx, buf) == true) { - light_ctl_temp_get(model, ctx, buf); + u8_t tid, tt, delay; + s16_t delta_uv; + u16_t temp; + s64_t now; + struct light_ctl_state *state = model->user_data; + + temp = net_buf_simple_pull_le16(buf); + delta_uv = (s16_t) net_buf_simple_pull_le16(buf); + tid = net_buf_simple_pull_u8(buf); + + if (temp < TEMP_MIN || temp > TEMP_MAX) { + return; } + + now = k_uptime_get(); + if (state->last_tid == tid && + state->last_src_addr == ctx->addr && + state->last_dst_addr == ctx->recv_dst && + (now - state->last_msg_timestamp <= K_SECONDS(6))) { + light_ctl_temp_get(model, ctx, buf); + return; + } + + switch (buf->om_len) { + case 0x00: /* No optional fields are available */ + tt = default_tt; + delay = 0; + break; + case 0x02: /* Optional fields are available */ + tt = net_buf_simple_pull_u8(buf); + if ((tt & 0x3F) == 0x3F) { + return; + } + + delay = net_buf_simple_pull_u8(buf); + break; + default: + return; + } + + *ptr_counter = 0; + ble_npl_callout_stop(ptr_timer); + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + + if (temp < state->temp_range_min) { + temp = state->temp_range_min; + } else if (temp > state->temp_range_max) { + temp = state->temp_range_max; + } + + state->target_temp = temp; + state->target_delta_uv = delta_uv; + + if (state->target_temp != state->temp || + state->target_delta_uv != state->delta_uv) { + light_ctl_temp_tt_values(state, tt, delay); + } else { + light_ctl_temp_get(model, ctx, buf); + light_ctl_temp_publish(model); + return; + } + + /* For Instantaneous Transition */ + if (state->transition->counter == 0) { + state->temp = state->target_temp; + state->delta_uv = state->target_delta_uv; + } + + state->transition->just_started = true; + light_ctl_temp_get(model, ctx, buf); + light_ctl_temp_publish(model); + light_ctl_temp_handler(state); } /* message handlers (End) */ @@ -1723,8 +2545,8 @@ static const struct bt_mesh_model_op gen_level_srv_op[] = { { BT_MESH_MODEL_OP_2(0x82, 0x07), 3, gen_level_set_unack }, { BT_MESH_MODEL_OP_2(0x82, 0x09), 5, gen_delta_set }, { BT_MESH_MODEL_OP_2(0x82, 0x0A), 5, gen_delta_set_unack }, - { BT_MESH_MODEL_OP_2(0x82, 0x0B), 5, gen_move_set }, - { BT_MESH_MODEL_OP_2(0x82, 0x0C), 5, gen_move_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x0B), 3, gen_move_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x0C), 3, gen_move_set_unack }, BT_MESH_MODEL_OP_END, }; @@ -1805,8 +2627,8 @@ static const struct bt_mesh_model_op light_lightness_cli_op[] = { /* Mapping of message handlers for Light CTL Server (0x1303) */ static const struct bt_mesh_model_op light_ctl_srv_op[] = { { BT_MESH_MODEL_OP_2(0x82, 0x5D), 0, light_ctl_get }, - { BT_MESH_MODEL_OP_2(0x82, 0x5E), 5, light_ctl_set }, - { BT_MESH_MODEL_OP_2(0x82, 0x5F), 5, light_ctl_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x5E), 7, light_ctl_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x5F), 7, light_ctl_set_unack }, { BT_MESH_MODEL_OP_2(0x82, 0x62), 0, light_ctl_temp_range_get }, { BT_MESH_MODEL_OP_2(0x82, 0x67), 0, light_ctl_default_get }, BT_MESH_MODEL_OP_END, @@ -1840,10 +2662,10 @@ static const struct bt_mesh_model_op light_ctl_temp_srv_op[] = { /* Mapping of message handlers for Vendor (0x4321) */ static const struct bt_mesh_model_op vnd_ops[] = { - { BT_MESH_MODEL_OP_3(0x00, CID_RUNTIME), 0, vnd_get }, - { BT_MESH_MODEL_OP_3(0x01, CID_RUNTIME), 3, vnd_set }, - { BT_MESH_MODEL_OP_3(0x02, CID_RUNTIME), 3, vnd_set_unack }, - { BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME), 6, vnd_status }, + { BT_MESH_MODEL_OP_3(0x01, CID_RUNTIME), 0, vnd_get }, + { BT_MESH_MODEL_OP_3(0x02, CID_RUNTIME), 3, vnd_set }, + { BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME), 3, vnd_set_unack }, + { BT_MESH_MODEL_OP_3(0x04, CID_RUNTIME), 6, vnd_status }, BT_MESH_MODEL_OP_END, }; @@ -1913,13 +2735,6 @@ struct bt_mesh_model vnd_models[] = { }; struct bt_mesh_model s0_models[] = { - BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, - gen_onoff_srv_op, &gen_onoff_srv_pub_s0, - &gen_onoff_srv_s0_user_data), - BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, - gen_onoff_cli_op, &gen_onoff_cli_pub_s0, - NULL), - BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_srv_op, &gen_level_srv_pub_s0, &gen_level_srv_s0_user_data), @@ -1942,3 +2757,4 @@ const struct bt_mesh_comp comp = { .elem = elements, .elem_count = ARRAY_SIZE(elements), }; + diff --git a/apps/blemesh_models_example_2/src/device_composition.h b/apps/blemesh_models_example_2/src/device_composition.h index d91b3e525..596e74c16 100644 --- a/apps/blemesh_models_example_2/src/device_composition.h +++ b/apps/blemesh_models_example_2/src/device_composition.h @@ -26,38 +26,18 @@ #define CANNOT_SET_RANGE_MIN 0x01 #define CANNOT_SET_RANGE_MAX 0x02 -enum lightness { - ONPOWERUP = 0x01, - ONOFF, - LEVEL, - DELTA_LEVEL, - ACTUAL, - LINEAR, - CTL, - IGNORE -}; - -enum temperature { - ONOFF_TEMP = 0x01, - LEVEL_TEMP, - CTL_TEMP, - IGNORE_TEMP -}; - struct generic_onoff_state { u8_t onoff; u8_t target_onoff; u8_t last_tid; - u16_t last_tx_addr; + u16_t last_src_addr; + u16_t last_dst_addr; s64_t last_msg_timestamp; - u8_t tt; - u32_t cal_tt; - u8_t delay; - u32_t tt_counter; + s32_t tt_delta; - u8_t is_optional_para_available; + struct transition *transition; }; struct generic_level_state { @@ -68,24 +48,17 @@ struct generic_level_state { s32_t last_delta; u8_t last_tid; - u16_t last_tx_addr; + u16_t last_src_addr; + u16_t last_dst_addr; s64_t last_msg_timestamp; s32_t tt_delta; - u8_t tt; - u32_t cal_tt; - u8_t delay; - u32_t tt_counter; - u32_t tt_counter_delta; - u32_t tt_counter_move; - u8_t is_optional_para_available; + struct transition *transition; }; struct generic_onpowerup_state { u8_t onpowerup; - u8_t last_tid; - u16_t last_tx_addr; }; struct gen_def_trans_time_state { @@ -96,7 +69,8 @@ struct vendor_state { int current; u32_t response; u8_t last_tid; - u16_t last_tx_addr; + u16_t last_src_addr; + u16_t last_dst_addr; s64_t last_msg_timestamp; }; @@ -113,20 +87,17 @@ struct light_lightness_state { u8_t status_code; u16_t light_range_min; u16_t light_range_max; + u32_t lightness_range; u8_t last_tid; - u16_t last_tx_addr; + u16_t last_src_addr; + u16_t last_dst_addr; s64_t last_msg_timestamp; s32_t tt_delta_actual; s32_t tt_delta_linear; - u8_t tt; - u32_t cal_tt; - u8_t delay; - u32_t tt_counter_actual; - u32_t tt_counter_linear; - u8_t is_optional_para_available; + struct transition *transition; }; struct light_ctl_state { @@ -142,27 +113,25 @@ struct light_ctl_state { u8_t status_code; u16_t temp_range_min; u16_t temp_range_max; + u32_t temperature_range; u16_t lightness_def; u16_t temp_def; + u32_t lightness_temp_def; s16_t delta_uv_def; - u16_t temp_last; + u32_t lightness_temp_last; u8_t last_tid; - u16_t last_tx_addr; + u16_t last_src_addr; + u16_t last_dst_addr; s64_t last_msg_timestamp; - s32_t tt_lightness_delta; - s32_t tt_temp_delta; - s32_t tt_duv_delta; - u8_t tt; - u32_t cal_tt; - u8_t delay; - u32_t tt_counter; - u32_t tt_counter_temp; + s32_t tt_delta_lightness; + s32_t tt_delta_temp; + s32_t tt_delta_duv; - u8_t is_optional_para_available; + struct transition *transition; }; extern struct generic_onoff_state gen_onoff_srv_root_user_data; @@ -179,4 +148,11 @@ extern struct bt_mesh_model s0_models[]; extern const struct bt_mesh_comp comp; +void gen_onoff_publish(struct bt_mesh_model *model); +void gen_level_publish(struct bt_mesh_model *model); +void light_lightness_publish(struct bt_mesh_model *model); +void light_lightness_linear_publish(struct bt_mesh_model *model); +void light_ctl_publish(struct bt_mesh_model *model); +void light_ctl_temp_publish(struct bt_mesh_model *model); + #endif diff --git a/apps/blemesh_models_example_2/src/main.c b/apps/blemesh_models_example_2/src/main.c index 10fc8dae8..62dfd3a99 100644 --- a/apps/blemesh_models_example_2/src/main.c +++ b/apps/blemesh_models_example_2/src/main.c @@ -5,88 +5,32 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "bsp/bsp.h" + #include "console/console.h" #include "hal/hal_gpio.h" +#include "mesh/mesh.h" + +#include "app_gpio.h" +#include "storage.h" -#include "common.h" #include "ble_mesh.h" #include "device_composition.h" +#include "no_transition_work_handler.h" #include "publisher.h" #include "state_binding.h" #include "transition.h" -int button_device[] = { - BUTTON_1, - BUTTON_2, - BUTTON_3, - BUTTON_4, -}; +static bool reset; -int led_device[] = { - LED_1, - LED_2, - LED_3, - LED_4, -}; - -static struct ble_npl_callout button_work; - -static void button_pressed(struct os_event *ev) +static void light_default_var_init(void) { - k_work_submit(&button_work); -} + gen_def_trans_time_srv_user_data.tt = 0x00; -static struct os_event button_event; - -static void -gpio_irq_handler(void *arg) -{ - button_event.ev_arg = arg; - os_eventq_put(os_eventq_dflt_get(), &button_event); -} - -static void gpio_init(void) -{ - /* LEDs configiuratin & setting */ - - hal_gpio_init_out(led_device[0], 1); - hal_gpio_init_out(led_device[1], 1); - hal_gpio_init_out(led_device[2], 1); - hal_gpio_init_out(led_device[3], 1); - - /* Buttons configiuratin & setting */ - - k_work_init(&button_work, publish); - - button_event.ev_cb = button_pressed; - - hal_gpio_irq_init(button_device[0], gpio_irq_handler, NULL, - HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); - hal_gpio_irq_enable(button_device[0]); - - hal_gpio_irq_init(button_device[1], gpio_irq_handler, NULL, - HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); - hal_gpio_irq_enable(button_device[1]); - - hal_gpio_irq_init(button_device[2], gpio_irq_handler, NULL, - HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); - hal_gpio_irq_enable(button_device[2]); - - hal_gpio_irq_init(button_device[3], gpio_irq_handler, NULL, - HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP); - hal_gpio_irq_enable(button_device[3]); -} - -void light_default_status_init(void) -{ - /* Assume vaules are retrived from Persistence Storage (Start). - * These had saved by respective Setup Servers. - */ gen_power_onoff_srv_user_data.onpowerup = STATE_DEFAULT; light_lightness_srv_user_data.light_range_min = LIGHTNESS_MIN; light_lightness_srv_user_data.light_range_max = LIGHTNESS_MAX; + light_lightness_srv_user_data.last = LIGHTNESS_MAX; light_lightness_srv_user_data.def = LIGHTNESS_MAX; /* Following 2 values are as per specification */ @@ -94,50 +38,89 @@ void light_default_status_init(void) light_ctl_srv_user_data.temp_range_max = TEMP_MAX; light_ctl_srv_user_data.temp_def = TEMP_MIN; - /* (End) */ - /* Assume following values are retrived from Persistence - * Storage (Start). - * These values had saved before power down. - */ - light_lightness_srv_user_data.last = LIGHTNESS_MAX; - light_ctl_srv_user_data.temp_last = TEMP_MIN; - /* (End) */ + light_ctl_srv_user_data.lightness_temp_last = + (u32_t) ((LIGHTNESS_MAX << 16) | TEMP_MIN); +} + +static void light_default_status_init(void) +{ + u16_t lightness; + + lightness = (u16_t) (light_ctl_srv_user_data.lightness_temp_last >> 16); + + if (lightness) { + gen_onoff_srv_root_user_data.onoff = STATE_ON; + } else { + gen_onoff_srv_root_user_data.onoff = STATE_OFF; + } + + /* Retrieve Default Lightness & Temperature Values */ + + if (light_ctl_srv_user_data.lightness_temp_def) { + light_ctl_srv_user_data.lightness_def = (u16_t) + (light_ctl_srv_user_data.lightness_temp_def >> 16); + + light_ctl_srv_user_data.temp_def = (u16_t) + (light_ctl_srv_user_data.lightness_temp_def); + } + + light_lightness_srv_user_data.def = + light_ctl_srv_user_data.lightness_def; light_ctl_srv_user_data.temp = light_ctl_srv_user_data.temp_def; - if (gen_power_onoff_srv_user_data.onpowerup == STATE_OFF) { - gen_onoff_srv_root_user_data.onoff = STATE_OFF; - state_binding(ONOFF, ONOFF_TEMP); - } else if (gen_power_onoff_srv_user_data.onpowerup == STATE_DEFAULT) { - gen_onoff_srv_root_user_data.onoff = STATE_ON; - state_binding(ONOFF, ONOFF_TEMP); - } else if (gen_power_onoff_srv_user_data.onpowerup == STATE_RESTORE) { - /* Assume following values is retrived from Persistence - * Storage (Start). - * This value had saved before power down. - */ - gen_onoff_srv_root_user_data.onoff = STATE_ON; - /* (End) */ + /* Retrieve Range of Lightness & Temperature */ - light_ctl_srv_user_data.temp = - light_ctl_srv_user_data.temp_last; + if (light_lightness_srv_user_data.lightness_range) { + light_lightness_srv_user_data.light_range_max = (u16_t) + (light_lightness_srv_user_data.lightness_range >> 16); - state_binding(ONPOWERUP, ONOFF_TEMP); + light_lightness_srv_user_data.light_range_min = (u16_t) + (light_lightness_srv_user_data.lightness_range); } + + if (light_ctl_srv_user_data.temperature_range) { + light_ctl_srv_user_data.temp_range_max = (u16_t) + (light_ctl_srv_user_data.temperature_range >> 16); + + light_ctl_srv_user_data.temp_range_min = (u16_t) + (light_ctl_srv_user_data.temperature_range); + } + + switch (gen_power_onoff_srv_user_data.onpowerup) { + case STATE_OFF: + gen_onoff_srv_root_user_data.onoff = STATE_OFF; + state_binding(ONOFF, ONOFF_TEMP); + break; + case STATE_DEFAULT: + gen_onoff_srv_root_user_data.onoff = STATE_ON; + state_binding(ONOFF, ONOFF_TEMP); + break; + case STATE_RESTORE: + light_lightness_srv_user_data.last = (u16_t) + (light_ctl_srv_user_data.lightness_temp_last >> 16); + + light_ctl_srv_user_data.temp = + (u16_t) (light_ctl_srv_user_data.lightness_temp_last); + + state_binding(ONPOWERUP, ONOFF_TEMP); + break; + } + + default_tt = gen_def_trans_time_srv_user_data.tt; } void update_light_state(void) { u8_t power, color; - power = 100 * ((float) light_lightness_srv_user_data.actual / 65535); - color = 100 * ((float) (gen_level_srv_s0_user_data.level + 32768) - / 65535); + power = 100 * ((float) lightness / 65535); + color = 100 * ((float) (temperature + 32768) / 65535); printk("power-> %d, color-> %d\n", power, color); - if (gen_onoff_srv_root_user_data.onoff == STATE_ON) { + if (lightness) { /* LED1 On */ hal_gpio_write(led_device[0], 0); } else { @@ -160,6 +143,56 @@ void update_light_state(void) /* LED4 Off */ hal_gpio_write(led_device[3], 1); } + + if (*ptr_counter == 0 || reset == false) { + reset = true; + k_work_submit(&no_transition_work); + } +} + +static void short_time_multireset_bt_mesh_unprovisioning(void) +{ + if (reset_counter >= 4) { + reset_counter = 0; + printk("BT Mesh reset\n"); + bt_mesh_reset(); + } else { + printk("Reset Counter -> %d\n", reset_counter); + reset_counter++; + } + + save_on_flash(RESET_COUNTER); +} + +static void reset_counter_timer_handler(struct ble_npl_event *dummy) +{ + reset_counter = 0; + save_on_flash(RESET_COUNTER); + printk("Reset Counter set to Zero\n"); +} + +struct ble_npl_callout reset_counter_timer; + +static void init_timers(void) +{ + + ble_npl_callout_init(&reset_counter_timer, ble_npl_eventq_dflt_get(), + reset_counter_timer_handler, NULL); + ble_npl_callout_reset(&reset_counter_timer, + ble_npl_time_ms_to_ticks32(K_MSEC(7000))); + + no_transition_work_init(); +} + +void bt_initialized(void) +{ + light_default_status_init(); + + update_light_state(); + + randomize_publishers_TID(); + + short_time_multireset_bt_mesh_unprovisioning(); } int main(void) @@ -171,16 +204,18 @@ int main(void) /* Initialize OS */ sysinit(); - light_default_status_init(); + light_default_var_init(); + + app_gpio_init(); + + init_timers(); transition_timers_init(); - gpio_init(); - - update_light_state(); - init_pub(); + ps_settings_init(); + printk("Initializing...\n"); /* Initialize the NimBLE host configuration. */ @@ -188,8 +223,6 @@ int main(void) ble_hs_cfg.sync_cb = blemesh_on_sync; ble_hs_cfg.store_status_cb = ble_store_util_status_rr; - randomize_publishers_TID(); - while (1) { os_eventq_run(os_eventq_dflt_get()); } diff --git a/apps/blemesh_models_example_2/src/no_transition_work_handler.c b/apps/blemesh_models_example_2/src/no_transition_work_handler.c new file mode 100644 index 000000000..9e0fceab5 --- /dev/null +++ b/apps/blemesh_models_example_2/src/no_transition_work_handler.c @@ -0,0 +1,70 @@ +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "ble_mesh.h" +#include "device_composition.h" + +#include "storage.h" + +static void unsolicitedly_publish_states_work_handler(struct ble_npl_event *work) +{ + gen_onoff_publish(&root_models[2]); + gen_level_publish(&root_models[4]); + light_lightness_publish(&root_models[11]); + light_lightness_linear_publish(&root_models[11]); + light_ctl_publish(&root_models[14]); + + gen_level_publish(&s0_models[0]); + light_ctl_temp_publish(&s0_models[2]); +} + +struct ble_npl_callout unsolicitedly_publish_states_work; + +static void unsolicitedly_publish_states_timer_handler(struct ble_npl_event *dummy) +{ + k_work_submit(&unsolicitedly_publish_states_work); +} + +struct ble_npl_callout unsolicitedly_publish_states_timer; + +static void save_lightness_temp_last_values_timer_handler(struct ble_npl_event *dummy) +{ + save_on_flash(LIGHTNESS_TEMP_LAST_STATE); +} + +struct ble_npl_callout save_lightness_temp_last_values_timer; + +static void no_transition_work_handler(struct ble_npl_event *work) +{ + ble_npl_callout_reset(&unsolicitedly_publish_states_timer, + ble_npl_time_ms_to_ticks32(K_MSEC(5000))); + + /* If Lightness & Temperature values remains stable for + * 10 Seconds then & then only get stored on SoC flash. + */ + if (gen_power_onoff_srv_user_data.onpowerup == STATE_RESTORE) { + ble_npl_callout_reset(&save_lightness_temp_last_values_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(10000))); + } +} + +struct ble_npl_callout no_transition_work; + +void no_transition_work_init(void) +{ + ble_npl_callout_init(&no_transition_work, ble_npl_eventq_dflt_get(), + no_transition_work_handler, NULL); + ble_npl_callout_init(&save_lightness_temp_last_values_timer, + ble_npl_eventq_dflt_get(), + save_lightness_temp_last_values_timer_handler, + NULL); + ble_npl_callout_init(&unsolicitedly_publish_states_work, ble_npl_eventq_dflt_get(), + unsolicitedly_publish_states_work_handler, NULL); + ble_npl_callout_init(&unsolicitedly_publish_states_timer, ble_npl_eventq_dflt_get(), + unsolicitedly_publish_states_timer_handler, NULL); +} diff --git a/apps/blemesh_models_example_2/src/no_transition_work_handler.h b/apps/blemesh_models_example_2/src/no_transition_work_handler.h new file mode 100644 index 000000000..2b9037980 --- /dev/null +++ b/apps/blemesh_models_example_2/src/no_transition_work_handler.h @@ -0,0 +1,15 @@ +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _NO_TRANSITION_WORK_HANDLER_H +#define _NO_TRANSITION_WORK_HANDLER_H + +extern struct ble_npl_callout no_transition_work; + +void no_transition_work_init(void); + +#endif diff --git a/apps/blemesh_models_example_2/src/publisher.c b/apps/blemesh_models_example_2/src/publisher.c index 9e0f47730..bdb8692cc 100644 --- a/apps/blemesh_models_example_2/src/publisher.c +++ b/apps/blemesh_models_example_2/src/publisher.c @@ -8,10 +8,11 @@ #include "console/console.h" #include "hal/hal_gpio.h" -#include "common.h" +#include "app_gpio.h" + #include "ble_mesh.h" -#include "publisher.h" #include "device_composition.h" +#include "publisher.h" #define ONOFF #define GENERIC_LEVEL @@ -20,7 +21,7 @@ static bool is_randomization_of_TIDs_done; -#if defined(ONOFF) +#if (defined(ONOFF) || defined(ONOFF_TT)) static u8_t tid_onoff; #elif defined(VND_MODEL_TEST) static u8_t tid_vnd; @@ -30,7 +31,7 @@ static u8_t tid_level; void randomize_publishers_TID(void) { -#if defined(ONOFF) +#if (defined(ONOFF) || defined(ONOFF_TT)) bt_rand(&tid_onoff, sizeof(tid_onoff)); #elif defined(VND_MODEL_TEST) bt_rand(&tid_vnd, sizeof(tid_vnd)); @@ -71,7 +72,7 @@ void publish(struct ble_npl_event *work) err = bt_mesh_model_publish(&root_models[3]); #elif defined(VND_MODEL_TEST) bt_mesh_model_msg_init(vnd_models[0].pub->msg, - BT_MESH_MODEL_OP_3(0x02, CID_RUNTIME)); + BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME)); net_buf_simple_add_le16(vnd_models[0].pub->msg, 0x0001); net_buf_simple_add_u8(vnd_models[0].pub->msg, tid_vnd++); err = bt_mesh_model_publish(&vnd_models[0]); @@ -94,7 +95,7 @@ void publish(struct ble_npl_event *work) err = bt_mesh_model_publish(&root_models[3]); #elif defined(VND_MODEL_TEST) bt_mesh_model_msg_init(vnd_models[0].pub->msg, - BT_MESH_MODEL_OP_3(0x02, CID_RUNTIME)); + BT_MESH_MODEL_OP_3(0x03, CID_RUNTIME)); net_buf_simple_add_le16(vnd_models[0].pub->msg, 0x0000); net_buf_simple_add_u8(vnd_models[0].pub->msg, tid_vnd++); err = bt_mesh_model_publish(&vnd_models[0]); @@ -107,6 +108,10 @@ void publish(struct ble_npl_event *work) net_buf_simple_add_le16(root_models[5].pub->msg, LEVEL_S25); net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++); err = bt_mesh_model_publish(&root_models[5]); +#elif defined(ONOFF_GET) + bt_mesh_model_msg_init(root_models[3].pub->msg, + BT_MESH_MODEL_OP_GEN_ONOFF_GET); + err = bt_mesh_model_publish(&root_models[3]); #elif defined(GENERIC_DELTA_LEVEL) bt_mesh_model_msg_init(root_models[5].pub->msg, BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK); @@ -239,3 +244,4 @@ void publish(struct ble_npl_event *work) printk("bt_mesh_model_publish: err: %d\n", err); } } + diff --git a/apps/blemesh_models_example_2/src/state_binding.c b/apps/blemesh_models_example_2/src/state_binding.c index bffe38bae..715ba6097 100644 --- a/apps/blemesh_models_example_2/src/state_binding.c +++ b/apps/blemesh_models_example_2/src/state_binding.c @@ -7,9 +7,14 @@ #include -#include "common.h" #include "ble_mesh.h" #include "device_composition.h" +#include "state_binding.h" +#include "transition.h" + + +u16_t lightness, target_lightness; +s16_t temperature, target_temperature; static s32_t ceiling(float num) { @@ -23,161 +28,262 @@ static s32_t ceiling(float num) return inum + 1; } -static bool constrain_light_actual_state(u16_t var) +u16_t actual_to_linear(u16_t val) { - bool is_value_within_range; + float tmp; - is_value_within_range = false; + tmp = ((float) val / 65535); + return (u16_t) ceiling(65535 * tmp * tmp); +} + +u16_t linear_to_actual(u16_t val) +{ + return (u16_t) (65535 * sqrt(((float) val / 65535))); +} + +static void constrain_lightness(u16_t var) +{ + if (var > 0 && var < light_lightness_srv_user_data.light_range_min) { + var = light_lightness_srv_user_data.light_range_min; + } else if (var > light_lightness_srv_user_data.light_range_max) { + var = light_lightness_srv_user_data.light_range_max; + } + + lightness = var; +} + +static void constrain_lightness2(u16_t var) +{ + /* This is as per Mesh Model Specification 3.3.2.2.3 */ + if (var > 0 && var < light_lightness_srv_user_data.light_range_min) { + if (gen_level_srv_root_user_data.last_delta < 0) { + var = 0U; + } else { + var = light_lightness_srv_user_data.light_range_min; + } + } else if (var > light_lightness_srv_user_data.light_range_max) { + var = light_lightness_srv_user_data.light_range_max; + } + + lightness = var; +} + +static void constrain_target_lightness(u16_t var) +{ if (var > 0 && var < light_lightness_srv_user_data.light_range_min) { var = light_lightness_srv_user_data.light_range_min; } else if (var > light_lightness_srv_user_data.light_range_max) { var = light_lightness_srv_user_data.light_range_max; - } else { - is_value_within_range = true; } - light_lightness_srv_user_data.actual = var; - - return is_value_within_range; + target_lightness = var; } -static void update_gen_onoff_state(void) +static s16_t light_ctl_temp_to_level(u16_t temp) { - if (light_lightness_srv_user_data.actual == 0) { - gen_onoff_srv_root_user_data.onoff = STATE_OFF; - } else { - gen_onoff_srv_root_user_data.onoff = STATE_ON; - } -} - -void state_binding(u8_t lightness, u8_t temperature) -{ - bool is_value_within_range; - u16_t tmp16; float tmp; - switch (temperature) { - case ONOFF_TEMP:/* Temp. update as per Light CTL temp. default state */ - case CTL_TEMP: /* Temp. update as per Light CTL temp. state */ - /* Mesh Model Specification 6.1.3.1.1 2nd formula start */ - tmp = (light_ctl_srv_user_data.temp - - light_ctl_srv_user_data.temp_range_min) * 65535; - tmp = tmp / (light_ctl_srv_user_data.temp_range_max - - light_ctl_srv_user_data.temp_range_min); - gen_level_srv_s0_user_data.level = tmp - 32768; - /* 6.1.3.1.1 2nd formula end */ + /* Mesh Model Specification 6.1.3.1.1 2nd formula start */ + + tmp = (temp - light_ctl_srv_user_data.temp_range_min) * 65535; + + tmp = tmp / (light_ctl_srv_user_data.temp_range_max - + light_ctl_srv_user_data.temp_range_min); + + return (s16_t) (tmp - 32768); + + /* 6.1.3.1.1 2nd formula end */ +} + +static u16_t level_to_light_ctl_temp(s16_t level) +{ + u16_t tmp; + float diff; + + /* Mesh Model Specification 6.1.3.1.1 1st formula start */ + diff = (float) (light_ctl_srv_user_data.temp_range_max - + light_ctl_srv_user_data.temp_range_min) / 65535; + + + tmp = (u16_t) ((level + 32768) * diff); + + return (light_ctl_srv_user_data.temp_range_min + tmp); + + /* 6.1.3.1.1 1st formula end */ +} + +void state_binding(u8_t light, u8_t temp) +{ + switch (temp) { + case ONOFF_TEMP: + case CTL_TEMP: + temperature = + light_ctl_temp_to_level(light_ctl_srv_user_data.temp); + + gen_level_srv_s0_user_data.level = temperature; break; - case LEVEL_TEMP:/* Temp. update as per Generic Level (s0) state */ - /* Mesh Model Specification 6.1.3.1.1 1st formula start */ - tmp = (float) (light_ctl_srv_user_data.temp_range_max - - light_ctl_srv_user_data.temp_range_min) / 65535; - tmp = (gen_level_srv_s0_user_data.level + 32768) * tmp; + case LEVEL_TEMP: + temperature = gen_level_srv_s0_user_data.level; light_ctl_srv_user_data.temp = - light_ctl_srv_user_data.temp_range_min + tmp; - /* 6.1.3.1.1 1st formula end */ + level_to_light_ctl_temp(temperature); break; default: break; } - tmp16 = 0; - - switch (lightness) { - case ONPOWERUP: /* Lightness update as per Generic OnPowerUp state */ + switch (light) { + case ONPOWERUP: if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) { - light_lightness_srv_user_data.actual = 0; - light_lightness_srv_user_data.linear = 0; - gen_level_srv_root_user_data.level = -32768; - light_ctl_srv_user_data.lightness = 0; - return; + lightness = 0U; } else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) { - light_lightness_srv_user_data.actual = - light_lightness_srv_user_data.last; + lightness = light_lightness_srv_user_data.last; } - break; - case ONOFF: /* Lightness update as per Generic OnOff (root) state */ + case ONOFF: if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) { - light_lightness_srv_user_data.actual = 0; - light_lightness_srv_user_data.linear = 0; - gen_level_srv_root_user_data.level = -32768; - light_ctl_srv_user_data.lightness = 0; - return; + lightness = 0U; } else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) { if (light_lightness_srv_user_data.def == 0) { - light_lightness_srv_user_data.actual = - light_lightness_srv_user_data.last; + lightness = light_lightness_srv_user_data.last; } else { - light_lightness_srv_user_data.actual = - light_lightness_srv_user_data.def; + lightness = light_lightness_srv_user_data.def; } } + break; + case LEVEL: + lightness = gen_level_srv_root_user_data.level + 32768; + break; + case DELTA_LEVEL: + lightness = gen_level_srv_root_user_data.level + 32768; + constrain_lightness2(lightness); + goto jump; + case ACTUAL: + lightness = light_lightness_srv_user_data.actual; + break; + case LINEAR: + lightness = + linear_to_actual(light_lightness_srv_user_data.linear); + break; + case CTL: + lightness = light_ctl_srv_user_data.lightness; + break; + default: + break; + } - break; - case LEVEL: /* Lightness update as per Generic Level (root) state */ - tmp16 = gen_level_srv_root_user_data.level + 32768; - constrain_light_actual_state(tmp16); - update_gen_onoff_state(); - break; - case DELTA_LEVEL: /* Lightness update as per Gen. Level (root) state */ - /* This is as per Mesh Model Specification 3.3.2.2.3 */ - tmp16 = gen_level_srv_root_user_data.level + 32768; - if (tmp16 > 0 && - tmp16 < light_lightness_srv_user_data.light_range_min) { - if (gen_level_srv_root_user_data.last_delta < 0) { - tmp16 = 0; + constrain_lightness(lightness); + +jump: + if (lightness != 0) { + light_lightness_srv_user_data.last = lightness; + } + + if (lightness) { + gen_onoff_srv_root_user_data.onoff = STATE_ON; + } else { + gen_onoff_srv_root_user_data.onoff = STATE_OFF; + } + + gen_level_srv_root_user_data.level = lightness - 32768; + light_lightness_srv_user_data.actual = lightness; + light_lightness_srv_user_data.linear = actual_to_linear(lightness); + light_ctl_srv_user_data.lightness = lightness; +} + +void calculate_lightness_target_values(u8_t type) +{ + bool set_light_ctl_temp_target_value; + u16_t tmp; + + set_light_ctl_temp_target_value = true; + + switch (type) { + case ONOFF: + if (gen_onoff_srv_root_user_data.target_onoff == 0) { + tmp = 0U; + } else { + if (light_lightness_srv_user_data.def == 0) { + tmp = light_lightness_srv_user_data.last; } else { - tmp16 = - light_lightness_srv_user_data.light_range_min; + tmp = light_lightness_srv_user_data.def; } - } else if (tmp16 > - light_lightness_srv_user_data.light_range_max) { - tmp16 = - light_lightness_srv_user_data.light_range_max; } - - light_lightness_srv_user_data.actual = tmp16; - - update_gen_onoff_state(); break; - case ACTUAL: /* Lightness update as per Light Lightness Actual state */ - update_gen_onoff_state(); + case LEVEL: + tmp = gen_level_srv_root_user_data.target_level + 32768; break; - case LINEAR: /* Lightness update as per Light Lightness Linear state */ - tmp16 = (u16_t) 65535 * - sqrt(((float) light_lightness_srv_user_data.linear / - 65535)); - - is_value_within_range = constrain_light_actual_state(tmp16); - update_gen_onoff_state(); - - if (is_value_within_range) { - goto ignore_linear_update_others; - } - + case ACTUAL: + tmp = light_lightness_srv_user_data.target_actual; break; - case CTL: /* Lightness update as per Light CTL Lightness state */ - constrain_light_actual_state(light_ctl_srv_user_data.lightness); - update_gen_onoff_state(); + case LINEAR: + tmp = linear_to_actual(light_lightness_srv_user_data.target_linear); + break; + case CTL: + set_light_ctl_temp_target_value = false; + + tmp = light_ctl_srv_user_data.target_lightness; + + target_temperature = light_ctl_temp_to_level(light_ctl_srv_user_data.target_temp); + gen_level_srv_s0_user_data.target_level = target_temperature; break; default: return; } - tmp = ((float) light_lightness_srv_user_data.actual / 65535); - light_lightness_srv_user_data.linear = ceiling(65535 * tmp * tmp); + constrain_target_lightness(tmp); -ignore_linear_update_others: - if (light_lightness_srv_user_data.actual != 0) { - light_lightness_srv_user_data.last = - light_lightness_srv_user_data.actual; + if (target_lightness) { + gen_onoff_srv_root_user_data.target_onoff = STATE_ON; + } else { + gen_onoff_srv_root_user_data.target_onoff = STATE_OFF; } - gen_level_srv_root_user_data.level = - light_lightness_srv_user_data.actual - 32768; + gen_level_srv_root_user_data.target_level = target_lightness - 32768; - light_ctl_srv_user_data.lightness = - light_lightness_srv_user_data.actual; + light_lightness_srv_user_data.target_actual = target_lightness; + + light_lightness_srv_user_data.target_linear = + actual_to_linear(target_lightness); + + light_ctl_srv_user_data.target_lightness = target_lightness; + + if (set_light_ctl_temp_target_value) { + target_temperature = light_ctl_srv_user_data.temp; + light_ctl_srv_user_data.target_temp = target_temperature; + } } + +void calculate_temp_target_values(u8_t type) +{ + bool set_light_ctl_delta_uv_target_value; + + set_light_ctl_delta_uv_target_value = true; + + switch (type) { + case LEVEL_TEMP: + target_temperature = gen_level_srv_s0_user_data.target_level; + light_ctl_srv_user_data.target_temp = + level_to_light_ctl_temp(target_temperature); + break; + case CTL_TEMP: + set_light_ctl_delta_uv_target_value = false; + + target_temperature = light_ctl_temp_to_level(light_ctl_srv_user_data.target_temp); + gen_level_srv_s0_user_data.target_level = target_temperature; + break; + default: + return; + } + + target_lightness = light_ctl_srv_user_data.lightness; + light_ctl_srv_user_data.target_lightness = target_lightness; + + if (set_light_ctl_delta_uv_target_value) { + + light_ctl_srv_user_data.target_delta_uv = + light_ctl_srv_user_data.delta_uv; + } +} + diff --git a/apps/blemesh_models_example_2/src/state_binding.h b/apps/blemesh_models_example_2/src/state_binding.h index e7dd1087d..014850061 100644 --- a/apps/blemesh_models_example_2/src/state_binding.h +++ b/apps/blemesh_models_example_2/src/state_binding.h @@ -8,6 +8,27 @@ #ifndef _STATE_BINDING_H #define _STATE_BINDING_H +enum state_binding { + ONPOWERUP = 0x01, + ONOFF, + LEVEL, + DELTA_LEVEL, + ACTUAL, + LINEAR, + CTL, + IGNORE, + + ONOFF_TEMP, + LEVEL_TEMP, + CTL_TEMP, + IGNORE_TEMP +}; + +extern u16_t lightness, target_lightness; +extern s16_t temperature, target_temperature; + void state_binding(u8_t lightness, u8_t temperature); +void calculate_lightness_target_values(u8_t type); +void calculate_temp_target_values(u8_t type); #endif diff --git a/apps/blemesh_models_example_2/src/storage.c b/apps/blemesh_models_example_2/src/storage.c new file mode 100644 index 000000000..86f8bdc8f --- /dev/null +++ b/apps/blemesh_models_example_2/src/storage.c @@ -0,0 +1,237 @@ +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "base64/base64.h" +#include "console/console.h" +#include "mesh/mesh.h" + +#include "ble_mesh.h" +#include "device_composition.h" +#include "storage.h" + +static u8_t storage_id; +u8_t reset_counter; + +static void save_reset_counter(void) +{ + char buf[5]; + + settings_str_from_bytes(&reset_counter, sizeof(reset_counter), buf, + sizeof(buf)); + + settings_save_one("ps/rc", buf); +} + +static void save_gen_def_trans_time_state(void) +{ + char buf[5]; + + settings_str_from_bytes(&gen_def_trans_time_srv_user_data.tt, + sizeof(gen_def_trans_time_srv_user_data.tt), + buf, sizeof(buf)); + + settings_save_one("ps/gdtt", buf); +} + +static void save_gen_onpowerup_state(void) +{ + char buf[5]; + + settings_str_from_bytes(&gen_power_onoff_srv_user_data.onpowerup, + sizeof(gen_power_onoff_srv_user_data.onpowerup), + buf, sizeof(buf)); + + settings_save_one("ps/gpo", buf); + + if (gen_power_onoff_srv_user_data.onpowerup == 0x02) { + save_on_flash(LIGHTNESS_TEMP_LAST_STATE); + } +} + +static void save_lightness_temp_def_state(void) +{ + char buf[12]; + + light_ctl_srv_user_data.lightness_temp_def = + (u32_t) ((light_ctl_srv_user_data.lightness_def << 16) | + light_ctl_srv_user_data.temp_def); + + settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_def, + sizeof(light_ctl_srv_user_data.lightness_temp_def), + buf, sizeof(buf)); + + settings_save_one("ps/ltd", buf); +} + +static void save_lightness_temp_last_state(void) +{ + char buf[12]; + + light_ctl_srv_user_data.lightness_temp_last = + (u32_t) ((light_ctl_srv_user_data.lightness << 16) | + light_ctl_srv_user_data.temp); + + settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_last, + sizeof(light_ctl_srv_user_data.lightness_temp_last), + buf, sizeof(buf)); + + settings_save_one("ps/ltl", buf); + + printk("Light CTL Last values have beed saved !!\n"); +} + +static void save_lightness_range(void) +{ + char buf[12]; + + light_lightness_srv_user_data.lightness_range = + (u32_t) ((light_lightness_srv_user_data.light_range_max << 16) | + light_lightness_srv_user_data.light_range_min); + + settings_str_from_bytes(&light_lightness_srv_user_data.lightness_range, + sizeof(light_lightness_srv_user_data.lightness_range), + buf, sizeof(buf)); + + settings_save_one("ps/lr", buf); +} + +static void save_temperature_range(void) +{ + char buf[12]; + + light_ctl_srv_user_data.temperature_range = + (u32_t) ((light_ctl_srv_user_data.temp_range_max << 16) | + light_ctl_srv_user_data.temp_range_min); + + settings_str_from_bytes(&light_ctl_srv_user_data.temperature_range, + sizeof(light_ctl_srv_user_data.temperature_range), + buf, sizeof(buf)); + + settings_save_one("ps/tr", buf); +} + +static void storage_work_handler(struct ble_npl_event *work) +{ + switch (storage_id) { + case RESET_COUNTER: + save_reset_counter(); + break; + case GEN_DEF_TRANS_TIME_STATE: + save_gen_def_trans_time_state(); + break; + case GEN_ONPOWERUP_STATE: + save_gen_onpowerup_state(); + break; + case LIGHTNESS_TEMP_DEF_STATE: + save_lightness_temp_def_state(); + break; + case LIGHTNESS_TEMP_LAST_STATE: + save_lightness_temp_last_state(); + break; + case LIGHTNESS_RANGE: + save_lightness_range(); + break; + case TEMPERATURE_RANGE: + save_temperature_range(); + break; + } +} + +struct ble_npl_callout storage_work; + +void save_on_flash(u8_t id) +{ + storage_id = id; + k_work_submit(&storage_work); + ble_npl_callout_reset(&storage_work, 0); +} + +static int ps_set(int argc, char **argv, char *val) +{ + int len; + + if (argc == 1) { + if (!strcmp(argv[0], "rc")) { + len = sizeof(reset_counter); + + return settings_bytes_from_str(val, &reset_counter, + &len); + } + + if (!strcmp(argv[0], "gdtt")) { + len = sizeof(gen_def_trans_time_srv_user_data.tt); + + return settings_bytes_from_str(val, + &gen_def_trans_time_srv_user_data.tt, &len); + } + + if (!strcmp(argv[0], "gpo")) { + len = sizeof(gen_power_onoff_srv_user_data.onpowerup); + + return settings_bytes_from_str(val, + &gen_power_onoff_srv_user_data.onpowerup, &len); + } + + if (!strcmp(argv[0], "ltd")) { + len = sizeof(light_ctl_srv_user_data.lightness_temp_def); + + return settings_bytes_from_str(val, + &light_ctl_srv_user_data.lightness_temp_def, + &len); + } + + if (!strcmp(argv[0], "ltl")) { + len = sizeof(light_ctl_srv_user_data. + lightness_temp_last); + + return settings_bytes_from_str(val, + &light_ctl_srv_user_data.lightness_temp_last, + &len); + } + + if (!strcmp(argv[0], "lr")) { + len = sizeof(light_lightness_srv_user_data. + lightness_range); + + return settings_bytes_from_str(val, + &light_lightness_srv_user_data.lightness_range, + &len); + } + + if (!strcmp(argv[0], "tr")) { + len = sizeof(light_ctl_srv_user_data. + temperature_range); + + return settings_bytes_from_str(val, + &light_ctl_srv_user_data. temperature_range, + &len); + } + } + + return -ENOENT; +} + +static struct conf_handler ps_settings = { + .ch_name = "ps", + .ch_set = ps_set, +}; + +int ps_settings_init(void) +{ + int err; + + ble_npl_callout_init(&storage_work, ble_npl_eventq_dflt_get(), + storage_work_handler, NULL); + + err = conf_register(&ps_settings); + if (err) { + printk("ps_settings_register failed (err %d)", err); + return err; + } + + return 0; +} diff --git a/apps/blemesh_models_example_2/src/storage.h b/apps/blemesh_models_example_2/src/storage.h new file mode 100644 index 000000000..5180dff2d --- /dev/null +++ b/apps/blemesh_models_example_2/src/storage.h @@ -0,0 +1,28 @@ +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef _STORAGE_H +#define _STORAGE_H + +enum ps_variables_id { + RESET_COUNTER = 0x01, + GEN_DEF_TRANS_TIME_STATE, + GEN_ONPOWERUP_STATE, + LIGHTNESS_TEMP_DEF_STATE, + LIGHTNESS_TEMP_LAST_STATE, + LIGHTNESS_RANGE, + TEMPERATURE_RANGE +}; + +extern u8_t reset_counter; + +extern struct ble_npl_callout storage_work; + +int ps_settings_init(void); +void save_on_flash(u8_t id); + +#endif diff --git a/apps/blemesh_models_example_2/src/transition.c b/apps/blemesh_models_example_2/src/transition.c index 3edbce2fe..8af549c32 100644 --- a/apps/blemesh_models_example_2/src/transition.c +++ b/apps/blemesh_models_example_2/src/transition.c @@ -5,15 +5,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#include "common.h" #include "ble_mesh.h" +#include "common.h" #include "device_composition.h" #include "state_binding.h" #include "transition.h" -u8_t enable_transition; -u8_t default_tt; - struct ble_npl_callout onoff_work; struct ble_npl_callout level_lightness_work; struct ble_npl_callout level_temp_work; @@ -22,175 +19,251 @@ struct ble_npl_callout light_lightness_linear_work; struct ble_npl_callout light_ctl_work; struct ble_npl_callout light_ctl_temp_work; -struct ble_npl_callout onoff_transition_timer; -struct ble_npl_callout level_lightness_transition_timer; -struct ble_npl_callout level_temp_transition_timer; -struct ble_npl_callout light_lightness_actual_transition_timer; -struct ble_npl_callout light_lightness_linear_transition_timer; -struct ble_npl_callout light_ctl_transition_timer; -struct ble_npl_callout light_ctl_temp_transition_timer; +struct ble_npl_callout dummy_timer; -static u32_t tt_counter_calculator(u8_t *tt, u32_t *cal_tt) +u8_t transition_type, default_tt; +u32_t *ptr_counter; +struct ble_npl_callout *ptr_timer = &dummy_timer; + +struct transition lightness_transition, temp_transition; + +/* Function to calculate Remaining Time (Start) */ + +void calculate_rt(struct transition *transition) +{ + u8_t steps, resolution; + s32_t duration_remainder; + s64_t now; + + if (transition->just_started) { + transition->rt = transition->tt; + } else { + now = k_uptime_get(); + duration_remainder = transition->total_duration - + (now - transition->start_timestamp); + + if (duration_remainder > 620000) { + /* > 620 seconds -> resolution = 0b11 [10 minutes] */ + resolution = 0x03; + steps = duration_remainder / 600000; + } else if (duration_remainder > 62000) { + /* > 62 seconds -> resolution = 0b10 [10 seconds] */ + resolution = 0x02; + steps = duration_remainder / 10000; + } else if (duration_remainder > 6200) { + /* > 6.2 seconds -> resolution = 0b01 [1 seconds] */ + resolution = 0x01; + steps = duration_remainder / 1000; + } else if (duration_remainder > 0) { + /* <= 6.2 seconds -> resolution = 0b00 [100 ms] */ + resolution = 0x00; + steps = duration_remainder / 100; + } else { + resolution = 0x00; + steps = 0x00; + } + + transition->rt = (resolution << 6) | steps; + } +} + +/* Function to calculate Remaining Time (End) */ + +static void bound_states_transition_type_reassignment(u8_t type) +{ + switch (type) { + case ONOFF: + case LEVEL: + case ACTUAL: + case LINEAR: + light_ctl_srv_user_data.transition = &lightness_transition; + break; + case CTL: + light_ctl_srv_user_data.transition = &lightness_transition; + gen_level_srv_s0_user_data.transition = &lightness_transition; + break; + case LEVEL_TEMP: + case CTL_TEMP: + gen_level_srv_s0_user_data.transition = &temp_transition; + light_ctl_srv_user_data.transition = &temp_transition; + break; + default: + break; + } +} + +static void tt_values_calculator(struct transition *transition) { u8_t steps_multiplier, resolution; - u32_t tt_counter; - resolution = ((*tt) >> 6); - steps_multiplier = (*tt) & 0x3F; + resolution = (transition->tt >> 6); + steps_multiplier = (transition->tt & 0x3F); switch (resolution) { case 0: /* 100ms */ - *cal_tt = steps_multiplier * 100; + transition->total_duration = steps_multiplier * 100; break; case 1: /* 1 second */ - *cal_tt = steps_multiplier * 1000; + transition->total_duration = steps_multiplier * 1000; break; case 2: /* 10 seconds */ - *cal_tt = steps_multiplier * 10000; + transition->total_duration = steps_multiplier * 10000; break; case 3: /* 10 minutes */ - *cal_tt = steps_multiplier * 600000; + transition->total_duration = steps_multiplier * 600000; break; } - tt_counter = ((float) *cal_tt / 100); + transition->counter = ((float) transition->total_duration / 100); - if (tt_counter > DEVICE_SPECIFIC_RESOLUTION) { - tt_counter = DEVICE_SPECIFIC_RESOLUTION; + if (transition->counter > DEVICE_SPECIFIC_RESOLUTION) { + transition->counter = DEVICE_SPECIFIC_RESOLUTION; } - if (tt_counter != 0) { - *cal_tt = *cal_tt / tt_counter; - } - - return tt_counter; + ptr_counter = &transition->counter; } -void onoff_tt_values(struct generic_onoff_state *state) +void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay) { - state->tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); + bound_states_transition_type_reassignment(ONOFF); + calculate_lightness_target_values(ONOFF); + state->transition->tt = tt; + state->transition->delay = delay; + + if (tt != 0) { + tt_values_calculator(state->transition); + } else { + return; + } + + state->transition->quo_tt = state->transition->total_duration / + state->transition->counter; + + state->tt_delta = ((float) (lightness - target_lightness) / + state->transition->counter); } -void level_tt_values(struct generic_level_state *state) +void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay) { - u32_t tt_counter; - - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; + if (state == &gen_level_srv_root_user_data) { + bound_states_transition_type_reassignment(LEVEL); + calculate_lightness_target_values(LEVEL); + } else if (state == &gen_level_srv_s0_user_data) { + bound_states_transition_type_reassignment(LEVEL_TEMP); + calculate_temp_target_values(LEVEL_TEMP); } + state->transition->tt = tt; + state->transition->delay = delay; + + if (tt != 0) { + tt_values_calculator(state->transition); + } else { + return; + } + + state->transition->quo_tt = state->transition->total_duration / + state->transition->counter; state->tt_delta = ((float) (state->level - state->target_level) / - tt_counter); + state->transition->counter); } -void delta_level_tt_values(struct generic_level_state *state) +void light_lightness_actual_tt_values(struct light_lightness_state *state, + u8_t tt, u8_t delay) { - u32_t tt_counter; + bound_states_transition_type_reassignment(ACTUAL); + calculate_lightness_target_values(ACTUAL); + state->transition->tt = tt; + state->transition->delay = delay; - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter_delta = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; + if (tt != 0) { + tt_values_calculator(state->transition); + } else { + return; } - state->tt_delta = ((float) state->last_delta / tt_counter); - - state->tt_delta *= -1; -} - -void move_level_tt_values(struct generic_level_state *state) -{ - u32_t tt_counter; - - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter_move = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; - } - - state->tt_delta = ((float) state->last_delta / tt_counter); - - state->tt_delta *= -1; -} - -void light_lightnes_actual_tt_values(struct light_lightness_state *state) -{ - u32_t tt_counter; - - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter_actual = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; - } + state->transition->quo_tt = state->transition->total_duration / + state->transition->counter; state->tt_delta_actual = ((float) (state->actual - state->target_actual) / - tt_counter); + state->transition->counter); } -void light_lightnes_linear_tt_values(struct light_lightness_state *state) +void light_lightness_linear_tt_values(struct light_lightness_state *state, + u8_t tt, u8_t delay) { - u32_t tt_counter; + bound_states_transition_type_reassignment(LINEAR); + calculate_lightness_target_values(LINEAR); + state->transition->tt = tt; + state->transition->delay = delay; - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter_linear = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; + if (tt != 0) { + tt_values_calculator(state->transition); + } else { + return; } + state->transition->quo_tt = state->transition->total_duration / + state->transition->counter; + state->tt_delta_linear = ((float) (state->linear - state->target_linear) / - tt_counter); + state->transition->counter); } -void light_ctl_tt_values(struct light_ctl_state *state) +void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay) { - u32_t tt_counter; + bound_states_transition_type_reassignment(CTL); + calculate_lightness_target_values(CTL); + state->transition->tt = tt; + state->transition->delay = delay; - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; + if (tt != 0) { + tt_values_calculator(state->transition); + } else { + return; } - state->tt_lightness_delta = + state->transition->quo_tt = state->transition->total_duration / + state->transition->counter; + + state->tt_delta_lightness = ((float) (state->lightness - state->target_lightness) / - tt_counter); + state->transition->counter); - state->tt_temp_delta = + state->tt_delta_temp = ((float) (state->temp - state->target_temp) / - tt_counter); + state->transition->counter); - state->tt_duv_delta = + state->tt_delta_duv = ((float) (state->delta_uv - state->target_delta_uv) / - tt_counter); + state->transition->counter); } -void light_ctl_temp_tt_values(struct light_ctl_state *state) +void light_ctl_temp_tt_values(struct light_ctl_state *state, + u8_t tt, u8_t delay) { - u32_t tt_counter; + bound_states_transition_type_reassignment(CTL_TEMP); + calculate_temp_target_values(CTL_TEMP); + state->transition->tt = tt; + state->transition->delay = delay; - tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt); - state->tt_counter_temp = tt_counter; - - if (tt_counter == 0) { - tt_counter = 1; + if (tt != 0) { + tt_values_calculator(state->transition); + } else { + return; } - state->tt_temp_delta = ((float) (state->temp - state->target_temp) / - tt_counter); + state->transition->quo_tt = state->transition->total_duration / + state->transition->counter; - state->tt_duv_delta = + state->tt_delta_temp = ((float) (state->temp - state->target_temp) / + state->transition->counter); + + state->tt_delta_duv = ((float) (state->delta_uv - state->target_delta_uv) / - tt_counter); + state->transition->counter); } /* Timers related handlers & threads (Start) */ @@ -198,141 +271,144 @@ static void onoff_work_handler(struct ble_npl_event *work) { struct generic_onoff_state *state = &gen_onoff_srv_root_user_data; - if (enable_transition != ONOFF_TT) { - ble_npl_callout_stop(&onoff_transition_timer); - return; - } - - if (state->tt_counter != 0) { - state->tt_counter--; - - if (state->target_onoff == STATE_ON) { - state->onoff = STATE_ON; + if (state->transition->just_started) { + state->transition->just_started = false; + if (state->transition->counter == 0) { state_binding(ONOFF, IGNORE_TEMP); update_light_state(); - enable_transition = DISABLE_TRANSITION; + ble_npl_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + + if (state->target_onoff == STATE_ON) { + state->onoff = STATE_ON; + } } + + return; } - if (state->tt_counter == 0) { - state->onoff = state->target_onoff; + if (state->transition->counter != 0) { + state->transition->counter--; - state_binding(ONOFF, IGNORE_TEMP); + lightness -= state->tt_delta; + + state_binding(IGNORE, IGNORE_TEMP); + update_light_state(); + } + + if (state->transition->counter == 0) { + state->onoff = state->target_onoff; + lightness = target_lightness; + + state_binding(IGNORE, IGNORE_TEMP); update_light_state(); - ble_npl_callout_stop(&onoff_transition_timer); + ble_npl_callout_stop(ptr_timer); } } static void level_lightness_work_handler(struct ble_npl_event *work) { - u32_t *tt_counter; + u8_t level; struct generic_level_state *state = &gen_level_srv_root_user_data; - tt_counter = NULL; - - switch (enable_transition) { + switch (transition_type) { case LEVEL_TT: - tt_counter = &state->tt_counter; + level = LEVEL; break; case LEVEL_TT_DELTA: - tt_counter = &state->tt_counter_delta; + level = DELTA_LEVEL; break; case LEVEL_TT_MOVE: - tt_counter = &state->tt_counter_move; + level = LEVEL; break; default: - ble_npl_callout_stop(&level_lightness_transition_timer); return; } - if (*tt_counter != 0) { - s32_t lightness; + if (state->transition->just_started) { + state->transition->just_started = false; - (*tt_counter)--; - - lightness = state->level - state->tt_delta; - - if (lightness > INT16_MAX) { - lightness = INT16_MAX; - } else if (lightness < INT16_MIN) { - lightness = INT16_MIN; - } - - if (state->level != lightness) { - state->level = lightness; - - state_binding(LEVEL, IGNORE_TEMP); + if (state->transition->counter == 0) { + state_binding(level, IGNORE_TEMP); update_light_state(); + + ble_npl_callout_stop(ptr_timer); } else { - enable_transition = DISABLE_TRANSITION; + state->transition->start_timestamp = k_uptime_get(); } + + return; } - if (*tt_counter == 0) { + if (state->transition->counter != 0) { + state->transition->counter--; + + state->level -= state->tt_delta; + + state_binding(level, IGNORE_TEMP); + update_light_state(); + } + + if (state->transition->counter == 0) { state->level = state->target_level; - state_binding(LEVEL, IGNORE_TEMP); + state_binding(level, IGNORE_TEMP); update_light_state(); - ble_npl_callout_stop(&level_lightness_transition_timer); + ble_npl_callout_stop(ptr_timer); } } static void level_temp_work_handler(struct ble_npl_event *work) { - u32_t *tt_counter; struct generic_level_state *state = &gen_level_srv_s0_user_data; - tt_counter = NULL; - - switch (enable_transition) { - case LEVEL_TT: - tt_counter = &state->tt_counter; + switch (transition_type) { + case LEVEL_TEMP_TT: break; - case LEVEL_TT_DELTA: - tt_counter = &state->tt_counter_delta; + case LEVEL_TEMP_TT_DELTA: break; - case LEVEL_TT_MOVE: - tt_counter = &state->tt_counter_move; + case LEVEL_TEMP_TT_MOVE: break; default: - ble_npl_callout_stop(&level_temp_transition_timer); return; } - if (*tt_counter != 0) { - s32_t temp; - - (*tt_counter)--; - - temp = state->level - state->tt_delta; - - if (temp > INT16_MAX) { - temp = INT16_MAX; - } else if (temp < INT16_MIN) { - temp = INT16_MIN; - } - - if (state->level != temp) { - state->level = temp; + if (state->transition->just_started) { + state->transition->just_started = false; + if (state->transition->counter == 0) { state_binding(IGNORE, LEVEL_TEMP); update_light_state(); + + ble_npl_callout_stop(ptr_timer); } else { - enable_transition = DISABLE_TRANSITION; + state->transition->start_timestamp = k_uptime_get(); } + + return; } - if (*tt_counter == 0) { + if (state->transition->counter != 0) { + state->transition->counter--; + + state->level -= state->tt_delta; + + state_binding(IGNORE, LEVEL_TEMP); + update_light_state(); + } + + if (state->transition->counter == 0) { state->level = state->target_level; state_binding(IGNORE, LEVEL_TEMP); update_light_state(); - ble_npl_callout_stop(&level_temp_transition_timer); + ble_npl_callout_stop(ptr_timer); } } @@ -340,35 +416,37 @@ static void light_lightness_actual_work_handler(struct ble_npl_event *work) { struct light_lightness_state *state = &light_lightness_srv_user_data; - if (enable_transition != LIGTH_LIGHTNESS_ACTUAL_TT) { - ble_npl_callout_stop(&light_lightness_actual_transition_timer); + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(ACTUAL, IGNORE_TEMP); + update_light_state(); + + ble_npl_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + return; } - if (state->tt_counter_actual != 0) { - u32_t actual; + if (state->transition->counter != 0) { + state->transition->counter--; - state->tt_counter_actual--; + state->actual -= state->tt_delta_actual; - actual = state->actual - state->tt_delta_actual; - - if (state->actual != actual) { - state->actual = actual; - - state_binding(ACTUAL, IGNORE_TEMP); - update_light_state(); - } else { - enable_transition = DISABLE_TRANSITION; - } + state_binding(ACTUAL, IGNORE_TEMP); + update_light_state(); } - if (state->tt_counter_actual == 0) { + if (state->transition->counter == 0) { state->actual = state->target_actual; state_binding(ACTUAL, IGNORE_TEMP); update_light_state(); - ble_npl_callout_stop(&light_lightness_actual_transition_timer); + ble_npl_callout_stop(ptr_timer); } } @@ -376,35 +454,37 @@ static void light_lightness_linear_work_handler(struct ble_npl_event *work) { struct light_lightness_state *state = &light_lightness_srv_user_data; - if (enable_transition != LIGTH_LIGHTNESS_LINEAR_TT) { - ble_npl_callout_stop(&light_lightness_linear_transition_timer); + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(LINEAR, IGNORE_TEMP); + update_light_state(); + + ble_npl_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + return; } - if (state->tt_counter_linear != 0) { - u32_t linear; + if (state->transition->counter != 0) { + state->transition->counter--; - state->tt_counter_linear--; + state->linear -= state->tt_delta_linear; - linear = state->linear - state->tt_delta_linear; - - if (state->linear != linear) { - state->linear = linear; - - state_binding(LINEAR, IGNORE_TEMP); - update_light_state(); - } else { - enable_transition = DISABLE_TRANSITION; - } + state_binding(LINEAR, IGNORE_TEMP); + update_light_state(); } - if (state->tt_counter_linear == 0) { + if (state->transition->counter == 0) { state->linear = state->target_linear; state_binding(LINEAR, IGNORE_TEMP); update_light_state(); - ble_npl_callout_stop(&light_lightness_linear_transition_timer); + ble_npl_callout_stop(ptr_timer); } } @@ -412,46 +492,38 @@ static void light_ctl_work_handler(struct ble_npl_event *work) { struct light_ctl_state *state = &light_ctl_srv_user_data; - if (enable_transition != LIGTH_CTL_TT) { - ble_npl_callout_stop(&light_ctl_transition_timer); + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(CTL, CTL_TEMP); + update_light_state(); + + ble_npl_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + return; } - if (state->tt_counter != 0) { - u32_t lightness, temp; - s32_t delta_uv; - - state->tt_counter--; + if (state->transition->counter != 0) { + state->transition->counter--; /* Lightness */ - lightness = state->lightness - state->tt_lightness_delta; + state->lightness -= state->tt_delta_lightness; /* Temperature */ - temp = state->temp - state->tt_temp_delta; + state->temp -= state->tt_delta_temp; /* Delta_UV */ - delta_uv = state->delta_uv - state->tt_duv_delta; + state->delta_uv -= state->tt_delta_duv; - if (delta_uv > INT16_MAX) { - delta_uv = INT16_MAX; - } else if (delta_uv < INT16_MIN) { - delta_uv = INT16_MIN; - } - - if (state->lightness != lightness || state->temp != temp || - state->delta_uv != delta_uv) { - state->lightness = lightness; - state->temp = temp; - state->delta_uv = delta_uv; - - state_binding(CTL, CTL_TEMP); - update_light_state(); - } else { - enable_transition = DISABLE_TRANSITION; - } + state_binding(CTL, CTL_TEMP); + update_light_state(); } - if (state->tt_counter == 0) { + if (state->transition->counter == 0) { state->lightness = state->target_lightness; state->temp = state->target_temp; state->delta_uv = state->target_delta_uv; @@ -459,7 +531,7 @@ static void light_ctl_work_handler(struct ble_npl_event *work) state_binding(CTL, CTL_TEMP); update_light_state(); - ble_npl_callout_stop(&light_ctl_transition_timer); + ble_npl_callout_stop(ptr_timer); } } @@ -467,58 +539,57 @@ static void light_ctl_temp_work_handler(struct ble_npl_event *work) { struct light_ctl_state *state = &light_ctl_srv_user_data; - if (enable_transition != LIGHT_CTL_TEMP_TT) { - ble_npl_callout_stop(&light_ctl_temp_transition_timer); + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(IGNORE, CTL_TEMP); + update_light_state(); + + ble_npl_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + return; } - if (state->tt_counter_temp != 0) { - s32_t delta_uv; - u32_t temp; - - state->tt_counter_temp--; + if (state->transition->counter != 0) { + state->transition->counter--; /* Temperature */ - temp = state->temp - state->tt_temp_delta; + state->temp -= state->tt_delta_temp; /* Delta UV */ - delta_uv = state->delta_uv - state->tt_duv_delta; + state->delta_uv -= state->tt_delta_duv; - if (delta_uv > INT16_MAX) { - delta_uv = INT16_MAX; - } else if (delta_uv < INT16_MIN) { - delta_uv = INT16_MIN; - } - - if (state->temp != temp || state->delta_uv != delta_uv) { - state->temp = temp; - state->delta_uv = delta_uv; - - state_binding(IGNORE, CTL_TEMP); - update_light_state(); - } else { - enable_transition = DISABLE_TRANSITION; - } + state_binding(IGNORE, CTL_TEMP); + update_light_state(); } - if (state->tt_counter_temp == 0) { + if (state->transition->counter == 0) { state->temp = state->target_temp; state->delta_uv = state->target_delta_uv; state_binding(IGNORE, CTL_TEMP); update_light_state(); - ble_npl_callout_stop(&light_ctl_temp_transition_timer); + ble_npl_callout_stop(ptr_timer); } } +static void dummy_timer_handler(struct ble_npl_event *ev) +{ } + static void onoff_tt_handler(struct ble_npl_event *ev) { struct generic_onoff_state *state = ble_npl_event_get_arg(ev); assert(state != NULL); ble_npl_callout_reset(&onoff_work, 0); - ble_npl_callout_reset(&onoff_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } static void level_lightness_tt_handler(struct ble_npl_event *ev) @@ -527,7 +598,9 @@ static void level_lightness_tt_handler(struct ble_npl_event *ev) assert(state != NULL); ble_npl_callout_reset(&level_lightness_work, 0); - ble_npl_callout_reset(&level_lightness_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } static void level_temp_tt_handler(struct ble_npl_event *ev) @@ -536,7 +609,9 @@ static void level_temp_tt_handler(struct ble_npl_event *ev) assert(state != NULL); ble_npl_callout_reset(&level_temp_work, 0); - ble_npl_callout_reset(&level_temp_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } static void light_lightness_actual_tt_handler(struct ble_npl_event *ev) @@ -545,7 +620,9 @@ static void light_lightness_actual_tt_handler(struct ble_npl_event *ev) assert(state != NULL); ble_npl_callout_reset(&light_lightness_actual_work, 0); - ble_npl_callout_reset(&light_lightness_actual_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } static void light_lightness_linear_tt_handler(struct ble_npl_event *ev) @@ -554,7 +631,9 @@ static void light_lightness_linear_tt_handler(struct ble_npl_event *ev) assert(state != NULL); ble_npl_callout_reset(&light_lightness_linear_work, 0); - ble_npl_callout_reset(&light_lightness_linear_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } static void light_ctl_tt_handler(struct ble_npl_event *ev) @@ -563,7 +642,9 @@ static void light_ctl_tt_handler(struct ble_npl_event *ev) assert(state != NULL); ble_npl_callout_reset(&light_ctl_work, 0); - ble_npl_callout_reset(&light_ctl_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } static void light_ctl_temp_tt_handler(struct ble_npl_event *ev) @@ -572,65 +653,97 @@ static void light_ctl_temp_tt_handler(struct ble_npl_event *ev) assert(state != NULL); ble_npl_callout_reset(&light_ctl_temp_work, 0); - ble_npl_callout_reset(&light_ctl_temp_transition_timer, K_MSEC(state->cal_tt)); + ble_npl_callout_reset(&state->transition->timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); } /* Timers related handlers & threads (End) */ /* Messages handlers (Start) */ void onoff_handler(struct generic_onoff_state *state) { - enable_transition = ONOFF_TT; + ptr_timer = &state->transition->timer; - ble_npl_callout_set_arg(&onoff_transition_timer, state); - ble_npl_callout_reset(&onoff_transition_timer, K_MSEC(5 * state->delay)); + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + onoff_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } void level_lightness_handler(struct generic_level_state *state) { - ble_npl_callout_set_arg(&level_lightness_transition_timer, state); - ble_npl_callout_reset(&level_lightness_transition_timer, - K_MSEC(5 * state->delay)); + ptr_timer = &state->transition->timer; + + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + level_lightness_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } void level_temp_handler(struct generic_level_state *state) { - ble_npl_callout_set_arg(&level_temp_transition_timer, state); - ble_npl_callout_reset(&level_temp_transition_timer, K_MSEC(5 * state->delay)); + ptr_timer = &state->transition->timer; + + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + level_temp_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } void light_lightness_actual_handler(struct light_lightness_state *state) { - enable_transition = LIGTH_LIGHTNESS_ACTUAL_TT; + ptr_timer = &state->transition->timer; - ble_npl_callout_set_arg(&light_lightness_actual_transition_timer, state); - ble_npl_callout_reset(&light_lightness_actual_transition_timer, - K_MSEC(5 * state->delay)); + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + light_lightness_actual_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, + state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } void light_lightness_linear_handler(struct light_lightness_state *state) { - enable_transition = LIGTH_LIGHTNESS_LINEAR_TT; + ptr_timer = &state->transition->timer; - ble_npl_callout_set_arg(&light_lightness_linear_transition_timer, state); - ble_npl_callout_reset(&light_lightness_linear_transition_timer, - K_MSEC(5 * state->delay)); + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + light_lightness_linear_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, + state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } void light_ctl_handler(struct light_ctl_state *state) { - enable_transition = LIGTH_CTL_TT; + ptr_timer = &state->transition->timer; - ble_npl_callout_set_arg(&light_ctl_transition_timer, state); - ble_npl_callout_reset(&light_ctl_transition_timer, K_MSEC(5 * state->delay)); + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + light_ctl_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } void light_ctl_temp_handler(struct light_ctl_state *state) { - enable_transition = LIGHT_CTL_TEMP_TT; + ptr_timer = &state->transition->timer; - ble_npl_callout_set_arg(&light_ctl_temp_transition_timer, state); - ble_npl_callout_reset(&light_ctl_temp_transition_timer, - K_MSEC(5 * state->delay)); + ble_npl_callout_init(ptr_timer, ble_npl_eventq_dflt_get(), + light_ctl_temp_tt_handler, NULL); + ble_npl_callout_set_arg(ptr_timer, state); + ble_npl_callout_reset(ptr_timer, + ble_npl_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); } /* Messages handlers (End) */ @@ -644,9 +757,11 @@ void transition_timers_init(void) ble_npl_callout_init(&level_temp_work, ble_npl_eventq_dflt_get(), level_temp_work_handler, NULL); - ble_npl_callout_init(&light_lightness_actual_work, ble_npl_eventq_dflt_get(), + ble_npl_callout_init(&light_lightness_actual_work, + ble_npl_eventq_dflt_get(), light_lightness_actual_work_handler, NULL); - ble_npl_callout_init(&light_lightness_linear_work, ble_npl_eventq_dflt_get(), + ble_npl_callout_init(&light_lightness_linear_work, + ble_npl_eventq_dflt_get(), light_lightness_linear_work_handler, NULL); ble_npl_callout_init(&light_ctl_work, ble_npl_eventq_dflt_get(), @@ -654,25 +769,7 @@ void transition_timers_init(void) ble_npl_callout_init(&light_ctl_temp_work, ble_npl_eventq_dflt_get(), light_ctl_temp_work_handler, NULL); - ble_npl_callout_init(&onoff_transition_timer, ble_npl_eventq_dflt_get(), - onoff_tt_handler, NULL); + ble_npl_callout_init(&dummy_timer, ble_npl_eventq_dflt_get(), + dummy_timer_handler, NULL); +} - ble_npl_callout_init(&level_lightness_transition_timer, ble_npl_eventq_dflt_get(), - level_lightness_tt_handler, NULL); - ble_npl_callout_init(&level_temp_transition_timer, ble_npl_eventq_dflt_get(), - level_temp_tt_handler, NULL); - - ble_npl_callout_init(&light_lightness_actual_transition_timer, ble_npl_eventq_dflt_get(), - light_lightness_actual_tt_handler, NULL); - ble_npl_callout_init(&light_lightness_linear_transition_timer, ble_npl_eventq_dflt_get(), - light_lightness_linear_tt_handler, NULL); - - ble_npl_callout_init(&light_ctl_transition_timer, ble_npl_eventq_dflt_get(), - light_ctl_tt_handler, NULL); - ble_npl_callout_init(&light_ctl_temp_transition_timer, ble_npl_eventq_dflt_get(), - light_ctl_temp_tt_handler, NULL); - - ble_npl_callout_init(&light_ctl_temp_transition_timer, ble_npl_eventq_dflt_get(), - light_ctl_temp_tt_handler, NULL); - -} \ No newline at end of file diff --git a/apps/blemesh_models_example_2/src/transition.h b/apps/blemesh_models_example_2/src/transition.h index f399005f6..ebc00cdbf 100644 --- a/apps/blemesh_models_example_2/src/transition.h +++ b/apps/blemesh_models_example_2/src/transition.h @@ -8,42 +8,52 @@ #ifndef _TRANSITION_H #define _TRANSITION_H +#define UNKNOWN_VALUE 0x3F #define DEVICE_SPECIFIC_RESOLUTION 10 -enum transition_time { - DISABLE_TRANSITION = 0x00, - ONOFF_TT = 0x01, +enum level_transition_types { LEVEL_TT, LEVEL_TT_DELTA, LEVEL_TT_MOVE, - LIGTH_LIGHTNESS_ACTUAL_TT, - LIGTH_LIGHTNESS_LINEAR_TT, - LIGTH_CTL_TT, + LEVEL_TEMP_TT, LEVEL_TEMP_TT_DELTA, LEVEL_TEMP_TT_MOVE, - LIGHT_CTL_TEMP_TT }; -extern u8_t enable_transition; -extern u8_t default_tt; +struct transition { + bool just_started; + u8_t tt; + u8_t rt; + u8_t delay; + u32_t quo_tt; + u32_t counter; + u32_t total_duration; + s64_t start_timestamp; -extern struct ble_npl_callout onoff_transition_timer; -extern struct ble_npl_callout level_lightness_transition_timer; -extern struct ble_npl_callout level_temp_transition_timer; -extern struct ble_npl_callout light_lightness_actual_transition_timer; -extern struct ble_npl_callout light_lightness_linear_transition_timer; -extern struct ble_npl_callout light_ctl_transition_timer; -extern struct ble_npl_callout light_ctl_temp_transition_timer; + struct ble_npl_callout timer; +}; -void onoff_tt_values(struct generic_onoff_state *state); -void level_tt_values(struct generic_level_state *state); -void delta_level_tt_values(struct generic_level_state *state); -void move_level_tt_values(struct generic_level_state *state); -void light_lightnes_actual_tt_values(struct light_lightness_state *state); -void light_lightnes_linear_tt_values(struct light_lightness_state *state); -void light_ctl_tt_values(struct light_ctl_state *state); -void light_ctl_temp_tt_values(struct light_ctl_state *state); +extern u8_t transition_type, default_tt; +extern u32_t *ptr_counter; +extern struct ble_npl_callout *ptr_timer; + +extern struct transition lightness_transition, temp_transition; + +extern struct ble_npl_callout dummy_timer; + +void calculate_rt(struct transition *transition); + + +void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay); +void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay); +void light_lightness_actual_tt_values(struct light_lightness_state *state, + u8_t tt, u8_t delay); +void light_lightness_linear_tt_values(struct light_lightness_state *state, + u8_t tt, u8_t delay); +void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay); +void light_ctl_temp_tt_values(struct light_ctl_state *state, + u8_t tt, u8_t delay); void onoff_handler(struct generic_onoff_state *state); void level_lightness_handler(struct generic_level_state *state); diff --git a/apps/blemesh_models_example_2/syscfg.yml b/apps/blemesh_models_example_2/syscfg.yml index bbc4ea083..bff8049e1 100644 --- a/apps/blemesh_models_example_2/syscfg.yml +++ b/apps/blemesh_models_example_2/syscfg.yml @@ -21,7 +21,7 @@ syscfg.vals: LOG_LEVEL: 1 # Default task settings - OS_MAIN_STACK_SIZE: 768 + OS_MAIN_STACK_SIZE: 4096 # Newtmgr is not supported in this app, so disable newtmgr-over-shell. SHELL_NEWTMGR: 0 @@ -31,14 +31,33 @@ syscfg.vals: FLOAT_USER: 1 HARD_FLOAT: 1 - BLE_MESH_ADV_BUF_COUNT: 20 - BLE_MESH_TX_SEG_MAX: 9 + BLE_MESH_DEV_UUID: "((uint8_t[16]){0xdd, 0xdd, 0})" + BLE_MESH_ADV_BUF_COUNT: 60 + BLE_MESH_TX_SEG_MAX: 6 + BLE_MESH_TX_SEG_MSG_COUNT: 3 + BLE_MESH_RX_SEG_MSG_COUNT: 3 + BLE_MESH_CRPL: 128 + BLE_MESH_RPL_STORE_TIMEOUT: 120 + BLE_MESH_MSG_CACHE_SIZE: 100 + + BLE_MESH_SETTINGS: 1 + CONFIG_FCB: 1 BLE_MESH: 1 - BLE_MESH_CFG_CLI: 1 - BLE_MESH_DEV_UUID: "((uint8_t[16]){0xdd, 0xdd, 0})" - BLE_MESH_SETTINGS: 0 - CONFIG_NFFS: 0 + BLE_MESH_RELAY: 1 + BLE_MESH_LOW_POWER: 0 + BLE_MESH_LPN_AUTO: 0 + BLE_MESH_FRIEND: 0 + + BLE_MESH_PROV: 1 + BLE_MESH_PB_ADV: 1 + BLE_MESH_PB_GATT: 1 + BLE_MESH_GATT_PROXY: 1 + + BLE_MESH_SUBNET_COUNT: 2 + BLE_MESH_APP_KEY_COUNT: 2 + BLE_MESH_MODEL_GROUP_COUNT: 2 + BLE_MESH_LABEL_COUNT: 3 BLE_MESH_DEBUG: 0 BLE_MESH_DEBUG_NET: 0