summaryrefslogtreecommitdiff
path: root/src/libs/mynewt-nimble/apps/blemesh_models_example_2
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/mynewt-nimble/apps/blemesh_models_example_2')
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/README.md101
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/pkg.yml40
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.c95
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/app_gpio.h36
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.c116
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/ble_mesh.h73
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/common.h33
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.c2779
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/device_composition.h177
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/main.c250
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.c89
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/no_transition_work_handler.h34
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.c266
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/publisher.h46
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.c308
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/state_binding.h53
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.c255
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/storage.h47
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.c792
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/src/transition.h87
-rw-r--r--src/libs/mynewt-nimble/apps/blemesh_models_example_2/syscfg.yml60
21 files changed, 5737 insertions, 0 deletions
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 <discovered UUID>
+menu config
+target 0100
+appkey-add 1
+bind 0 1 1000
+bind 0 1 1001
+bind 0 1 1002
+bind 0 1 1003
+sub-add 0100 c000 1000
+sub-add 0100 c000 1002
+pub-set 0100 c000 1 0 5 1001
+pub-set 0100 c000 1 0 5 1003
+```
+
+The meshctl utility maintains a persistent JSON database containing
+the mesh configuration. As additional nodes (boards) are provisioned, it
+assigns sequential unicast addresses based on the number of elements
+supported by the node. This example supports 2 elements per node.
+
+The meshctl target for configuration must be the root element's unicast
+address as it is the only one that has a configuration server model. If
+meshctl is gracefully exited, it can be restarted and reconnected to
+network 0x0.
+
+The meshctl utility also supports a onoff model client that can be used to
+change the state of any LED that is bound to application key 0x1.
+This is done by setting the target to the unicast address of the element
+that has that LED's model and issuing the onoff command.
+Group addresses are not supported.
+
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 <michal.narajowski@codecoup.pl>"
+pkg.homepage: "http://mynewt.apache.org/"
+pkg.keywords:
+
+pkg.deps:
+ - "@apache-mynewt-core/kernel/os"
+ - "@apache-mynewt-core/sys/console/full"
+ - "@apache-mynewt-core/sys/log/full"
+ - "@apache-mynewt-core/sys/stats/full"
+ - "@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 <math.h>
+
+#include "ble_mesh.h"
+#include "device_composition.h"
+#include "state_binding.h"
+#include "transition.h"
+
+
+u16_t lightness, target_lightness;
+s16_t temperature, target_temperature;
+
+static s32_t ceiling(float num)
+{
+ 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