apps/blemesh_models_example_2: Add app with various models

This is a application demonstrating a Bluetooth mesh node in
which Root element has following models

- Generic OnOff Server
- Generic OnOff Client
- Generic Level Server
- Generic Level Client
- Generic Power OnOff Server
- Generic Power OnOff Setup Server
- Generic Power OnOff Client
- Light Lightness Server
- Light Lightness Setup Server
- Light Lightness Client
- Light CTL Server
- Light CTL Setup Server
- Light CTL Client
- Vendor Model

And Secondary element has following models

- Generic OnOff Server
- Generic OnOff Client
- Generic Level Server
- Generic Level Client
- Light CTL Temperature Server

Prior to provisioning, an unprovisioned beacon is broadcast that contains
a unique UUID. Each button controls the state of its
corresponding LED and does not initiate any mesh activity
This commit is contained in:
Michał Narajowski
2018-07-26 13:52:59 +02:00
parent af8b5332a5
commit 5c058dd19e
15 changed files with 3862 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
#### Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
##### Overview
********
This is a application demonstrating a Bluetooth mesh node in
which Root element has following models
- Generic OnOff Server
- Generic OnOff Client
- Generic Level Server
- Generic Level Client
- Generic Power OnOff Server
- Generic Power OnOff Setup Server
- Generic Power OnOff Client
- Light Lightness Server
- Light Lightness Setup Server
- Light Lightness Client
- Light CTL Server
- Light CTL Setup Server
- Light CTL Client
- Vendor Model
And Secondary element has following models
- Generic OnOff Server
- Generic OnOff Client
- Generic Level Server
- Generic Level Client
- Light CTL Temperature Server
Prior to provisioning, an unprovisioned beacon is broadcast that contains
a unique UUID. Each button controls the state of its
corresponding LED and does not initiate any mesh activity
##### Associations of Models with hardware
************************************
For the nRF52840-PDK board, these are the model associations:
* LED1 is associated with generic OnOff Server's state which is part of Root element
* LED2 is associated with Vendor Model which is part of Root element
* LED3 is associated with generic Level (ROOT) / Light Lightness Actual value
* LED4 is associated with generic Level (Secondary) / Light CTL Temperature value
* Button1 and Button2 are associated with gen. OnOff Client or Vendor Model which is part of Root element
* Button3 and Button4 are associated with gen. Level Client / Light Lightness Client / Light CTL Client which is part of Root element
States of Servers are bounded as per Bluetooth SIG Mesh Model Specification v1.0
After provisioning, the button clients must
be configured to publish and the LED servers to subscribe.
If a server is provided with a publish address, it will
also publish its relevant status.
##### Requirements
************
This sample has been tested on the Nordic nRF52840-PDK board, but would
likely also run on the nrf52_pca10040 board.
##### Running
************
Provisioning is done using the BlueZ meshctl utility. In this example, we'll use meshctl commands to bind:
- Button1, Button2, and LED1 to application key 1. It then configures Button1 and Button2
to publish to group 0xC000 and LED1 to subscribe to that group.
- Button3, Button4, and LED3 to application key 1. It then configures Button3 and Button4
to publish to group 0xC000 and LED3 to subscribe to that group.
```
discover-unprovisioned on
provision <discovered UUID>
menu config
target 0100
appkey-add 1
bind 0 1 1000
bind 0 1 1001
bind 0 1 1002
bind 0 1 1003
sub-add 0100 c000 1000
sub-add 0100 c000 1002
pub-set 0100 c000 1 0 5 1001
pub-set 0100 c000 1 0 5 1003
```
The meshctl utility maintains a persistent JSON database containing
the mesh configuration. As additional nodes (boards) are provisioned, it
assigns sequential unicast addresses based on the number of elements
supported by the node. This example supports 2 elements per node.
The meshctl target for configuration must be the root element's unicast
address as it is the only one that has a configuration server model. If
meshctl is gracefully exited, it can be restarted and reconnected to
network 0x0.
The meshctl utility also supports a onoff model client that can be used to
change the state of any LED that is bound to application key 0x1.
This is done by setting the target to the unicast address of the element
that has that LED's model and issuing the onoff command.
Group addresses are not supported.
+38
View File
@@ -0,0 +1,38 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
pkg.name: apps/blemesh_models_example_2
pkg.type: app
pkg.description: Sample application for BLE Mesh node with on/off, level, light and vendor models on nRF52840pdk
pkg.author: "Michał Narajowski <michal.narajowski@codecoup.pl>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
pkg.deps:
- "@apache-mynewt-core/kernel/os"
- "@apache-mynewt-core/sys/console/full"
- "@apache-mynewt-core/sys/log/full"
- "@apache-mynewt-core/sys/stats/full"
- nimble/controller
- nimble/host
- nimble/host/services/gap
- nimble/host/services/gatt
- nimble/transport/ram
pkg.lflags:
- -DFLOAT_SUPPORT
- -lm
@@ -0,0 +1,93 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "console/console.h"
#include "ble_mesh.h"
#include "device_composition.h"
#define OOB_AUTH_ENABLE 1
#ifdef OOB_AUTH_ENABLE
static int output_number(bt_mesh_output_action_t action, u32_t number)
{
printk("OOB Number: %lu\n", number);
return 0;
}
static int output_string(const char *str)
{
printk("OOB String: %s\n", str);
return 0;
}
#endif
static void prov_complete(u16_t net_idx, u16_t addr)
{
}
static void prov_reset(void)
{
bt_mesh_prov_enable(BT_MESH_PROV_ADV | BT_MESH_PROV_GATT);
}
static u8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
static const struct bt_mesh_prov prov = {
.uuid = dev_uuid,
#ifdef OOB_AUTH_ENABLE
.output_size = 6,
.output_actions = BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING,
.output_number = output_number,
.output_string = output_string,
#endif
.complete = prov_complete,
.reset = prov_reset,
};
void blemesh_on_reset(int reason)
{
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
}
void blemesh_on_sync(void)
{
int err;
ble_addr_t addr;
console_printf("Bluetooth initialized\n");
/* Use NRPA */
err = ble_hs_id_gen_rnd(1, &addr);
assert(err == 0);
err = ble_hs_id_set_rnd(addr.val);
assert(err == 0);
err = bt_mesh_init(addr.type, &prov, &comp);
if (err) {
console_printf("Initializing mesh failed (err %d)\n", err);
return;
}
if (IS_ENABLED(CONFIG_SETTINGS)) {
settings_load();
}
if (bt_mesh_is_provisioned()) {
console_printf("Mesh network restored from flash\n");
}
bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV);
console_printf("Mesh initialized\n");
}
@@ -0,0 +1,34 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLE_MESH_H
#define _BLE_MESH_H
#include "mesh/mesh.h"
#include "mesh/glue.h"
/* Model Operation Codes */
#define BT_MESH_MODEL_OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)
#define BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x03)
#define BT_MESH_MODEL_OP_GEN_ONOFF_STATUS BT_MESH_MODEL_OP_2(0x82, 0x04)
#define BT_MESH_MODEL_OP_GEN_LEVEL_GET BT_MESH_MODEL_OP_2(0x82, 0x05)
#define BT_MESH_MODEL_OP_GEN_LEVEL_SET BT_MESH_MODEL_OP_2(0x82, 0x06)
#define BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x07)
#define BT_MESH_MODEL_OP_GEN_LEVEL_STATUS BT_MESH_MODEL_OP_2(0x82, 0x08)
#define BT_MESH_MODEL_OP_GEN_DELTA_SET BT_MESH_MODEL_OP_2(0x82, 0x09)
#define BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x0A)
#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)
void blemesh_on_reset(int reason);
void blemesh_on_sync(void);
void init_pub(void);
#endif
@@ -0,0 +1,16 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _COMMON_H
#define _COMMON_H
extern int button_device[];
extern int led_device[];
void update_light_state(void);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,182 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _DEVICE_COMPOSITION_H
#define _DEVICE_COMPOSITION_H
#define CID_RUNTIME 0x05C3
#define STATE_OFF 0x00
#define STATE_ON 0x01
#define STATE_DEFAULT 0x01
#define STATE_RESTORE 0x02
/* Following 4 values are as per Mesh Model specification */
#define LIGHTNESS_MIN 0x0001
#define LIGHTNESS_MAX 0xFFFF
#define TEMP_MIN 0x0320
#define TEMP_MAX 0x4E20
/* Refer 7.2 of Mesh Model Specification */
#define RANGE_SUCCESSFULLY_UPDATED 0x00
#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;
s64_t last_msg_timestamp;
u8_t tt;
u32_t cal_tt;
u8_t delay;
u32_t tt_counter;
u8_t is_optional_para_available;
};
struct generic_level_state {
s16_t level;
s16_t target_level;
s16_t last_level;
s32_t last_delta;
u8_t last_tid;
u16_t last_tx_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 generic_onpowerup_state {
u8_t onpowerup;
u8_t last_tid;
u16_t last_tx_addr;
};
struct gen_def_trans_time_state {
u8_t tt;
};
struct vendor_state {
int current;
u32_t response;
u8_t last_tid;
u16_t last_tx_addr;
s64_t last_msg_timestamp;
};
struct light_lightness_state {
u16_t linear;
u16_t target_linear;
u16_t actual;
u16_t target_actual;
u16_t last;
u16_t def;
u8_t status_code;
u16_t light_range_min;
u16_t light_range_max;
u8_t last_tid;
u16_t last_tx_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 light_ctl_state {
u16_t lightness;
u16_t target_lightness;
u16_t temp;
u16_t target_temp;
s16_t delta_uv;
s16_t target_delta_uv;
u8_t status_code;
u16_t temp_range_min;
u16_t temp_range_max;
u16_t lightness_def;
u16_t temp_def;
s16_t delta_uv_def;
u16_t temp_last;
u8_t last_tid;
u16_t last_tx_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;
u8_t is_optional_para_available;
};
extern struct generic_onoff_state gen_onoff_srv_root_user_data;
extern struct generic_level_state gen_level_srv_root_user_data;
extern struct gen_def_trans_time_state gen_def_trans_time_srv_user_data;
extern struct generic_onpowerup_state gen_power_onoff_srv_user_data;
extern struct light_lightness_state light_lightness_srv_user_data;
extern struct light_ctl_state light_ctl_srv_user_data;
extern struct generic_level_state gen_level_srv_s0_user_data;
extern struct bt_mesh_model root_models[];
extern struct bt_mesh_model vnd_models[];
extern struct bt_mesh_model s0_models[];
extern const struct bt_mesh_comp comp;
#endif
+198
View File
@@ -0,0 +1,198 @@
/* 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 "common.h"
#include "ble_mesh.h"
#include "device_composition.h"
#include "publisher.h"
#include "state_binding.h"
#include "transition.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);
}
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.def = LIGHTNESS_MAX;
/* Following 2 values are as per specification */
light_ctl_srv_user_data.temp_range_min = TEMP_MIN;
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.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) */
light_ctl_srv_user_data.temp =
light_ctl_srv_user_data.temp_last;
state_binding(ONPOWERUP, ONOFF_TEMP);
}
}
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);
printk("power-> %d, color-> %d\n", power, color);
if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
/* LED1 On */
hal_gpio_write(led_device[0], 0);
} else {
/* LED1 Off */
hal_gpio_write(led_device[0], 1);
}
if (power < 50) {
/* LED3 On */
hal_gpio_write(led_device[2], 0);
} else {
/* LED3 Off */
hal_gpio_write(led_device[2], 1);
}
if (color < 50) {
/* LED4 On */
hal_gpio_write(led_device[3], 0);
} else {
/* LED4 Off */
hal_gpio_write(led_device[3], 1);
}
}
int main(void)
{
#ifdef ARCH_sim
mcu_sim_parse_args(argc, argv);
#endif
/* Initialize OS */
sysinit();
light_default_status_init();
transition_timers_init();
gpio_init();
update_light_state();
init_pub();
printk("Initializing...\n");
/* Initialize the NimBLE host configuration. */
ble_hs_cfg.reset_cb = blemesh_on_reset;
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());
}
return 0;
}
@@ -0,0 +1,241 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "console/console.h"
#include "hal/hal_gpio.h"
#include "common.h"
#include "ble_mesh.h"
#include "publisher.h"
#include "device_composition.h"
#define ONOFF
#define GENERIC_LEVEL
/* #define LIGHT_CTL */
/* #define LIGHT_CTL_TEMP */
static bool is_randomization_of_TIDs_done;
#if defined(ONOFF)
static u8_t tid_onoff;
#elif defined(VND_MODEL_TEST)
static u8_t tid_vnd;
#endif
static u8_t tid_level;
void randomize_publishers_TID(void)
{
#if defined(ONOFF)
bt_rand(&tid_onoff, sizeof(tid_onoff));
#elif defined(VND_MODEL_TEST)
bt_rand(&tid_vnd, sizeof(tid_vnd));
#endif
bt_rand(&tid_level, sizeof(tid_level));
is_randomization_of_TIDs_done = true;
}
static u32_t button_read(int button)
{
return (uint32_t) hal_gpio_read(button);
}
void publish(struct ble_npl_event *work)
{
int err = 0;
if (is_randomization_of_TIDs_done == false) {
return;
}
if (button_read(button_device[0]) == 0) {
#if defined(ONOFF)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(ONOFF_TT)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
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));
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]);
#endif
} else if (button_read(button_device[1]) == 0) {
#if defined(ONOFF)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x00);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
err = bt_mesh_model_publish(&root_models[3]);
#elif defined(ONOFF_TT)
bt_mesh_model_msg_init(root_models[3].pub->msg,
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x00);
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
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));
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]);
#endif
} else if (button_read(button_device[2]) == 0) {
#if defined(GENERIC_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK);
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(GENERIC_DELTA_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK);
net_buf_simple_add_le32(root_models[5].pub->msg, 100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(GENERIC_MOVE_LEVEL_TT)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, 13100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(LIGHT_LIGHTNESS_TT)
bt_mesh_model_msg_init(root_models[13].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x4D));
net_buf_simple_add_le16(root_models[13].pub->msg, LEVEL_U25);
net_buf_simple_add_u8(root_models[13].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x28);
err = bt_mesh_model_publish(&root_models[13]);
#elif defined(LIGHT_CTL)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U25);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TT)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U25);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TEMP)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x65));
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0320);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#endif
} else if (button_read(button_device[3]) == 0) {
#if defined(GENERIC_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_LEVEL_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, LEVEL_S100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(GENERIC_DELTA_LEVEL)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_DELTA_SET_UNACK);
net_buf_simple_add_le32(root_models[5].pub->msg, -100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(GENERIC_MOVE_LEVEL_TT)
bt_mesh_model_msg_init(root_models[5].pub->msg,
BT_MESH_MODEL_OP_GEN_MOVE_SET_UNACK);
net_buf_simple_add_le16(root_models[5].pub->msg, -13100);
net_buf_simple_add_u8(root_models[5].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[5].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[5]);
#elif defined(LIGHT_LIGHTNESS_TT)
bt_mesh_model_msg_init(root_models[13].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x4D));
net_buf_simple_add_le16(root_models[13].pub->msg, LEVEL_U100);
net_buf_simple_add_u8(root_models[13].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[13].pub->msg, 0x28);
err = bt_mesh_model_publish(&root_models[13]);
#elif defined(LIGHT_CTL)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U100);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TT)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x5F));
/* Lightness */
net_buf_simple_add_le16(root_models[16].pub->msg, LEVEL_U100);
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x45);
net_buf_simple_add_u8(root_models[16].pub->msg, 0x00);
err = bt_mesh_model_publish(&root_models[16]);
#elif defined(LIGHT_CTL_TEMP)
bt_mesh_model_msg_init(root_models[16].pub->msg,
BT_MESH_MODEL_OP_2(0x82, 0x65));
/* Temperature (value should be from 0x0320 to 0x4E20 */
/* This is as per 6.1.3.1 in Mesh Model Specification */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x4E20);
/* Delta UV */
net_buf_simple_add_le16(root_models[16].pub->msg, 0x0000);
net_buf_simple_add_u8(root_models[16].pub->msg, tid_level++);
err = bt_mesh_model_publish(&root_models[16]);
#endif
}
if (err) {
printk("bt_mesh_model_publish: err: %d\n", err);
}
}
@@ -0,0 +1,27 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _PUBLISHER_H
#define _PUBLISHER_H
/* Others */
#define LEVEL_S0 -32768
#define LEVEL_S25 -16384
#define LEVEL_S50 0
#define LEVEL_S75 16384
#define LEVEL_S100 32767
#define LEVEL_U0 0
#define LEVEL_U25 16384
#define LEVEL_U50 32768
#define LEVEL_U75 49152
#define LEVEL_U100 65535
void randomize_publishers_TID(void);
void publish(struct ble_npl_event *work);
#endif
@@ -0,0 +1,183 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <math.h>
#include "common.h"
#include "ble_mesh.h"
#include "device_composition.h"
static s32_t ceiling(float num)
{
s32_t inum;
inum = (s32_t) num;
if (num == (float) inum) {
return inum;
}
return inum + 1;
}
static bool constrain_light_actual_state(u16_t var)
{
bool is_value_within_range;
is_value_within_range = false;
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;
}
static void update_gen_onoff_state(void)
{
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 */
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;
light_ctl_srv_user_data.temp =
light_ctl_srv_user_data.temp_range_min + tmp;
/* 6.1.3.1.1 1st formula end */
break;
default:
break;
}
tmp16 = 0;
switch (lightness) {
case ONPOWERUP: /* Lightness update as per Generic OnPowerUp state */
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;
} else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) {
light_lightness_srv_user_data.actual =
light_lightness_srv_user_data.last;
}
break;
case ONOFF: /* Lightness update as per Generic OnOff (root) state */
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;
} 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;
} else {
light_lightness_srv_user_data.actual =
light_lightness_srv_user_data.def;
}
}
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;
} else {
tmp16 =
light_lightness_srv_user_data.light_range_min;
}
} 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();
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;
}
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();
break;
default:
return;
}
tmp = ((float) light_lightness_srv_user_data.actual / 65535);
light_lightness_srv_user_data.linear = ceiling(65535 * tmp * 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;
}
gen_level_srv_root_user_data.level =
light_lightness_srv_user_data.actual - 32768;
light_ctl_srv_user_data.lightness =
light_lightness_srv_user_data.actual;
}
@@ -0,0 +1,13 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _STATE_BINDING_H
#define _STATE_BINDING_H
void state_binding(u8_t lightness, u8_t temperature);
#endif
@@ -0,0 +1,678 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "common.h"
#include "ble_mesh.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;
struct ble_npl_callout light_lightness_actual_work;
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;
static u32_t tt_counter_calculator(u8_t *tt, u32_t *cal_tt)
{
u8_t steps_multiplier, resolution;
u32_t tt_counter;
resolution = ((*tt) >> 6);
steps_multiplier = (*tt) & 0x3F;
switch (resolution) {
case 0: /* 100ms */
*cal_tt = steps_multiplier * 100;
break;
case 1: /* 1 second */
*cal_tt = steps_multiplier * 1000;
break;
case 2: /* 10 seconds */
*cal_tt = steps_multiplier * 10000;
break;
case 3: /* 10 minutes */
*cal_tt = steps_multiplier * 600000;
break;
}
tt_counter = ((float) *cal_tt / 100);
if (tt_counter > DEVICE_SPECIFIC_RESOLUTION) {
tt_counter = DEVICE_SPECIFIC_RESOLUTION;
}
if (tt_counter != 0) {
*cal_tt = *cal_tt / tt_counter;
}
return tt_counter;
}
void onoff_tt_values(struct generic_onoff_state *state)
{
state->tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
}
void 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 = tt_counter;
if (tt_counter == 0) {
tt_counter = 1;
}
state->tt_delta = ((float) (state->level - state->target_level) /
tt_counter);
}
void delta_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_delta = tt_counter;
if (tt_counter == 0) {
tt_counter = 1;
}
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->tt_delta_actual =
((float) (state->actual - state->target_actual) /
tt_counter);
}
void light_lightnes_linear_tt_values(struct light_lightness_state *state)
{
u32_t tt_counter;
tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
state->tt_counter_linear = tt_counter;
if (tt_counter == 0) {
tt_counter = 1;
}
state->tt_delta_linear =
((float) (state->linear - state->target_linear) /
tt_counter);
}
void light_ctl_tt_values(struct light_ctl_state *state)
{
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;
}
state->tt_lightness_delta =
((float) (state->lightness - state->target_lightness) /
tt_counter);
state->tt_temp_delta =
((float) (state->temp - state->target_temp) /
tt_counter);
state->tt_duv_delta =
((float) (state->delta_uv - state->target_delta_uv) /
tt_counter);
}
void light_ctl_temp_tt_values(struct light_ctl_state *state)
{
u32_t tt_counter;
tt_counter = tt_counter_calculator(&state->tt, &state->cal_tt);
state->tt_counter_temp = tt_counter;
if (tt_counter == 0) {
tt_counter = 1;
}
state->tt_temp_delta = ((float) (state->temp - state->target_temp) /
tt_counter);
state->tt_duv_delta =
((float) (state->delta_uv - state->target_delta_uv) /
tt_counter);
}
/* Timers related handlers & threads (Start) */
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;
state_binding(ONOFF, IGNORE_TEMP);
update_light_state();
enable_transition = DISABLE_TRANSITION;
}
}
if (state->tt_counter == 0) {
state->onoff = state->target_onoff;
state_binding(ONOFF, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(&onoff_transition_timer);
}
}
static void level_lightness_work_handler(struct ble_npl_event *work)
{
u32_t *tt_counter;
struct generic_level_state *state = &gen_level_srv_root_user_data;
tt_counter = NULL;
switch (enable_transition) {
case LEVEL_TT:
tt_counter = &state->tt_counter;
break;
case LEVEL_TT_DELTA:
tt_counter = &state->tt_counter_delta;
break;
case LEVEL_TT_MOVE:
tt_counter = &state->tt_counter_move;
break;
default:
ble_npl_callout_stop(&level_lightness_transition_timer);
return;
}
if (*tt_counter != 0) {
s32_t lightness;
(*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);
update_light_state();
} else {
enable_transition = DISABLE_TRANSITION;
}
}
if (*tt_counter == 0) {
state->level = state->target_level;
state_binding(LEVEL, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(&level_lightness_transition_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;
break;
case LEVEL_TT_DELTA:
tt_counter = &state->tt_counter_delta;
break;
case LEVEL_TT_MOVE:
tt_counter = &state->tt_counter_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;
state_binding(IGNORE, LEVEL_TEMP);
update_light_state();
} else {
enable_transition = DISABLE_TRANSITION;
}
}
if (*tt_counter == 0) {
state->level = state->target_level;
state_binding(IGNORE, LEVEL_TEMP);
update_light_state();
ble_npl_callout_stop(&level_temp_transition_timer);
}
}
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);
return;
}
if (state->tt_counter_actual != 0) {
u32_t actual;
state->tt_counter_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;
}
}
if (state->tt_counter_actual == 0) {
state->actual = state->target_actual;
state_binding(ACTUAL, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(&light_lightness_actual_transition_timer);
}
}
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);
return;
}
if (state->tt_counter_linear != 0) {
u32_t linear;
state->tt_counter_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;
}
}
if (state->tt_counter_linear == 0) {
state->linear = state->target_linear;
state_binding(LINEAR, IGNORE_TEMP);
update_light_state();
ble_npl_callout_stop(&light_lightness_linear_transition_timer);
}
}
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);
return;
}
if (state->tt_counter != 0) {
u32_t lightness, temp;
s32_t delta_uv;
state->tt_counter--;
/* Lightness */
lightness = state->lightness - state->tt_lightness_delta;
/* Temperature */
temp = state->temp - state->tt_temp_delta;
/* Delta_UV */
delta_uv = state->delta_uv - state->tt_duv_delta;
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;
}
}
if (state->tt_counter == 0) {
state->lightness = state->target_lightness;
state->temp = state->target_temp;
state->delta_uv = state->target_delta_uv;
state_binding(CTL, CTL_TEMP);
update_light_state();
ble_npl_callout_stop(&light_ctl_transition_timer);
}
}
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);
return;
}
if (state->tt_counter_temp != 0) {
s32_t delta_uv;
u32_t temp;
state->tt_counter_temp--;
/* Temperature */
temp = state->temp - state->tt_temp_delta;
/* Delta UV */
delta_uv = state->delta_uv - state->tt_duv_delta;
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;
}
}
if (state->tt_counter_temp == 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);
}
}
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));
}
static void level_lightness_tt_handler(struct ble_npl_event *ev)
{
struct generic_level_state *state = ble_npl_event_get_arg(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));
}
static void level_temp_tt_handler(struct ble_npl_event *ev)
{
struct generic_level_state *state = ble_npl_event_get_arg(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));
}
static void light_lightness_actual_tt_handler(struct ble_npl_event *ev)
{
struct light_lightness_state *state = ble_npl_event_get_arg(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));
}
static void light_lightness_linear_tt_handler(struct ble_npl_event *ev)
{
struct light_lightness_state *state = ble_npl_event_get_arg(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));
}
static void light_ctl_tt_handler(struct ble_npl_event *ev)
{
struct light_ctl_state *state = ble_npl_event_get_arg(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));
}
static void light_ctl_temp_tt_handler(struct ble_npl_event *ev)
{
struct light_ctl_state *state = ble_npl_event_get_arg(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));
}
/* Timers related handlers & threads (End) */
/* Messages handlers (Start) */
void onoff_handler(struct generic_onoff_state *state)
{
enable_transition = ONOFF_TT;
ble_npl_callout_set_arg(&onoff_transition_timer, state);
ble_npl_callout_reset(&onoff_transition_timer, K_MSEC(5 * state->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));
}
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));
}
void light_lightness_actual_handler(struct light_lightness_state *state)
{
enable_transition = LIGTH_LIGHTNESS_ACTUAL_TT;
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));
}
void light_lightness_linear_handler(struct light_lightness_state *state)
{
enable_transition = LIGTH_LIGHTNESS_LINEAR_TT;
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));
}
void light_ctl_handler(struct light_ctl_state *state)
{
enable_transition = LIGTH_CTL_TT;
ble_npl_callout_set_arg(&light_ctl_transition_timer, state);
ble_npl_callout_reset(&light_ctl_transition_timer, K_MSEC(5 * state->delay));
}
void light_ctl_temp_handler(struct light_ctl_state *state)
{
enable_transition = LIGHT_CTL_TEMP_TT;
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));
}
/* Messages handlers (End) */
void transition_timers_init(void)
{
ble_npl_callout_init(&onoff_work, ble_npl_eventq_dflt_get(),
onoff_work_handler, NULL);
ble_npl_callout_init(&level_lightness_work, ble_npl_eventq_dflt_get(),
level_lightness_work_handler, NULL);
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(),
light_lightness_actual_work_handler, NULL);
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(),
light_ctl_work_handler, NULL);
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(&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);
}
@@ -0,0 +1,58 @@
/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
*
* Copyright (c) 2018 Vikrant More
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _TRANSITION_H
#define _TRANSITION_H
#define DEVICE_SPECIFIC_RESOLUTION 10
enum transition_time {
DISABLE_TRANSITION = 0x00,
ONOFF_TT = 0x01,
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;
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;
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);
void onoff_handler(struct generic_onoff_state *state);
void level_lightness_handler(struct generic_level_state *state);
void level_temp_handler(struct generic_level_state *state);
void light_lightness_actual_handler(struct light_lightness_state *state);
void light_lightness_linear_handler(struct light_lightness_state *state);
void light_ctl_handler(struct light_ctl_state *state);
void light_ctl_temp_handler(struct light_ctl_state *state);
void transition_timers_init(void);
#endif
+56
View File
@@ -0,0 +1,56 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Package: apps/blemesh
syscfg.vals:
# Set log level to info (disable debug logging).
LOG_LEVEL: 1
# Default task settings
OS_MAIN_STACK_SIZE: 768
# Newtmgr is not supported in this app, so disable newtmgr-over-shell.
SHELL_NEWTMGR: 0
MSYS_1_BLOCK_COUNT: 48
FLOAT_USER: 1
HARD_FLOAT: 1
BLE_MESH_ADV_BUF_COUNT: 20
BLE_MESH_TX_SEG_MAX: 9
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_DEBUG: 0
BLE_MESH_DEBUG_NET: 0
BLE_MESH_DEBUG_TRANS: 0
BLE_MESH_DEBUG_BEACON: 0
BLE_MESH_DEBUG_CRYPTO: 0
BLE_MESH_DEBUG_PROV: 0
BLE_MESH_DEBUG_ACCESS: 0
BLE_MESH_DEBUG_MODEL: 0
BLE_MESH_DEBUG_ADV: 0
BLE_MESH_DEBUG_LOW_POWER: 0
BLE_MESH_DEBUG_FRIEND: 0
BLE_MESH_DEBUG_PROXY: 0