From bdc10744fb338ae197692713a0b48a7ccc36f566 Mon Sep 17 00:00:00 2001 From: JF Date: Sun, 26 Apr 2020 10:25:59 +0200 Subject: Add Nimble in libs directory --- .../apps/blemesh_models_example_2/README.md | 101 + .../apps/blemesh_models_example_2/pkg.yml | 40 + .../apps/blemesh_models_example_2/src/app_gpio.c | 95 + .../apps/blemesh_models_example_2/src/app_gpio.h | 36 + .../apps/blemesh_models_example_2/src/ble_mesh.c | 116 + .../apps/blemesh_models_example_2/src/ble_mesh.h | 73 + .../apps/blemesh_models_example_2/src/common.h | 33 + .../src/device_composition.c | 2779 ++++++++++++++++++++ .../src/device_composition.h | 177 ++ .../apps/blemesh_models_example_2/src/main.c | 250 ++ .../src/no_transition_work_handler.c | 89 + .../src/no_transition_work_handler.h | 34 + .../apps/blemesh_models_example_2/src/publisher.c | 266 ++ .../apps/blemesh_models_example_2/src/publisher.h | 46 + .../blemesh_models_example_2/src/state_binding.c | 308 +++ .../blemesh_models_example_2/src/state_binding.h | 53 + .../apps/blemesh_models_example_2/src/storage.c | 255 ++ .../apps/blemesh_models_example_2/src/storage.h | 47 + .../apps/blemesh_models_example_2/src/transition.c | 792 ++++++ .../apps/blemesh_models_example_2/src/transition.h | 87 + .../apps/blemesh_models_example_2/syscfg.yml | 60 + 21 files changed, 5737 insertions(+) create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/common.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.c create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.h create mode 100644 src/libs/mynewt-nimble/apps/blemesh_models_example_2/syscfg.yml (limited to 'src/libs/mynewt-nimble/apps/blemesh_models_example_2') diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md new file mode 100644 index 00000000..7bec909e --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md @@ -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 Default Transition Time Server +- Generic Default Transition Time 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 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 +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. + diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml new file mode 100644 index 00000000..ee2be6da --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml @@ -0,0 +1,40 @@ +# 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 " +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" + - "@apache-mynewt-core/encoding/base64" + - "@apache-mynewt-core/sys/config" + - nimble/controller + - nimble/host + - nimble/host/services/gap + - nimble/host/services/gatt + - nimble/transport/ram + +pkg.lflags: + - -DFLOAT_SUPPORT + - -lm diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.c new file mode 100644 index 00000000..76e361af --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.c @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/* 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 os_callout button_work; + +static void button_pressed(struct os_event *ev) +{ + os_callout_reset(&button_work, 0); +} + +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 */ + + os_callout_init(&button_work, os_eventq_dflt_get(), publish, NULL); + + 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/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.h new file mode 100644 index 00000000..6eabc1ce --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +/* 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/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.c new file mode 100644 index 00000000..86d4c515 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.c @@ -0,0 +1,116 @@ +/* + * 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. + */ + +/* 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 "common.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) +{ + printk("Local node provisioned, primary address 0x%04x\n", 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"); + + bt_initialized(); +} diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.h new file mode 100644 index 00000000..c02af243 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.h @@ -0,0 +1,73 @@ +/* + * 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. + */ + +/* 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) + +#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); + +#endif + diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/common.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/common.h new file mode 100644 index 00000000..57cd401a --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/common.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/* 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 + +void update_light_state(void); +void bt_initialized(void); + +#endif diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.c new file mode 100644 index 00000000..b638b861 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.c @@ -0,0 +1,2779 @@ +/* + * 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. + */ + +/* 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 "mesh/mesh.h" + +#include "app_gpio.h" +#include "storage.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_ENABLED, + .beacon = BT_MESH_BEACON_ENABLED, + +#if defined(CONFIG_BT_MESH_FRIEND) + .frnd = BT_MESH_FRIEND_ENABLED, +#else + .frnd = BT_MESH_FRIEND_NOT_SUPPORTED, +#endif + +#if defined(CONFIG_BT_MESH_GATT_PROXY) + .gatt_proxy = BT_MESH_GATT_PROXY_ENABLED, +#else + .gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED, +#endif + + .default_ttl = 7, + + /* 2 transmissions with 20ms interval */ + .net_transmit = 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; +static struct bt_mesh_model_pub gen_onoff_cli_pub_root; +static struct bt_mesh_model_pub gen_level_srv_pub_root; +static struct bt_mesh_model_pub gen_level_cli_pub_root; +static struct bt_mesh_model_pub gen_def_trans_time_srv_pub; +static struct bt_mesh_model_pub gen_def_trans_time_cli_pub; +static struct bt_mesh_model_pub gen_power_onoff_srv_pub; +static struct bt_mesh_model_pub gen_power_onoff_cli_pub; +static struct bt_mesh_model_pub light_lightness_srv_pub; +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_level_srv_pub_s0; +static struct bt_mesh_model_pub gen_level_cli_pub_s0; + + +static struct os_mbuf *bt_mesh_pub_msg_health_pub; +static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_srv_pub_root; +static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_cli_pub_root; +static struct os_mbuf *bt_mesh_pub_msg_gen_level_srv_pub_root; +static struct os_mbuf *bt_mesh_pub_msg_gen_level_cli_pub_root; +static struct os_mbuf *bt_mesh_pub_msg_gen_def_trans_time_srv_pub; +static struct os_mbuf *bt_mesh_pub_msg_gen_def_trans_time_cli_pub; +static struct os_mbuf *bt_mesh_pub_msg_gen_power_onoff_srv_pub; +static struct os_mbuf *bt_mesh_pub_msg_gen_power_onoff_cli_pub; +static struct os_mbuf *bt_mesh_pub_msg_light_lightness_srv_pub; +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_level_srv_pub_s0; +static struct os_mbuf *bt_mesh_pub_msg_gen_level_cli_pub_s0; + + +void init_pub(void) +{ + bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(1 + 3 + 0); + bt_mesh_pub_msg_gen_onoff_srv_pub_root = NET_BUF_SIMPLE(2 + 3); + bt_mesh_pub_msg_gen_onoff_cli_pub_root = NET_BUF_SIMPLE(2 + 4); + bt_mesh_pub_msg_gen_level_srv_pub_root = NET_BUF_SIMPLE(2 + 5); + bt_mesh_pub_msg_gen_level_cli_pub_root = NET_BUF_SIMPLE(2 + 7); + bt_mesh_pub_msg_gen_power_onoff_srv_pub = NET_BUF_SIMPLE(2 + 1); + bt_mesh_pub_msg_gen_power_onoff_cli_pub = NET_BUF_SIMPLE(2 + 1); + bt_mesh_pub_msg_gen_def_trans_time_srv_pub = NET_BUF_SIMPLE(2 + 1); + bt_mesh_pub_msg_gen_def_trans_time_cli_pub = NET_BUF_SIMPLE(2 + 1); + bt_mesh_pub_msg_light_lightness_srv_pub = NET_BUF_SIMPLE(2 + 5); + bt_mesh_pub_msg_light_lightness_cli_pub = NET_BUF_SIMPLE(2 + 5); + 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_level_srv_pub_s0 = NET_BUF_SIMPLE(2 + 5); + bt_mesh_pub_msg_gen_level_cli_pub_s0 = NET_BUF_SIMPLE(2 + 7); + + + health_pub.msg = bt_mesh_pub_msg_health_pub; + gen_onoff_srv_pub_root.msg = bt_mesh_pub_msg_gen_onoff_srv_pub_root; + gen_onoff_cli_pub_root.msg = bt_mesh_pub_msg_gen_onoff_cli_pub_root; + gen_level_srv_pub_root.msg = bt_mesh_pub_msg_gen_level_srv_pub_root; + gen_level_cli_pub_root.msg = bt_mesh_pub_msg_gen_level_cli_pub_root; + gen_power_onoff_srv_pub.msg = bt_mesh_pub_msg_gen_power_onoff_srv_pub; + gen_power_onoff_cli_pub.msg = bt_mesh_pub_msg_gen_power_onoff_cli_pub; + gen_def_trans_time_srv_pub.msg = bt_mesh_pub_msg_gen_def_trans_time_srv_pub; + gen_def_trans_time_cli_pub.msg = bt_mesh_pub_msg_gen_def_trans_time_cli_pub; + light_lightness_srv_pub.msg = bt_mesh_pub_msg_light_lightness_srv_pub; + light_lightness_cli_pub.msg = bt_mesh_pub_msg_light_lightness_cli_pub; + 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_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 = { + .transition = &lightness_transition, +}; + +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 = { + .transition = &lightness_transition, +}; + +struct light_ctl_state light_ctl_srv_user_data = { + .transition = &lightness_transition, +}; + +struct vendor_state vnd_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[]; + +/* message handlers (Start) */ + +/* Generic OnOff Server message handlers */ +static void gen_onoff_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4); + struct generic_onoff_state *state = model->user_data; + + 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); + } + + 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); +} + +void gen_onoff_publish(struct bt_mesh_model *model) +{ + int err; + struct os_mbuf *msg = model->pub->msg; + struct generic_onoff_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_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); + } + + err = bt_mesh_model_publish(model); + if (err) { + printk("bt_mesh_model_publish err %d\n", err); + } +} + +static void gen_onoff_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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; + os_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) +{ + 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; + os_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 */ +static void gen_onoff_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from GEN_ONOFF_SRV\n"); + printk("Present OnOff = %02x\n", net_buf_simple_pull_u8(buf)); + + if (buf->om_len == 2) { + printk("Target OnOff = %02x\n", net_buf_simple_pull_u8(buf)); + printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); + } +} + +/* Generic Level Server message handlers */ +static void gen_level_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) { + calculate_rt(state->transition); + net_buf_simple_add_le16(msg, state->target_level); + net_buf_simple_add_u8(msg, state->transition->rt); + } + + 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, 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))) { + 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; + os_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_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 */ + 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_level_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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; + os_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, 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) { + 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; + os_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_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 */ + 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_delta_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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; + os_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, 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))) { + 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; + os_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_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 */ + 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); + } +} + +static void gen_move_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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; + os_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 */ +static void gen_level_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from GEN_LEVEL_SRV\n"); + printk("Present Level = %04x\n", net_buf_simple_pull_le16(buf)); + + if (buf->om_len == 3) { + printk("Target Level = %04x\n", net_buf_simple_pull_le16(buf)); + printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); + } +} + +/* Generic Default Transition Time Server message handlers */ +static void gen_def_trans_time_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + u8_t tt; + struct gen_def_trans_time_state *state = model->user_data; + + tt = net_buf_simple_pull_u8(buf); + + /* Here, Model specification is silent about tid implementation */ + + if ((tt & 0x3F) == 0x3F) { + return false; + } + + if (state->tt != tt) { + state->tt = tt; + default_tt = tt; + + save_on_flash(GEN_DEF_TRANS_TIME_STATE); + } + + return true; +} + +static void gen_def_trans_time_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + if (gen_def_trans_time_setunack(model, ctx, buf) == true) { + gen_def_trans_time_get(model, ctx, buf); + gen_def_trans_time_publish(model); + } +} + +/* Generic Default Transition Time Client message handlers */ +static void gen_def_trans_time_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from GEN_DEF_TT_SRV\n"); + printk("Transition Time = %02x\n", net_buf_simple_pull_u8(buf)); +} + +/* Generic Power OnOff Server message handlers */ +static void gen_onpowerup_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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 */ +static void gen_onpowerup_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from GEN_POWER_ONOFF_SRV\n"); + printk("OnPowerUp = %02x\n", net_buf_simple_pull_u8(buf)); +} + +/* 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 generic_onpowerup_state *state = model->user_data; + + onpowerup = net_buf_simple_pull_u8(buf); + + /* Here, Model specification is silent about tid implementation */ + + if (onpowerup > STATE_RESTORE) { + return false; + } + + if (state->onpowerup != onpowerup) { + state->onpowerup = onpowerup; + + save_on_flash(GEN_ONPOWERUP_STATE); + } + + return true; +} + +static void gen_onpowerup_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + if (gen_onpowerup_setunack(model, ctx, buf) == true) { + gen_onpowerup_publish(model); + } +} + +static void gen_onpowerup_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + if (gen_onpowerup_setunack(model, ctx, buf) == true) { + gen_onpowerup_get(model, ctx, buf); + gen_onpowerup_publish(model); + } +} + +/* Vendor Model message handlers*/ +static void vnd_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(3 + 6 + 4); + struct vendor_state *state = model->user_data; + + /* 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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + u8_t tid; + int current; + s64_t now; + struct vendor_state *state = model->user_data; + + current = 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))) { + return; + } + + state->last_tid = tid; + state->last_src_addr = ctx->addr; + state->last_dst_addr = ctx->recv_dst; + state->last_msg_timestamp = now; + state->current = current; + + printk("Vendor model message = %04x\n", state->current); + + if (state->current == STATE_ON) { + /* LED2 On */ + hal_gpio_write(led_device[1], 0); + } else { + /* LED2 Off */ + hal_gpio_write(led_device[1], 1); + } +} + +static void vnd_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + vnd_set_unack(model, ctx, buf); + vnd_get(model, ctx, buf); +} + +static void vnd_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from Vendor\n"); + printk("cmd = %04x\n", net_buf_simple_pull_le16(buf)); + printk("response = %08lx\n", net_buf_simple_pull_le32(buf)); +} + +/* Light Lightness Server message handlers */ +static void light_lightness_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 light_lightness_state *state = model->user_data; + + 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); + } + + 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, 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))) { + 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; + os_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_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); +} + +static void light_lightness_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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; + os_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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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); + } + + 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, 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))) { + 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; + os_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_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); +} + +static void light_lightness_linear_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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; + os_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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); + struct light_lightness_state *state = model->user_data; + + 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); + + if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + printk("Unable to send LightLightnessRange Status response\n"); + } + + 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) +{ + u16_t lightness; + struct light_lightness_state *state = model->user_data; + + lightness = net_buf_simple_pull_le16(buf); + + /* Here, Model specification is silent about tid implementation */ + + if (state->def != lightness) { + state->def = lightness; + light_ctl_srv_user_data.lightness_def = state->def; + + save_on_flash(LIGHTNESS_TEMP_DEF_STATE); + } + + light_lightness_default_publish(model); +} + +static void light_lightness_default_set(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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) +{ + u16_t min, max; + struct light_lightness_state *state = model->user_data; + + min = net_buf_simple_pull_le16(buf); + max = net_buf_simple_pull_le16(buf); + + /* Here, Model specification is silent about tid implementation */ + + if (min == 0 || max == 0) { + return false; + } else { + if (min <= max) { + state->status_code = RANGE_SUCCESSFULLY_UPDATED; + + if (state->light_range_min != min || + state->light_range_max != max) { + + 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; + return false; + } + } + + return true; +} + +static void light_lightness_range_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + if (light_lightness_range_setunack(model, ctx, buf) == true) { + light_lightness_range_get(model, ctx, buf); + light_lightness_range_publish(model); + } +} + +/* Light Lightness Client message handlers */ +static void light_lightness_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Actual)\n"); + printk("Present Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + + if (buf->om_len == 3) { + printk("Target Lightness = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); + } +} + +static void light_lightness_linear_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Linear)\n"); + printk("Present Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + + if (buf->om_len == 3) { + printk("Target Lightness = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); + } +} + +static void light_lightness_last_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Last)\n"); + printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); +} + +static void light_lightness_default_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Default)\n"); + printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); +} + +static void light_lightness_range_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_LIGHTNESS_SRV (Lightness Range)\n"); + printk("Status Code = %02x\n", net_buf_simple_pull_u8(buf)); + printk("Range Min = %04x\n", net_buf_simple_pull_le16(buf)); + printk("Range Max = %04x\n", net_buf_simple_pull_le16(buf)); +} + +/* Light CTL Server message handlers */ +static void light_ctl_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_LIGHT_CTL_STATUS); + 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); + } + + if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + printk("Unable to send LightCTL Status response\n"); + } + + os_mbuf_free_chain(msg); +} + +void light_ctl_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_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 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))) { + 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; + os_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_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); +} + +static void light_ctl_set(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 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; + os_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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4); + struct light_ctl_state *state = model->user_data; + + 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); + + if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + printk("Unable to send LightCTL Temp Range Status response\n"); + } + + os_mbuf_free_chain(msg); +} + +static void light_ctl_default_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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); + + 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 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); + + /* Here, Model specification is silent about tid implementation */ + + if (temp < TEMP_MIN || temp > TEMP_MAX) { + return false; + } + + if (temp < state->temp_range_min) { + temp = state->temp_range_min; + } else if (temp > state->temp_range_max) { + temp = state->temp_range_max; + } + + 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; + + save_on_flash(LIGHTNESS_TEMP_DEF_STATE); + } + + return true; +} + +static void light_ctl_default_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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); + } +} + +static bool light_ctl_temp_range_setunack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + u16_t min, max; + struct light_ctl_state *state = model->user_data; + + min = net_buf_simple_pull_le16(buf); + max = net_buf_simple_pull_le16(buf); + + /* Here, Model specification is silent about tid implementation */ + + /* This is as per 6.1.3.1 in Mesh Model Specification */ + if (min < TEMP_MIN || min > TEMP_MAX || + max < TEMP_MIN || max > TEMP_MAX) { + return false; + } + + if (min <= max) { + state->status_code = RANGE_SUCCESSFULLY_UPDATED; + + 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; + } + + return true; +} + +static void light_ctl_temp_range_set_unack(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *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, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + if (light_ctl_temp_range_setunack(model, ctx, buf) == true) { + light_ctl_temp_range_get(model, ctx, buf); + light_ctl_temp_range_publish(model); + } +} + +/* Light CTL Client message handlers */ +static void light_ctl_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_CTL_SRV\n"); + printk("Present CTL Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + printk("Present CTL Temperature = %04x\n", + net_buf_simple_pull_le16(buf)); + + if (buf->om_len == 5) { + printk("Target CTL Lightness = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Target CTL Temperature = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); + } +} + +static void light_ctl_temp_range_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_CTL_SRV (Temperature Range)\n"); + printk("Status Code = %02x\n", net_buf_simple_pull_u8(buf)); + printk("Range Min = %04x\n", net_buf_simple_pull_le16(buf)); + printk("Range Max = %04x\n", net_buf_simple_pull_le16(buf)); +} + +static void light_ctl_temp_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_CTL_TEMP_SRV\n"); + printk("Present CTL Temperature = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Present CTL Delta UV = %04x\n", + net_buf_simple_pull_le16(buf)); + + if (buf->om_len == 5) { + printk("Target CTL Temperature = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Target CTL Delta UV = %04x\n", + net_buf_simple_pull_le16(buf)); + printk("Remaining Time = %02x\n", net_buf_simple_pull_u8(buf)); + } +} + +static void light_ctl_default_status(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + printk("Acknownledgement from LIGHT_CTL_SRV (Default)\n"); + printk("Lightness = %04x\n", net_buf_simple_pull_le16(buf)); + printk("Temperature = %04x\n", net_buf_simple_pull_le16(buf)); + printk("Delta UV = %04x\n", net_buf_simple_pull_le16(buf)); +} + +/* Light CTL Temp. Server message handlers */ +static void light_ctl_temp_get(struct bt_mesh_model *model, + struct bt_mesh_msg_ctx *ctx, + struct os_mbuf *buf) +{ + 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_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); + } + + if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) { + printk("Unable to send LightCTL Temp. Status response\n"); + } + + os_mbuf_free_chain(msg); +} + +void light_ctl_temp_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_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 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))) { + 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; + os_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_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); +} + +static void light_ctl_temp_set(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 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; + os_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) */ + +/* Mapping of message handlers for Generic OnOff Server (0x1000) */ +static const struct bt_mesh_model_op gen_onoff_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x01), 0, gen_onoff_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x02), 2, gen_onoff_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x03), 2, gen_onoff_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic OnOff Client (0x1001) */ +static const struct bt_mesh_model_op gen_onoff_cli_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x04), 1, gen_onoff_status }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Levl Server (0x1002) */ +static const struct bt_mesh_model_op gen_level_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x05), 0, gen_level_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x06), 3, gen_level_set }, + { 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), 3, gen_move_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x0C), 3, gen_move_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Level Client (0x1003) */ +static const struct bt_mesh_model_op gen_level_cli_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x08), 2, gen_level_status }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Default TT Server (0x1004) */ +static const struct bt_mesh_model_op gen_def_trans_time_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x0D), 0, gen_def_trans_time_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x0E), 1, gen_def_trans_time_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x0F), 1, gen_def_trans_time_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Default TT Client (0x1005) */ +static const struct bt_mesh_model_op gen_def_trans_time_cli_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x10), 1, gen_def_trans_time_status }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Power OnOff Server (0x1006) */ +static const struct bt_mesh_model_op gen_power_onoff_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x11), 0, gen_onpowerup_get }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Power OnOff Setup Server (0x1007) */ +static const struct bt_mesh_model_op gen_power_onoff_setup_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x13), 1, gen_onpowerup_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x14), 1, gen_onpowerup_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Generic Power OnOff Client (0x1008) */ +static const struct bt_mesh_model_op gen_power_onoff_cli_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x12), 1, gen_onpowerup_status }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Light Lightness Server (0x1300) */ +static const struct bt_mesh_model_op light_lightness_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x4B), 0, light_lightness_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x4C), 3, light_lightness_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x4D), 3, light_lightness_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x4F), 0, light_lightness_linear_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x50), 3, light_lightness_linear_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x51), 3, + light_lightness_linear_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x53), 0, light_lightness_last_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x55), 0, light_lightness_default_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x57), 0, light_lightness_range_get }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Light Lightness Setup Server (0x1301) */ +static const struct bt_mesh_model_op light_lightness_setup_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x59), 2, light_lightness_default_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x5A), 2, + light_lightness_default_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x5B), 4, light_lightness_range_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x5C), 4, light_lightness_range_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Light Lightness Client (0x1302) */ +static const struct bt_mesh_model_op light_lightness_cli_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x4E), 2, light_lightness_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x52), 2, light_lightness_linear_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x54), 2, light_lightness_last_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x56), 2, light_lightness_default_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x58), 5, light_lightness_range_status }, + BT_MESH_MODEL_OP_END, +}; + +/* 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), 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, +}; + +/* Mapping of message handlers for Light CTL Setup Server (0x1304) */ +static const struct bt_mesh_model_op light_ctl_setup_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x69), 6, light_ctl_default_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x6A), 6, light_ctl_default_set_unack }, + { BT_MESH_MODEL_OP_2(0x82, 0x6B), 4, light_ctl_temp_range_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x6C), 4, light_ctl_temp_range_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Light CTL Client (0x1305) */ +static const struct bt_mesh_model_op light_ctl_cli_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x60), 4, light_ctl_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x63), 5, light_ctl_temp_range_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x66), 4, light_ctl_temp_status }, + { BT_MESH_MODEL_OP_2(0x82, 0x68), 6, light_ctl_default_status }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Light CTL Temp. Server (0x1306) */ +static const struct bt_mesh_model_op light_ctl_temp_srv_op[] = { + { BT_MESH_MODEL_OP_2(0x82, 0x61), 0, light_ctl_temp_get }, + { BT_MESH_MODEL_OP_2(0x82, 0x64), 5, light_ctl_temp_set }, + { BT_MESH_MODEL_OP_2(0x82, 0x65), 5, light_ctl_temp_set_unack }, + BT_MESH_MODEL_OP_END, +}; + +/* Mapping of message handlers for Vendor (0x4321) */ +static const struct bt_mesh_model_op vnd_ops[] = { + { 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, +}; + +struct bt_mesh_model root_models[] = { + BT_MESH_MODEL_CFG_SRV(&cfg_srv), + BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, + gen_onoff_srv_op, &gen_onoff_srv_pub_root, + &gen_onoff_srv_root_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, + gen_onoff_cli_op, &gen_onoff_cli_pub_root, + NULL), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, + gen_level_srv_op, &gen_level_srv_pub_root, + &gen_level_srv_root_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_CLI, + gen_level_cli_op, &gen_level_cli_pub_root, + NULL), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV, + gen_def_trans_time_srv_op, + &gen_def_trans_time_srv_pub, + &gen_def_trans_time_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI, + gen_def_trans_time_cli_op, + &gen_def_trans_time_cli_pub, + NULL), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV, + gen_power_onoff_srv_op, &gen_power_onoff_srv_pub, + &gen_power_onoff_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV, + gen_power_onoff_setup_srv_op, + &gen_power_onoff_srv_pub, + &gen_power_onoff_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI, + gen_power_onoff_cli_op, &gen_power_onoff_cli_pub, + NULL), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV, + light_lightness_srv_op, &light_lightness_srv_pub, + &light_lightness_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV, + light_lightness_setup_srv_op, + &light_lightness_srv_pub, + &light_lightness_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI, + light_lightness_cli_op, &light_lightness_cli_pub, + NULL), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_CTL_SRV, + light_ctl_srv_op, &light_ctl_srv_pub, + &light_ctl_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV, + light_ctl_setup_srv_op, &light_ctl_srv_pub, + &light_ctl_srv_user_data), + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_CTL_CLI, + light_ctl_cli_op, &light_ctl_cli_pub, + NULL), +}; + +struct bt_mesh_model vnd_models[] = { + BT_MESH_MODEL_VND(CID_RUNTIME, 0x4321, vnd_ops, + &vnd_pub, &vnd_user_data), +}; + +struct bt_mesh_model s0_models[] = { + 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), + BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_CLI, + gen_level_cli_op, &gen_level_cli_pub_s0, + NULL), + + BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV, + light_ctl_temp_srv_op, &light_ctl_srv_pub, + &light_ctl_srv_user_data), +}; + +static struct bt_mesh_elem elements[] = { + BT_MESH_ELEM(0, root_models, vnd_models), + BT_MESH_ELEM(0, s0_models, BT_MESH_MODEL_NONE), +}; + +const struct bt_mesh_comp comp = { + .cid = CID_RUNTIME, + .elem = elements, + .elem_count = ARRAY_SIZE(elements), +}; + diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.h new file mode 100644 index 00000000..38507195 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.h @@ -0,0 +1,177 @@ +/* + * 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. + */ + +/* 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 + +struct generic_onoff_state { + u8_t onoff; + u8_t target_onoff; + + u8_t last_tid; + u16_t last_src_addr; + u16_t last_dst_addr; + s64_t last_msg_timestamp; + + s32_t tt_delta; + + struct transition *transition; +}; + +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_src_addr; + u16_t last_dst_addr; + s64_t last_msg_timestamp; + + s32_t tt_delta; + + struct transition *transition; +}; + +struct generic_onpowerup_state { + u8_t onpowerup; +}; + +struct gen_def_trans_time_state { + u8_t tt; +}; + +struct vendor_state { + int current; + u32_t response; + u8_t last_tid; + u16_t last_src_addr; + u16_t last_dst_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; + u32_t lightness_range; + + u8_t last_tid; + 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; + + struct transition *transition; +}; + +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; + u32_t temperature_range; + + u16_t lightness_def; + u16_t temp_def; + u32_t lightness_temp_def; + s16_t delta_uv_def; + + u32_t lightness_temp_last; + + u8_t last_tid; + u16_t last_src_addr; + u16_t last_dst_addr; + s64_t last_msg_timestamp; + + s32_t tt_delta_lightness; + s32_t tt_delta_temp; + s32_t tt_delta_duv; + + struct transition *transition; +}; + +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; + +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/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c new file mode 100644 index 00000000..7c8d65e6 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c @@ -0,0 +1,250 @@ +/* + * 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. + */ + +/* 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 "mesh/mesh.h" + +#include "app_gpio.h" +#include "storage.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" + +static bool reset; + +static void light_default_var_init(void) +{ + gen_def_trans_time_srv_user_data.tt = 0x00; + + 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 */ + 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; + + 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; + + /* Retrieve Range of Lightness & Temperature */ + + 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); + + 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) lightness / 65535); + color = 100 * ((float) (temperature + 32768) / 65535); + + printk("power-> %d, color-> %d\n", power, color); + + if (lightness) { + /* 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); + } + + if (*ptr_counter == 0 || reset == false) { + reset = true; + os_callout_reset(&no_transition_work, 0); + } +} + +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 os_event *dummy) +{ + reset_counter = 0; + save_on_flash(RESET_COUNTER); + printk("Reset Counter set to Zero\n"); +} + +struct os_callout reset_counter_timer; + +static void init_timers(void) +{ + + os_callout_init(&reset_counter_timer, os_eventq_dflt_get(), + reset_counter_timer_handler, NULL); + os_callout_reset(&reset_counter_timer, + os_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) +{ +#ifdef ARCH_sim + mcu_sim_parse_args(argc, argv); +#endif + + /* Initialize OS */ + sysinit(); + + light_default_var_init(); + + app_gpio_init(); + + init_timers(); + + transition_timers_init(); + + init_pub(); + + ps_settings_init(); + + 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; + + while (1) { + os_eventq_run(os_eventq_dflt_get()); + } + + return 0; +} diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.c new file mode 100644 index 00000000..58630bdc --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.c @@ -0,0 +1,89 @@ +/* + * 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. + */ + +/* 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 os_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 os_callout unsolicitedly_publish_states_work; + +static void unsolicitedly_publish_states_timer_handler(struct os_event *dummy) +{ + os_callout_reset(&unsolicitedly_publish_states_work, 0); +} + +struct os_callout unsolicitedly_publish_states_timer; + +static void save_lightness_temp_last_values_timer_handler(struct os_event *dummy) +{ + save_on_flash(LIGHTNESS_TEMP_LAST_STATE); +} + +struct os_callout save_lightness_temp_last_values_timer; + +static void no_transition_work_handler(struct os_event *work) +{ + os_callout_reset(&unsolicitedly_publish_states_timer, + os_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) { + os_callout_reset(&save_lightness_temp_last_values_timer, + os_time_ms_to_ticks32( + K_MSEC(10000))); + } +} + +struct os_callout no_transition_work; + +void no_transition_work_init(void) +{ + os_callout_init(&no_transition_work, os_eventq_dflt_get(), + no_transition_work_handler, NULL); + os_callout_init(&save_lightness_temp_last_values_timer, + os_eventq_dflt_get(), + save_lightness_temp_last_values_timer_handler, + NULL); + os_callout_init(&unsolicitedly_publish_states_work, os_eventq_dflt_get(), + unsolicitedly_publish_states_work_handler, NULL); + os_callout_init(&unsolicitedly_publish_states_timer, os_eventq_dflt_get(), + unsolicitedly_publish_states_timer_handler, NULL); +} diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.h new file mode 100644 index 00000000..a747dfda --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +/* 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 os_callout no_transition_work; + +void no_transition_work_init(void); + +#endif diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.c new file mode 100644 index 00000000..21364b81 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.c @@ -0,0 +1,266 @@ +/* + * 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. + */ + +/* 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 "app_gpio.h" + +#include "ble_mesh.h" +#include "device_composition.h" +#include "publisher.h" + +#define ONOFF +#define GENERIC_LEVEL +/* #define LIGHT_CTL */ +/* #define LIGHT_CTL_TEMP */ + +static bool is_randomization_of_TIDs_done; + +#if (defined(ONOFF) || defined(ONOFF_TT)) +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) || defined(ONOFF_TT)) + 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 os_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(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]); +#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(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]); +#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(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); + 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); + } +} + diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.h new file mode 100644 index 00000000..09b740b4 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.h @@ -0,0 +1,46 @@ +/* + * 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. + */ + +/* 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 os_event *work); + +#endif diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.c new file mode 100644 index 00000000..ae539433 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.c @@ -0,0 +1,308 @@ +/* + * 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. + */ + +/* Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models + * + * Copyright (c) 2018 Vikrant More + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include + +#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) +{ + s32_t inum; + + inum = (s32_t) num; + if (num == (float) inum) { + return inum; + } + + return inum + 1; +} + +u16_t actual_to_linear(u16_t val) +{ + float tmp; + + 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; + } + + target_lightness = var; +} + +static s16_t light_ctl_temp_to_level(u16_t temp) +{ + float tmp; + + /* 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: + temperature = gen_level_srv_s0_user_data.level; + light_ctl_srv_user_data.temp = + level_to_light_ctl_temp(temperature); + break; + default: + break; + } + + switch (light) { + case ONPOWERUP: + if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) { + lightness = 0U; + } else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) { + lightness = light_lightness_srv_user_data.last; + } + break; + case ONOFF: + if (gen_onoff_srv_root_user_data.onoff == STATE_OFF) { + lightness = 0U; + } else if (gen_onoff_srv_root_user_data.onoff == STATE_ON) { + if (light_lightness_srv_user_data.def == 0) { + lightness = light_lightness_srv_user_data.last; + } else { + 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; + } + + 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 { + tmp = light_lightness_srv_user_data.def; + } + } + break; + case LEVEL: + tmp = gen_level_srv_root_user_data.target_level + 32768; + break; + case ACTUAL: + tmp = light_lightness_srv_user_data.target_actual; + break; + 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; + } + + constrain_target_lightness(tmp); + + 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.target_level = target_lightness - 32768; + + 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/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.h new file mode 100644 index 00000000..db1f2a2e --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.h @@ -0,0 +1,53 @@ +/* + * 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. + */ + +/* 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 + +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/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.c new file mode 100644 index 00000000..86fec7cc --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.c @@ -0,0 +1,255 @@ +/* + * 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. + */ + +/* 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 os_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 os_callout storage_work; + +void save_on_flash(u8_t id) +{ + storage_id = id; + os_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; + + os_callout_init(&storage_work, os_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/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.h new file mode 100644 index 00000000..e2905048 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.h @@ -0,0 +1,47 @@ +/* + * 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. + */ + +/* 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 os_callout storage_work; + +int ps_settings_init(void); +void save_on_flash(u8_t id); + +#endif diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.c b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.c new file mode 100644 index 00000000..c9463e10 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.c @@ -0,0 +1,792 @@ +/* + * 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. + */ + +/* 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 "common.h" +#include "device_composition.h" +#include "state_binding.h" +#include "transition.h" + +struct os_callout onoff_work; +struct os_callout level_lightness_work; +struct os_callout level_temp_work; +struct os_callout light_lightness_actual_work; +struct os_callout light_lightness_linear_work; +struct os_callout light_ctl_work; +struct os_callout light_ctl_temp_work; + +struct os_callout dummy_timer; + +u8_t transition_type, default_tt; +u32_t *ptr_counter; +struct os_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; + + resolution = (transition->tt >> 6); + steps_multiplier = (transition->tt & 0x3F); + + switch (resolution) { + case 0: /* 100ms */ + transition->total_duration = steps_multiplier * 100; + break; + case 1: /* 1 second */ + transition->total_duration = steps_multiplier * 1000; + break; + case 2: /* 10 seconds */ + transition->total_duration = steps_multiplier * 10000; + break; + case 3: /* 10 minutes */ + transition->total_duration = steps_multiplier * 600000; + break; + } + + transition->counter = ((float) transition->total_duration / 100); + + if (transition->counter > DEVICE_SPECIFIC_RESOLUTION) { + transition->counter = DEVICE_SPECIFIC_RESOLUTION; + } + + ptr_counter = &transition->counter; +} + +void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay) +{ + 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, u8_t tt, u8_t delay) +{ + 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) / + state->transition->counter); +} + +void light_lightness_actual_tt_values(struct light_lightness_state *state, + u8_t tt, u8_t delay) +{ + bound_states_transition_type_reassignment(ACTUAL); + calculate_lightness_target_values(ACTUAL); + 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_actual = + ((float) (state->actual - state->target_actual) / + state->transition->counter); +} + +void light_lightness_linear_tt_values(struct light_lightness_state *state, + u8_t tt, u8_t delay) +{ + bound_states_transition_type_reassignment(LINEAR); + calculate_lightness_target_values(LINEAR); + 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_linear = + ((float) (state->linear - state->target_linear) / + state->transition->counter); +} + +void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay) +{ + bound_states_transition_type_reassignment(CTL); + calculate_lightness_target_values(CTL); + 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_lightness = + ((float) (state->lightness - state->target_lightness) / + state->transition->counter); + + 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) / + state->transition->counter); +} + +void light_ctl_temp_tt_values(struct light_ctl_state *state, + u8_t tt, u8_t delay) +{ + bound_states_transition_type_reassignment(CTL_TEMP); + calculate_temp_target_values(CTL_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_temp = ((float) (state->temp - state->target_temp) / + state->transition->counter); + + state->tt_delta_duv = + ((float) (state->delta_uv - state->target_delta_uv) / + state->transition->counter); +} + +/* Timers related handlers & threads (Start) */ +static void onoff_work_handler(struct os_event *work) +{ + struct generic_onoff_state *state = &gen_onoff_srv_root_user_data; + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(ONOFF, IGNORE_TEMP); + update_light_state(); + + os_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->transition->counter != 0) { + state->transition->counter--; + + 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(); + + os_callout_stop(ptr_timer); + } +} + +static void level_lightness_work_handler(struct os_event *work) +{ + u8_t level; + struct generic_level_state *state = &gen_level_srv_root_user_data; + + switch (transition_type) { + case LEVEL_TT: + level = LEVEL; + break; + case LEVEL_TT_DELTA: + level = DELTA_LEVEL; + break; + case LEVEL_TT_MOVE: + level = LEVEL; + break; + default: + return; + } + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(level, IGNORE_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + + return; + } + + 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); + update_light_state(); + + os_callout_stop(ptr_timer); + } +} + +static void level_temp_work_handler(struct os_event *work) +{ + struct generic_level_state *state = &gen_level_srv_s0_user_data; + + switch (transition_type) { + case LEVEL_TEMP_TT: + break; + case LEVEL_TEMP_TT_DELTA: + break; + case LEVEL_TEMP_TT_MOVE: + break; + default: + return; + } + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(IGNORE, LEVEL_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + + return; + } + + 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(); + + os_callout_stop(ptr_timer); + } +} + +static void light_lightness_actual_work_handler(struct os_event *work) +{ + struct light_lightness_state *state = &light_lightness_srv_user_data; + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(ACTUAL, IGNORE_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + + return; + } + + if (state->transition->counter != 0) { + state->transition->counter--; + + state->actual -= state->tt_delta_actual; + + state_binding(ACTUAL, IGNORE_TEMP); + update_light_state(); + } + + if (state->transition->counter == 0) { + state->actual = state->target_actual; + + state_binding(ACTUAL, IGNORE_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } +} + +static void light_lightness_linear_work_handler(struct os_event *work) +{ + struct light_lightness_state *state = &light_lightness_srv_user_data; + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(LINEAR, IGNORE_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + + return; + } + + if (state->transition->counter != 0) { + state->transition->counter--; + + state->linear -= state->tt_delta_linear; + + state_binding(LINEAR, IGNORE_TEMP); + update_light_state(); + } + + if (state->transition->counter == 0) { + state->linear = state->target_linear; + + state_binding(LINEAR, IGNORE_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } +} + +static void light_ctl_work_handler(struct os_event *work) +{ + struct light_ctl_state *state = &light_ctl_srv_user_data; + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(CTL, CTL_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + + return; + } + + if (state->transition->counter != 0) { + state->transition->counter--; + + /* Lightness */ + state->lightness -= state->tt_delta_lightness; + + /* Temperature */ + state->temp -= state->tt_delta_temp; + + /* Delta_UV */ + state->delta_uv -= state->tt_delta_duv; + + state_binding(CTL, CTL_TEMP); + update_light_state(); + } + + if (state->transition->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(); + + os_callout_stop(ptr_timer); + } +} + +static void light_ctl_temp_work_handler(struct os_event *work) +{ + struct light_ctl_state *state = &light_ctl_srv_user_data; + + if (state->transition->just_started) { + state->transition->just_started = false; + + if (state->transition->counter == 0) { + state_binding(IGNORE, CTL_TEMP); + update_light_state(); + + os_callout_stop(ptr_timer); + } else { + state->transition->start_timestamp = k_uptime_get(); + } + + return; + } + + if (state->transition->counter != 0) { + state->transition->counter--; + + /* Temperature */ + state->temp -= state->tt_delta_temp; + + /* Delta UV */ + state->delta_uv -= state->tt_delta_duv; + + state_binding(IGNORE, CTL_TEMP); + update_light_state(); + } + + 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(); + + os_callout_stop(ptr_timer); + } +} + +static void dummy_timer_handler(struct os_event *ev) +{ } + +static void onoff_tt_handler(struct os_event *ev) +{ + struct generic_onoff_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&onoff_work, 0); + os_callout_reset(&state->transition->timer, + os_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); +} + +static void level_lightness_tt_handler(struct os_event *ev) +{ + struct generic_level_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&level_lightness_work, 0); + os_callout_reset(&state->transition->timer, + os_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); +} + +static void level_temp_tt_handler(struct os_event *ev) +{ + struct generic_level_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&level_temp_work, 0); + os_callout_reset(&state->transition->timer, + os_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); +} + +static void light_lightness_actual_tt_handler(struct os_event *ev) +{ + struct light_lightness_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&light_lightness_actual_work, 0); + os_callout_reset(&state->transition->timer, + os_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); +} + +static void light_lightness_linear_tt_handler(struct os_event *ev) +{ + struct light_lightness_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&light_lightness_linear_work, 0); + os_callout_reset(&state->transition->timer, + os_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); +} + +static void light_ctl_tt_handler(struct os_event *ev) +{ + struct light_ctl_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&light_ctl_work, 0); + os_callout_reset(&state->transition->timer, + os_time_ms_to_ticks32( + K_MSEC(state->transition->quo_tt))); +} + +static void light_ctl_temp_tt_handler(struct os_event *ev) +{ + struct light_ctl_state *state = ev->ev_arg; + + assert(state != NULL); + os_callout_reset(&light_ctl_temp_work, 0); + os_callout_reset(&state->transition->timer, + os_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) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + onoff_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} + +void level_lightness_handler(struct generic_level_state *state) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + level_lightness_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} + +void level_temp_handler(struct generic_level_state *state) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + level_temp_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} + +void light_lightness_actual_handler(struct light_lightness_state *state) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + light_lightness_actual_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} + +void light_lightness_linear_handler(struct light_lightness_state *state) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + light_lightness_linear_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} + +void light_ctl_handler(struct light_ctl_state *state) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + light_ctl_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} + +void light_ctl_temp_handler(struct light_ctl_state *state) +{ + ptr_timer = &state->transition->timer; + + os_callout_init(ptr_timer, os_eventq_dflt_get(), + light_ctl_temp_tt_handler, NULL); + ptr_timer->c_ev.ev_arg = state; + os_callout_reset(ptr_timer, + os_time_ms_to_ticks32( + K_MSEC(5 * state->transition->delay))); +} +/* Messages handlers (End) */ + +void transition_timers_init(void) +{ + os_callout_init(&onoff_work, os_eventq_dflt_get(), + onoff_work_handler, NULL); + + os_callout_init(&level_lightness_work, os_eventq_dflt_get(), + level_lightness_work_handler, NULL); + os_callout_init(&level_temp_work, os_eventq_dflt_get(), + level_temp_work_handler, NULL); + + os_callout_init(&light_lightness_actual_work, + os_eventq_dflt_get(), + light_lightness_actual_work_handler, NULL); + os_callout_init(&light_lightness_linear_work, + os_eventq_dflt_get(), + light_lightness_linear_work_handler, NULL); + + os_callout_init(&light_ctl_work, os_eventq_dflt_get(), + light_ctl_work_handler, NULL); + os_callout_init(&light_ctl_temp_work, os_eventq_dflt_get(), + light_ctl_temp_work_handler, NULL); + + os_callout_init(&dummy_timer, os_eventq_dflt_get(), + dummy_timer_handler, NULL); +} + diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.h b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.h new file mode 100644 index 00000000..84101395 --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.h @@ -0,0 +1,87 @@ +/* + * 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. + */ + +/* 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 UNKNOWN_VALUE 0x3F +#define DEVICE_SPECIFIC_RESOLUTION 10 + +enum level_transition_types { + LEVEL_TT, + LEVEL_TT_DELTA, + LEVEL_TT_MOVE, + + LEVEL_TEMP_TT, + LEVEL_TEMP_TT_DELTA, + LEVEL_TEMP_TT_MOVE, +}; + +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; + + struct os_callout timer; +}; + +extern u8_t transition_type, default_tt; +extern u32_t *ptr_counter; +extern struct os_callout *ptr_timer; + +extern struct transition lightness_transition, temp_transition; + +extern struct os_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); +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 diff --git a/src/libs/mynewt-nimble/apps/blemesh_models_example_2/syscfg.yml b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/syscfg.yml new file mode 100644 index 00000000..b56e9d2d --- /dev/null +++ b/src/libs/mynewt-nimble/apps/blemesh_models_example_2/syscfg.yml @@ -0,0 +1,60 @@ +# 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. +# + +syscfg.vals: + # Set log level to info (disable debug logging). + LOG_LEVEL: 1 + + # Default task settings + OS_MAIN_STACK_SIZE: 4096 + + # SMP is not supported in this app, so disable smp-over-shell. + SHELL_MGMT: 0 + + MSYS_1_BLOCK_COUNT: 48 + + FLOAT_USER: 1 + HARD_FLOAT: 1 + + 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_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 -- cgit v1.2.3