add nimble mesh example
need meshctl installed on raspberrypi. nimble offical samples have a lot of pit ...
This commit is contained in:
564
examples/nimble_mesh/main.c
Normal file
564
examples/nimble_mesh/main.c
Normal file
@@ -0,0 +1,564 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include "mesh/mesh.h"
|
||||
#include "console/console.h"
|
||||
#if 0
|
||||
#include "hal/hal_system.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "bsp/bsp.h"
|
||||
#include "shell/shell.h"
|
||||
#endif
|
||||
|
||||
///////////////////////
|
||||
// stub-s
|
||||
#define LED_1 17
|
||||
#define LED_2 18
|
||||
#define LED_3 19
|
||||
#define LED_4 20
|
||||
|
||||
void hal_gpio_init_out(int led, int s)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void hal_gpio_write(int led, int s)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int __atomic_load_4(int *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
int __atomic_fetch_and_4(int *p, int v)
|
||||
{
|
||||
return *p & v;
|
||||
}
|
||||
|
||||
int __atomic_fetch_or_4(int *p, int v)
|
||||
{
|
||||
return *p | v;
|
||||
}
|
||||
|
||||
int __atomic_exchange_4(int *p, int v)
|
||||
{
|
||||
int old = *p;
|
||||
*p = v;
|
||||
return old;
|
||||
}
|
||||
|
||||
void unreachable(void)
|
||||
{
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "mesh/glue.h"
|
||||
|
||||
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG))
|
||||
|
||||
/* Company ID */
|
||||
#define CID_VENDOR 0x05C3
|
||||
#define STANDARD_TEST_ID 0x00
|
||||
#define TEST_ID 0x01
|
||||
static int recent_test_id = STANDARD_TEST_ID;
|
||||
|
||||
#define FAULT_ARR_SIZE 2
|
||||
|
||||
static bool has_reg_fault = true;
|
||||
|
||||
static struct bt_mesh_cfg_srv cfg_srv = {
|
||||
.relay = BT_MESH_RELAY_DISABLED,
|
||||
.beacon = BT_MESH_BEACON_ENABLED,
|
||||
#if MYNEWT_VAL(BLE_MESH_FRIEND)
|
||||
.frnd = BT_MESH_FRIEND_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
#if MYNEWT_VAL(BLE_MESH_GATT_PROXY)
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_ENABLED,
|
||||
#else
|
||||
.gatt_proxy = BT_MESH_GATT_PROXY_NOT_SUPPORTED,
|
||||
#endif
|
||||
.default_ttl = 7,
|
||||
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = BT_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
static int
|
||||
fault_get_cur(struct bt_mesh_model *model,
|
||||
uint8_t *test_id,
|
||||
uint16_t *company_id,
|
||||
uint8_t *faults,
|
||||
uint8_t *fault_count)
|
||||
{
|
||||
uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff };
|
||||
|
||||
console_printf("fault_get_cur() has_reg_fault %u\n", has_reg_fault);
|
||||
|
||||
*test_id = recent_test_id;
|
||||
*company_id = CID_VENDOR;
|
||||
|
||||
*fault_count = min(*fault_count, sizeof(reg_faults));
|
||||
memcpy(faults, reg_faults, *fault_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fault_get_reg(struct bt_mesh_model *model,
|
||||
uint16_t company_id,
|
||||
uint8_t *test_id,
|
||||
uint8_t *faults,
|
||||
uint8_t *fault_count)
|
||||
{
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
console_printf("fault_get_reg() has_reg_fault %u\n", has_reg_fault);
|
||||
|
||||
*test_id = recent_test_id;
|
||||
|
||||
if (has_reg_fault) {
|
||||
uint8_t reg_faults[FAULT_ARR_SIZE] = { [0 ... FAULT_ARR_SIZE-1] = 0xff };
|
||||
|
||||
*fault_count = min(*fault_count, sizeof(reg_faults));
|
||||
memcpy(faults, reg_faults, *fault_count);
|
||||
} else {
|
||||
*fault_count = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fault_clear(struct bt_mesh_model *model, uint16_t company_id)
|
||||
{
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
has_reg_fault = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
fault_test(struct bt_mesh_model *model, uint8_t test_id, uint16_t company_id)
|
||||
{
|
||||
if (company_id != CID_VENDOR) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
if (test_id != STANDARD_TEST_ID && test_id != TEST_ID) {
|
||||
return -BLE_HS_EINVAL;
|
||||
}
|
||||
|
||||
recent_test_id = test_id;
|
||||
has_reg_fault = true;
|
||||
bt_mesh_fault_update(bt_mesh_model_elem(model));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct bt_mesh_health_srv_cb health_srv_cb = {
|
||||
.fault_get_cur = &fault_get_cur,
|
||||
.fault_get_reg = &fault_get_reg,
|
||||
.fault_clear = &fault_clear,
|
||||
.fault_test = &fault_test,
|
||||
};
|
||||
|
||||
static struct bt_mesh_health_srv health_srv = {
|
||||
.cb = &health_srv_cb,
|
||||
};
|
||||
|
||||
static struct bt_mesh_model_pub health_pub;
|
||||
|
||||
static void
|
||||
health_pub_init(void)
|
||||
{
|
||||
health_pub.msg = BT_MESH_HEALTH_FAULT_MSG(0);
|
||||
}
|
||||
|
||||
static struct bt_mesh_model_pub gen_level_pub;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub;
|
||||
|
||||
static uint8_t gen_on_off_state;
|
||||
static int16_t gen_level_state;
|
||||
|
||||
static void gen_onoff_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
|
||||
uint8_t *status;
|
||||
|
||||
console_printf("#mesh-onoff STATUS\n");
|
||||
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x04));
|
||||
status = net_buf_simple_add(msg, 1);
|
||||
*status = gen_on_off_state;
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
console_printf("#mesh-onoff STATUS: send status failed\n");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static void gen_onoff_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-onoff GET\n");
|
||||
|
||||
gen_onoff_status(model, ctx);
|
||||
}
|
||||
|
||||
static void gen_onoff_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-onoff SET\n");
|
||||
|
||||
gen_on_off_state = buf->om_data[0];
|
||||
hal_gpio_write(LED_2, !gen_on_off_state);
|
||||
|
||||
gen_onoff_status(model, ctx);
|
||||
}
|
||||
|
||||
static void gen_onoff_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-onoff SET-UNACK\n");
|
||||
|
||||
gen_on_off_state = buf->om_data[0];
|
||||
hal_gpio_write(LED_2, !gen_on_off_state);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op gen_onoff_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,
|
||||
};
|
||||
|
||||
static void gen_level_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
|
||||
|
||||
console_printf("#mesh-level STATUS\n");
|
||||
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_2(0x82, 0x08));
|
||||
net_buf_simple_add_le16(msg, gen_level_state);
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
console_printf("#mesh-level STATUS: send status failed\n");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static void gen_level_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
console_printf("#mesh-level GET\n");
|
||||
|
||||
gen_level_status(model, ctx);
|
||||
}
|
||||
|
||||
static void gen_level_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t level;
|
||||
|
||||
level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level SET: level=%d\n", level);
|
||||
|
||||
gen_level_status(model, ctx);
|
||||
|
||||
gen_level_state = level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_level_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t level;
|
||||
|
||||
level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level SET-UNACK: level=%d\n", level);
|
||||
|
||||
gen_level_state = level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_delta_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t delta_level;
|
||||
|
||||
delta_level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level);
|
||||
|
||||
gen_level_status(model, ctx);
|
||||
|
||||
gen_level_state += delta_level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_delta_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
int16_t delta_level;
|
||||
|
||||
delta_level = (int16_t) net_buf_simple_pull_le16(buf);
|
||||
console_printf("#mesh-level DELTA-SET: delta_level=%d\n", delta_level);
|
||||
|
||||
gen_level_state += delta_level;
|
||||
console_printf("#mesh-level: level=%d\n", gen_level_state);
|
||||
}
|
||||
|
||||
static void gen_move_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
}
|
||||
|
||||
static void gen_move_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op gen_level_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,
|
||||
};
|
||||
|
||||
static 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_op,
|
||||
&gen_onoff_pub, NULL),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, gen_level_op,
|
||||
&gen_level_pub, NULL),
|
||||
};
|
||||
|
||||
static struct bt_mesh_model_pub vnd_model_pub;
|
||||
|
||||
static void vnd_model_recv(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
|
||||
|
||||
console_printf("#vendor-model-recv\n");
|
||||
|
||||
console_printf("data:%s len:%d\n", bt_hex(buf->om_data, buf->om_len),
|
||||
buf->om_len);
|
||||
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_3(0x01, CID_VENDOR));
|
||||
os_mbuf_append(msg, buf->om_data, buf->om_len);
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
console_printf("#vendor-model-recv: send rsp failed\n");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static const struct bt_mesh_model_op vnd_model_op[] = {
|
||||
{ BT_MESH_MODEL_OP_3(0x01, CID_VENDOR), 0, vnd_model_recv },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
static struct bt_mesh_model vnd_models[] = {
|
||||
BT_MESH_MODEL_VND(CID_VENDOR, BT_MESH_MODEL_ID_GEN_ONOFF_SRV, vnd_model_op,
|
||||
&vnd_model_pub, NULL),
|
||||
};
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(0, root_models, vnd_models),
|
||||
};
|
||||
|
||||
static const struct bt_mesh_comp comp = {
|
||||
.cid = CID_VENDOR,
|
||||
.elem = elements,
|
||||
.elem_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
static int output_number(bt_mesh_output_action_t action, uint32_t number)
|
||||
{
|
||||
console_printf("OOB Number: %lu\n", number);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prov_complete(u16_t net_idx, u16_t addr)
|
||||
{
|
||||
console_printf("Local node provisioned, primary address 0x%04x\n", addr);
|
||||
}
|
||||
|
||||
static const uint8_t dev_uuid[16] = MYNEWT_VAL(BLE_MESH_DEV_UUID);
|
||||
|
||||
static const struct bt_mesh_prov prov = {
|
||||
.uuid = dev_uuid,
|
||||
.output_size = 4,
|
||||
.output_actions = BT_MESH_DISPLAY_NUMBER | BT_MESH_BEEP | BT_MESH_VIBRATE | BT_MESH_BLINK,
|
||||
.output_number = output_number,
|
||||
.complete = prov_complete,
|
||||
};
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
void mesh_initialized(void);
|
||||
|
||||
static 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 (MYNEWT_VAL(BLE_MESH_SHELL))
|
||||
shell_register_default_module("mesh");
|
||||
#endif
|
||||
|
||||
console_printf("Mesh initialized\n");
|
||||
|
||||
/* THIS IS VERY IMPORTANT */
|
||||
/* the official sample doesnot do this, the meshctl cannot discover the mesh device */
|
||||
mesh_initialized();
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
printk("Mesh network restored from flash\n");
|
||||
}
|
||||
}
|
||||
|
||||
void *ble_mesh_adv_task(void *param)
|
||||
{
|
||||
mesh_adv_thread(param);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
k_stack_t ble_mesh_adv_stack[1024];
|
||||
static struct ble_npl_task s_task_mesh_adv;
|
||||
|
||||
void mesh_initialized(void)
|
||||
{
|
||||
ble_npl_task_init(&s_task_mesh_adv, "ble_mesh_adv", ble_mesh_adv_task,
|
||||
NULL, 4, BLE_NPL_TIME_FOREVER,
|
||||
ble_mesh_adv_stack, sizeof(ble_mesh_adv_stack));
|
||||
}
|
||||
|
||||
int ble_boot(void)
|
||||
{
|
||||
#ifdef ARCH_sim
|
||||
mcu_sim_parse_args(argc, argv);
|
||||
#endif
|
||||
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
bt_mesh_register_gatt();
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_ram_init();
|
||||
|
||||
/* 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;
|
||||
|
||||
hal_gpio_init_out(LED_2, 0);
|
||||
|
||||
health_pub_init();
|
||||
|
||||
extern void nimble_port_run(void);
|
||||
nimble_port_tencentos_tiny_init(nimble_port_run);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_task_t ble_boot_task;
|
||||
k_stack_t ble_boot_stack[512];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
|
||||
/* Initialize OS */
|
||||
tos_knl_init();
|
||||
|
||||
nimble_port_init();
|
||||
|
||||
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
|
||||
4,
|
||||
ble_boot_stack, sizeof(ble_boot_stack),
|
||||
0);
|
||||
tos_knl_start();
|
||||
}
|
||||
|
244
examples/nimble_mesh_light/light_model.c
Normal file
244
examples/nimble_mesh_light/light_model.c
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
|
||||
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
|
||||
|
||||
#include "mesh/mesh.h"
|
||||
#if 0
|
||||
#include "bsp.h"
|
||||
#include "pwm/pwm.h"
|
||||
#endif
|
||||
#include "light_model.h"
|
||||
#include "ws2812.h"
|
||||
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
struct pwm_dev *pwm0;
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
struct pwm_dev *pwm1;
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
struct pwm_dev *pwm2;
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
struct pwm_dev *pwm3;
|
||||
#endif
|
||||
|
||||
static uint16_t top_val;
|
||||
#endif
|
||||
|
||||
#if (MYNEWT_VAL(USE_NEOPIXEL))
|
||||
static uint32_t neopixel[WS2812_NUM_LED];
|
||||
#endif
|
||||
|
||||
static u8_t gen_onoff_state;
|
||||
static s16_t gen_level_state;
|
||||
|
||||
static void light_set_lightness(u8_t percentage)
|
||||
{
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
int rc;
|
||||
|
||||
uint16_t pwm_val = (uint16_t) (percentage * top_val / 100);
|
||||
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
rc = pwm_set_duty_cycle(pwm0, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
rc = pwm_set_duty_cycle(pwm1, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
rc = pwm_set_duty_cycle(pwm2, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
rc = pwm_set_duty_cycle(pwm3, 0, pwm_val);
|
||||
assert(rc == 0);
|
||||
#endif
|
||||
#else
|
||||
int i;
|
||||
u32_t lightness;
|
||||
u8_t max_lightness = 0x1f;
|
||||
|
||||
lightness = (u8_t) (percentage * max_lightness / 100);
|
||||
|
||||
for (i = 0; i < WS2812_NUM_LED; i++) {
|
||||
neopixel[i] = (lightness | lightness << 8 | lightness << 16);
|
||||
}
|
||||
ws2812_write(neopixel);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void update_light_state(void)
|
||||
{
|
||||
u16_t level = (u16_t)gen_level_state;
|
||||
int percent = 100 * level / 0xffff;
|
||||
|
||||
if (gen_onoff_state == 0) {
|
||||
percent = 0;
|
||||
}
|
||||
light_set_lightness((uint8_t) percent);
|
||||
}
|
||||
|
||||
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state)
|
||||
{
|
||||
*state = gen_onoff_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state)
|
||||
{
|
||||
gen_onoff_state = state;
|
||||
update_light_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level)
|
||||
{
|
||||
*level = gen_level_state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level)
|
||||
{
|
||||
gen_level_state = level;
|
||||
if ((u16_t)gen_level_state > 0x0000) {
|
||||
gen_onoff_state = 1;
|
||||
}
|
||||
if ((u16_t)gen_level_state == 0x0000) {
|
||||
gen_onoff_state = 0;
|
||||
}
|
||||
update_light_state();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness)
|
||||
{
|
||||
return light_model_gen_level_get(model, lightness);
|
||||
}
|
||||
|
||||
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness)
|
||||
{
|
||||
return light_model_gen_level_set(model, lightness);
|
||||
}
|
||||
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
struct pwm_dev_cfg dev_conf = {
|
||||
.n_cycles = 0,
|
||||
.int_prio = 3,
|
||||
};
|
||||
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
static struct pwm_chan_cfg led1_conf = {
|
||||
.pin = LED_1,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
static struct pwm_chan_cfg led2_conf = {
|
||||
.pin = LED_2,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
static struct pwm_chan_cfg led3_conf = {
|
||||
.pin = LED_3,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
static struct pwm_chan_cfg led4_conf = {
|
||||
.pin = LED_4,
|
||||
.inverted = true,
|
||||
};
|
||||
#endif
|
||||
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
void init_pwm_dev(struct pwm_dev **pwm, char *dev_name, struct pwm_chan_cfg *chan_cfg)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
*pwm = (struct pwm_dev *) os_dev_open(dev_name, 0, NULL);
|
||||
assert(pwm);
|
||||
rc = pwm_configure_device(*pwm, &dev_conf);
|
||||
assert(rc == 0);
|
||||
rc = pwm_configure_channel(*pwm, 0, chan_cfg);
|
||||
assert(rc == 0);
|
||||
rc = pwm_enable(*pwm);
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
int pwm_init(void)
|
||||
{
|
||||
|
||||
#if MYNEWT_VAL(PWM_0)
|
||||
init_pwm_dev(&pwm0, "pwm0", &led1_conf);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_1)
|
||||
init_pwm_dev(&pwm1, "pwm1", &led2_conf);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_2)
|
||||
init_pwm_dev(&pwm2, "pwm2", &led3_conf);
|
||||
#endif
|
||||
|
||||
#if MYNEWT_VAL(PWM_3)
|
||||
init_pwm_dev(&pwm3, "pwm3", &led4_conf);
|
||||
#endif
|
||||
|
||||
if (!pwm0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
top_val = (uint16_t) pwm_get_top_value(pwm0);
|
||||
update_light_state();
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int light_model_init(void)
|
||||
{
|
||||
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
|
||||
int rc;
|
||||
#if (!MYNEWT_VAL(USE_NEOPIXEL))
|
||||
rc = pwm_init();
|
||||
assert(rc == 0);
|
||||
#else
|
||||
rc = ws2812_init();
|
||||
assert(rc == 0);
|
||||
update_light_state();
|
||||
#endif
|
||||
return rc;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
37
examples/nimble_mesh_light/light_model.h
Normal file
37
examples/nimble_mesh_light/light_model.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BT_MESH_LIGHT_MODEL_H
|
||||
#define __BT_MESH_LIGHT_MODEL_H
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state);
|
||||
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state);
|
||||
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level);
|
||||
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level);
|
||||
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness);
|
||||
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness);
|
||||
int light_model_init(void);
|
||||
|
||||
#endif
|
207
examples/nimble_mesh_light/main.c
Normal file
207
examples/nimble_mesh_light/main.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "os/os.h"
|
||||
#include "mesh/mesh.h"
|
||||
#include "console/console.h"
|
||||
#if 0
|
||||
#include "hal/hal_system.h"
|
||||
#include "hal/hal_gpio.h"
|
||||
#include "bsp/bsp.h"
|
||||
#endif
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
/* BLE */
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "mesh/testing.h"
|
||||
#include "mesh/model_srv.h"
|
||||
#include "light_model.h"
|
||||
|
||||
///////////////////////
|
||||
// stub-s
|
||||
|
||||
int __atomic_load_4(int *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
int __atomic_fetch_and_4(int *p, int v)
|
||||
{
|
||||
return *p & v;
|
||||
}
|
||||
|
||||
int __atomic_fetch_or_4(int *p, int v)
|
||||
{
|
||||
return *p | v;
|
||||
}
|
||||
|
||||
int __atomic_exchange_4(int *p, int v)
|
||||
{
|
||||
int old = *p;
|
||||
*p = v;
|
||||
return old;
|
||||
}
|
||||
|
||||
void unreachable(void)
|
||||
{
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
void shell_register_default_module(char *module)
|
||||
{
|
||||
}
|
||||
|
||||
void shell_evq_set(struct ble_npl_eventq *evq)
|
||||
{
|
||||
}
|
||||
|
||||
int shell_register(const char *module_name, const struct shell_cmd *commands)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
//////////////////////
|
||||
|
||||
static void model_bound_cb(u16_t addr, struct bt_mesh_model *model,
|
||||
u16_t key_idx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
console_printf("Model bound: remote addr 0x%04x key_idx 0x%04x model %p\n",
|
||||
addr, key_idx, model);
|
||||
|
||||
if (model->id != BT_MESH_MODEL_ID_GEN_LEVEL_SRV) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Hack for demo purposes */
|
||||
rc = bt_test_bind_app_key_to_model(model, key_idx,
|
||||
BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV);
|
||||
|
||||
if (rc) {
|
||||
console_printf("Failed to bind light lightness srv model to app_key");
|
||||
} else {
|
||||
console_printf("Successfuly bound light lightness srv model to app_key");
|
||||
}
|
||||
}
|
||||
|
||||
static struct bt_test_cb bt_test_cb = {
|
||||
.mesh_model_bound = model_bound_cb,
|
||||
};
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static struct bt_mesh_gen_onoff_srv_cb gen_onoff_srv_cb = {
|
||||
.get = light_model_gen_onoff_get,
|
||||
.set = light_model_gen_onoff_set,
|
||||
};
|
||||
static struct bt_mesh_gen_level_srv_cb gen_level_srv_cb = {
|
||||
.get = light_model_gen_level_get,
|
||||
.set = light_model_gen_level_set,
|
||||
};
|
||||
static struct bt_mesh_light_lightness_srv_cb light_lightness_srv_cb = {
|
||||
.get = light_model_light_lightness_get,
|
||||
.set = light_model_light_lightness_set,
|
||||
};
|
||||
|
||||
static void
|
||||
blemesh_on_sync(void)
|
||||
{
|
||||
console_printf("Bluetooth initialized\n");
|
||||
|
||||
shell_register_default_module("mesh");
|
||||
|
||||
bt_test_cb_register(&bt_test_cb);
|
||||
|
||||
light_model_init();
|
||||
bt_mesh_set_gen_onoff_srv_cb(&gen_onoff_srv_cb);
|
||||
bt_mesh_set_gen_level_srv_cb(&gen_level_srv_cb);
|
||||
bt_mesh_set_light_lightness_srv_cb(&light_lightness_srv_cb);
|
||||
|
||||
console_printf("Mesh initialized\n");
|
||||
|
||||
if (IS_ENABLED(CONFIG_SETTINGS)) {
|
||||
settings_load();
|
||||
}
|
||||
|
||||
if (bt_mesh_is_provisioned()) {
|
||||
printk("Mesh network restored from flash\n");
|
||||
}
|
||||
|
||||
/* Hack for demo purposes */
|
||||
bt_test_shell_init();
|
||||
|
||||
#if 1 // we donnot have a shell yet, trigger the command by code...
|
||||
if (bt_mesh_prov_enable(BT_MESH_PROV_GATT | BT_MESH_PROV_ADV)) {
|
||||
console_printf("Failed to enable PB-ADV & PB-GATT\n");
|
||||
} else {
|
||||
console_printf("PB-ADV & PB-GATT enabled\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int ble_boot(void)
|
||||
{
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
bt_mesh_register_gatt();
|
||||
|
||||
/* XXX Need to have template for store */
|
||||
ble_store_ram_init();
|
||||
|
||||
/* 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;
|
||||
|
||||
extern void nimble_port_run(void);
|
||||
nimble_port_tencentos_tiny_init(nimble_port_run);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_task_t ble_boot_task;
|
||||
k_stack_t ble_boot_stack[512];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
|
||||
/* Initialize OS */
|
||||
tos_knl_init();
|
||||
|
||||
nimble_port_init();
|
||||
|
||||
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
|
||||
4,
|
||||
ble_boot_stack, sizeof(ble_boot_stack),
|
||||
0);
|
||||
tos_knl_start();
|
||||
}
|
||||
|
143
examples/nimble_mesh_light/ws2812.c
Normal file
143
examples/nimble_mesh_light/ws2812.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "syscfg/syscfg.h"
|
||||
|
||||
#if (MYNEWT_VAL(USE_NEOPIXEL))
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "sysinit/sysinit.h"
|
||||
#include "os/os.h"
|
||||
#if 0
|
||||
#include "bsp/bsp.h"
|
||||
#include "pwm/pwm.h"
|
||||
#endif
|
||||
#include "nrfx.h"
|
||||
#include "nrfx_pwm.h"
|
||||
#include "ws2812.h"
|
||||
|
||||
#define BITS_PER_SEQ (24)
|
||||
#define BIT0 (0x8000 | 6)
|
||||
#define BIT1 (0x8000 | 11)
|
||||
|
||||
static const nrfx_pwm_t pwm = NRFX_PWM_INSTANCE(WS2812_PWM);
|
||||
|
||||
static const nrfx_pwm_config_t pwm_config = {
|
||||
.output_pins = { WS2812_GPIO, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED, NRFX_PWM_PIN_NOT_USED },
|
||||
.irq_priority = 3,
|
||||
.base_clock = NRF_PWM_CLK_16MHz,
|
||||
.count_mode = NRF_PWM_MODE_UP,
|
||||
.top_value = 20,
|
||||
.load_mode = NRF_PWM_LOAD_COMMON,
|
||||
.step_mode = NRF_PWM_STEP_AUTO,
|
||||
};
|
||||
|
||||
static uint16_t pwm_seq_values[2][BITS_PER_SEQ];
|
||||
|
||||
static const nrf_pwm_sequence_t pwm_seq[2] = {
|
||||
{
|
||||
.values.p_raw = pwm_seq_values[0],
|
||||
.length = BITS_PER_SEQ,
|
||||
.repeats = 0,
|
||||
.end_delay = 0,
|
||||
}, {
|
||||
.values.p_raw = pwm_seq_values[1],
|
||||
.length = BITS_PER_SEQ,
|
||||
.repeats = 0,
|
||||
.end_delay = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static uint32_t led_color[WS2812_NUM_LED];
|
||||
static int led_idx;
|
||||
|
||||
static void
|
||||
load_pixel(void)
|
||||
{
|
||||
uint16_t *seq_values;
|
||||
uint32_t grb;
|
||||
int i;
|
||||
|
||||
seq_values = pwm_seq_values[led_idx & 1];
|
||||
grb = led_color[led_idx];
|
||||
|
||||
for (i = 0; i < BITS_PER_SEQ; i++) {
|
||||
*seq_values = grb & 0x800000 ? BIT1 : BIT0;
|
||||
grb <<= 1;
|
||||
seq_values++;
|
||||
}
|
||||
|
||||
led_idx++;
|
||||
}
|
||||
|
||||
static void
|
||||
pwm_handler_func(nrfx_pwm_evt_type_t event_type)
|
||||
{
|
||||
switch (event_type) {
|
||||
case NRFX_PWM_EVT_END_SEQ0:
|
||||
case NRFX_PWM_EVT_END_SEQ1:
|
||||
load_pixel();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
ws2812_init(void)
|
||||
{
|
||||
#if 0
|
||||
nrfx_err_t err;
|
||||
|
||||
err = nrfx_pwm_init(&pwm, &pwm_config, pwm_handler_func);
|
||||
|
||||
return err != NRFX_SUCCESS;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ws2812_write(const uint32_t *rgb)
|
||||
{
|
||||
uint32_t grb;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WS2812_NUM_LED; i++) {
|
||||
grb = 0;
|
||||
grb |= (rgb[i] & 0x00FF00) << 8;
|
||||
grb |= (rgb[i] & 0xFF0000) >> 8;
|
||||
grb |= (rgb[i] & 0x0000FF);
|
||||
|
||||
led_color[i] = grb;
|
||||
}
|
||||
|
||||
led_idx = 0;
|
||||
|
||||
load_pixel();
|
||||
load_pixel();
|
||||
nrfx_pwm_complex_playback(&pwm, &pwm_seq[0], &pwm_seq[1], WS2812_NUM_LED,
|
||||
NRFX_PWM_FLAG_SIGNAL_END_SEQ0 |
|
||||
NRFX_PWM_FLAG_SIGNAL_END_SEQ1 |
|
||||
NRFX_PWM_FLAG_STOP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
42
examples/nimble_mesh_light/ws2812.h
Normal file
42
examples/nimble_mesh_light/ws2812.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef __WS2812_H__
|
||||
#define __WS2812_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define WS2812_PWM 0
|
||||
#define WS2812_GPIO 30
|
||||
#define WS2812_NUM_LED 32
|
||||
|
||||
int ws2812_init(void);
|
||||
|
||||
int ws2812_write(const uint32_t *rgb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __WS2812_H__ */
|
79
examples/nimble_mesh_models_example_1/README.md
Normal file
79
examples/nimble_mesh_models_example_1/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
### Bluetooth: Mesh OnOff Model
|
||||
|
||||
|
||||
#### Overview
|
||||
|
||||
This is a simple application demonstrating a Bluetooth mesh multi-element node.
|
||||
Each element has a mesh onoff client and server
|
||||
model which controls one of the 4 sets of buttons and LEDs .
|
||||
|
||||
Prior to provisioning, an unprovisioned beacon is broadcast that contains
|
||||
a UUID. Each button controls the state of its
|
||||
corresponding LED and does not initiate any mesh activity.
|
||||
|
||||
The models for button 1 and LED 1 are in the node's root element.
|
||||
The 3 remaining button/LED pairs are in elements 1 through 3.
|
||||
Assuming the provisioner assigns 0x100 to the root element,
|
||||
the secondary elements will appear at 0x101, 0x102 and 0x103.
|
||||
|
||||
After provisioning, the button clients must
|
||||
be configured to publish and the LED servers to subscribe.
|
||||
|
||||
If a LED server is provided with a publish address, it will
|
||||
also publish its status on an onoff state change.
|
||||
|
||||
If a button is pressed only once within a 1 second interval, it sends an
|
||||
"on" message. If it is pressed more than once, it
|
||||
sends an "off" message. The buttons are quite noisy and are debounced in
|
||||
the button_pressed() interrupt handler. An interrupt within 250ms of the
|
||||
previous is discarded. This might seem a little clumsy, but the alternative of
|
||||
using one button for "on" and another for "off" would reduce the number
|
||||
of onoff clients from 4 to 2.
|
||||
|
||||
#### Requirements
|
||||
************
|
||||
|
||||
This sample has been tested on the Nordic nRF52840-PDK board, but would
|
||||
likely also run on the nrf52_pca10040 board.
|
||||
|
||||
#### Building and Running
|
||||
********************
|
||||
|
||||
Prior to provisioning, each button controls its corresponding LED as one
|
||||
would expect with an actual switch.
|
||||
|
||||
Provisioning is done using the BlueZ meshctl utility. Below is an example that
|
||||
binds button 2 and LED 1 to application key 1. It then configures button 2
|
||||
to publish to group 0xc000 and LED 1 to subscribe to that group.
|
||||
|
||||
```
|
||||
discover-unprovisioned on
|
||||
provision <discovered UUID>
|
||||
menu config
|
||||
target 0100
|
||||
appkey-add 1
|
||||
bind 0 1 1000 # bind appkey 1 to LED server on element 0 (unicast 0100)
|
||||
sub-add 0100 c000 1000 # add subscription to group address c000 to the LED server
|
||||
bind 1 1 1001 # bind appkey 1 to button 2 on element 1 (unicast 0101)
|
||||
pub-set 0101 c000 1 0 0 1001 # publish button 2 to group address c000
|
||||
```
|
||||
|
||||
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 4 elements per node.
|
||||
|
||||
The first or root element of the node contains models for configuration,
|
||||
health, and onoff. The secondary elements only
|
||||
have models for onoff. 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.
|
817
examples/nimble_mesh_models_example_1/main.c
Normal file
817
examples/nimble_mesh_models_example_1/main.c
Normal file
@@ -0,0 +1,817 @@
|
||||
/* main.c - Application main entry point */
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* This application is specific to the Nordic nRF52840-PDK board.
|
||||
*
|
||||
* It supports the 4 buttons and 4 LEDs as mesh clients and servers.
|
||||
*
|
||||
* Prior to provisioning, a button inverts the state of the
|
||||
* corresponding LED.
|
||||
*
|
||||
* Button and LED 1 are in the root node.
|
||||
* The 3 remaining button/LED pairs are in element 1 through 3.
|
||||
* Assuming the provisioner assigns 0x100 to the root node,
|
||||
* the secondary elements will appear at 0x101, 0x102 and 0x103.
|
||||
*
|
||||
* It's anticipated that after provisioning, the button clients would
|
||||
* be configured to publish and the LED servers to subscribe.
|
||||
*
|
||||
* If a LED server is provided with a publish address, it will
|
||||
* also publish its status on a state change.
|
||||
*
|
||||
* Messages from a button to its corresponding LED are ignored as
|
||||
* the LED's state has already been changed locally by the button client.
|
||||
*
|
||||
* The buttons are debounced at a nominal 250ms. That value can be
|
||||
* changed as needed.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "bsp/bsp.h"
|
||||
#include "console/console.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "mesh/glue.h"
|
||||
#include "mesh/mesh.h"
|
||||
|
||||
///////////////////////
|
||||
// stub-s
|
||||
|
||||
/*
|
||||
* The "pull" of the gpio. This is either an input or an output.
|
||||
*/
|
||||
enum hal_gpio_pull {
|
||||
/** Pull-up/down not enabled */
|
||||
HAL_GPIO_PULL_NONE = 0,
|
||||
/** Pull-up enabled */
|
||||
HAL_GPIO_PULL_UP = 1,
|
||||
/** Pull-down enabled */
|
||||
HAL_GPIO_PULL_DOWN = 2
|
||||
};
|
||||
typedef enum hal_gpio_pull hal_gpio_pull_t;
|
||||
|
||||
/*
|
||||
* IRQ trigger type.
|
||||
*/
|
||||
enum hal_gpio_irq_trigger {
|
||||
HAL_GPIO_TRIG_NONE = 0,
|
||||
/** IRQ occurs on rising edge */
|
||||
HAL_GPIO_TRIG_RISING = 1,
|
||||
/** IRQ occurs on falling edge */
|
||||
HAL_GPIO_TRIG_FALLING = 2,
|
||||
/** IRQ occurs on either edge */
|
||||
HAL_GPIO_TRIG_BOTH = 3,
|
||||
/** IRQ occurs when line is low */
|
||||
HAL_GPIO_TRIG_LOW = 4,
|
||||
/** IRQ occurs when line is high */
|
||||
HAL_GPIO_TRIG_HIGH = 5
|
||||
};
|
||||
typedef enum hal_gpio_irq_trigger hal_gpio_irq_trig_t;
|
||||
|
||||
|
||||
/* Function proto for GPIO irq handler functions */
|
||||
typedef void (*hal_gpio_irq_handler_t)(void *arg);
|
||||
|
||||
int hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg,
|
||||
hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull)
|
||||
{
|
||||
// printf("gpio irq init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hal_gpio_irq_enable(int pin)
|
||||
{
|
||||
// printf("gpio irq enable\n");
|
||||
}
|
||||
|
||||
void hal_gpio_init_out(int led, int s)
|
||||
{
|
||||
// printf("gpio init out\n");
|
||||
}
|
||||
|
||||
void hal_gpio_write(int led, int s)
|
||||
{
|
||||
// printf("led[%d]: %s\n", s == 0 ? "OFF" : "ON");
|
||||
}
|
||||
|
||||
int __atomic_load_4(int *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
int __atomic_fetch_and_4(int *p, int v)
|
||||
{
|
||||
return *p & v;
|
||||
}
|
||||
|
||||
int __atomic_fetch_or_4(int *p, int v)
|
||||
{
|
||||
return *p | v;
|
||||
}
|
||||
|
||||
int __atomic_exchange_4(int *p, int v)
|
||||
{
|
||||
int old = *p;
|
||||
*p = v;
|
||||
return old;
|
||||
}
|
||||
|
||||
void unreachable(void)
|
||||
{
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
|
||||
#define CID_RUNTIME 0x05C3
|
||||
|
||||
/* 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)
|
||||
|
||||
static void gen_onoff_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
static void gen_onoff_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
static void gen_onoff_get(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
static void gen_onoff_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf);
|
||||
|
||||
/*
|
||||
* Server Configuration Declaration
|
||||
*/
|
||||
|
||||
static struct bt_mesh_cfg_srv cfg_srv = {
|
||||
.relay = BT_MESH_RELAY_DISABLED,
|
||||
.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,
|
||||
|
||||
/* 3 transmissions with 20ms interval */
|
||||
.net_transmit = BT_MESH_TRANSMIT(2, 20),
|
||||
.relay_retransmit = BT_MESH_TRANSMIT(2, 20),
|
||||
};
|
||||
|
||||
/*
|
||||
* Client Configuration Declaration
|
||||
*/
|
||||
|
||||
static struct bt_mesh_cfg_cli cfg_cli = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Health Server Declaration
|
||||
*/
|
||||
|
||||
static struct bt_mesh_health_srv health_srv = {
|
||||
};
|
||||
|
||||
/*
|
||||
* Publication Declarations
|
||||
*
|
||||
* The publication messages are initialized to the
|
||||
* the size of the opcode + content
|
||||
*
|
||||
* For publication, the message must be in static or global as
|
||||
* it is re-transmitted several times. This occurs
|
||||
* after the function that called bt_mesh_model_publish() has
|
||||
* exited and the stack is no longer valid.
|
||||
*
|
||||
* Note that the additional 4 bytes for the AppMIC is not needed
|
||||
* because it is added to a stack variable at the time a
|
||||
* transmission occurs.
|
||||
*
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model_pub health_pub;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_0;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_0;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_1;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_1;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_srv_s_2;
|
||||
static struct bt_mesh_model_pub gen_onoff_pub_cli_s_2;
|
||||
|
||||
static struct os_mbuf *bt_mesh_pub_msg_health_pub;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
|
||||
static struct os_mbuf *bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
|
||||
|
||||
void init_pub(void)
|
||||
{
|
||||
bt_mesh_pub_msg_health_pub = NET_BUF_SIMPLE(1 + 3 + 0);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv_s_0 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli_s_0 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv_s_1 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli_s_1 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_srv_s_2 = NET_BUF_SIMPLE(2 + 2);
|
||||
bt_mesh_pub_msg_gen_onoff_pub_cli_s_2 = NET_BUF_SIMPLE(2 + 2);
|
||||
|
||||
health_pub.msg = bt_mesh_pub_msg_health_pub;
|
||||
gen_onoff_pub_srv.msg = bt_mesh_pub_msg_gen_onoff_pub_srv;
|
||||
gen_onoff_pub_cli.msg = bt_mesh_pub_msg_gen_onoff_pub_cli;
|
||||
gen_onoff_pub_srv_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_0;
|
||||
gen_onoff_pub_cli_s_0.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_0;
|
||||
gen_onoff_pub_srv_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_1;
|
||||
gen_onoff_pub_cli_s_1.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_1;
|
||||
gen_onoff_pub_srv_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_srv_s_2;
|
||||
gen_onoff_pub_cli_s_2.msg = bt_mesh_pub_msg_gen_onoff_pub_cli_s_2;
|
||||
}
|
||||
|
||||
/*
|
||||
* Models in an element must have unique op codes.
|
||||
*
|
||||
* The mesh stack dispatches a message to the first model in an element
|
||||
* that is also bound to an app key and supports the op code in the
|
||||
* received message.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* OnOff Model Server Op Dispatch Table
|
||||
*
|
||||
*/
|
||||
|
||||
static const struct bt_mesh_model_op gen_onoff_srv_op[] = {
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_GET, 0, gen_onoff_get },
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET, 2, gen_onoff_set },
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK, 2, gen_onoff_set_unack },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
/*
|
||||
* OnOff Model Client Op Dispatch Table
|
||||
*/
|
||||
|
||||
static const struct bt_mesh_model_op gen_onoff_cli_op[] = {
|
||||
{ BT_MESH_MODEL_OP_GEN_ONOFF_STATUS, 1, gen_onoff_status },
|
||||
BT_MESH_MODEL_OP_END,
|
||||
};
|
||||
|
||||
struct onoff_state {
|
||||
u8_t current;
|
||||
u8_t previous;
|
||||
u8_t led_gpio_pin;
|
||||
};
|
||||
|
||||
/*
|
||||
* Declare and Initialize Element Contexts
|
||||
* Change to select different GPIO output pins
|
||||
*/
|
||||
|
||||
static struct onoff_state onoff_state_arr[] = {
|
||||
{ .led_gpio_pin = LED_1 },
|
||||
{ .led_gpio_pin = LED_2 },
|
||||
{ .led_gpio_pin = LED_3 },
|
||||
{ .led_gpio_pin = LED_4 },
|
||||
};
|
||||
|
||||
/*
|
||||
*
|
||||
* Element Model Declarations
|
||||
*
|
||||
* Element 0 Root Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model root_models[] = {
|
||||
BT_MESH_MODEL_CFG_SRV(&cfg_srv),
|
||||
BT_MESH_MODEL_CFG_CLI(&cfg_cli),
|
||||
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_pub_srv, &onoff_state_arr[0]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli, &onoff_state_arr[0]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Element 1 Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model secondary_0_models[] = {
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv_s_0, &onoff_state_arr[1]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli_s_0, &onoff_state_arr[1]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Element 2 Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model secondary_1_models[] = {
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv_s_1, &onoff_state_arr[2]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli_s_1, &onoff_state_arr[2]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Element 3 Models
|
||||
*/
|
||||
|
||||
static struct bt_mesh_model secondary_2_models[] = {
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, gen_onoff_srv_op,
|
||||
&gen_onoff_pub_srv_s_2, &onoff_state_arr[3]),
|
||||
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op,
|
||||
&gen_onoff_pub_cli_s_2, &onoff_state_arr[3]),
|
||||
};
|
||||
|
||||
/*
|
||||
* Button to Client Model Assignments
|
||||
*/
|
||||
|
||||
struct bt_mesh_model *mod_cli_sw[] = {
|
||||
&root_models[4],
|
||||
&secondary_0_models[1],
|
||||
&secondary_1_models[1],
|
||||
&secondary_2_models[1],
|
||||
};
|
||||
|
||||
/*
|
||||
* LED to Server Model Assigmnents
|
||||
*/
|
||||
|
||||
struct bt_mesh_model *mod_srv_sw[] = {
|
||||
&root_models[3],
|
||||
&secondary_0_models[0],
|
||||
&secondary_1_models[0],
|
||||
&secondary_2_models[0],
|
||||
};
|
||||
|
||||
/*
|
||||
* Root and Secondary Element Declarations
|
||||
*/
|
||||
|
||||
static struct bt_mesh_elem elements[] = {
|
||||
BT_MESH_ELEM(0, root_models, BT_MESH_MODEL_NONE),
|
||||
BT_MESH_ELEM(0, secondary_0_models, BT_MESH_MODEL_NONE),
|
||||
BT_MESH_ELEM(0, secondary_1_models, BT_MESH_MODEL_NONE),
|
||||
BT_MESH_ELEM(0, secondary_2_models, BT_MESH_MODEL_NONE),
|
||||
};
|
||||
|
||||
static const struct bt_mesh_comp comp = {
|
||||
.cid = CID_RUNTIME,
|
||||
.elem = elements,
|
||||
.elem_count = ARRAY_SIZE(elements),
|
||||
};
|
||||
|
||||
struct sw {
|
||||
u8_t sw_num;
|
||||
u8_t onoff_state;
|
||||
struct ble_npl_callout button_work;
|
||||
struct ble_npl_callout button_timer;
|
||||
};
|
||||
|
||||
|
||||
static u8_t button_press_cnt;
|
||||
static struct sw sw;
|
||||
|
||||
static u8_t trans_id;
|
||||
static u32_t time, last_time;
|
||||
static u16_t primary_addr;
|
||||
static u16_t primary_net_idx;
|
||||
|
||||
/*
|
||||
* Generic OnOff Model Server Message Handlers
|
||||
*
|
||||
* Mesh Model Specification 3.1.1
|
||||
*
|
||||
*/
|
||||
|
||||
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 + 1 + 4);
|
||||
struct onoff_state *state = model->user_data;
|
||||
|
||||
BT_INFO("addr 0x%04x onoff 0x%02x",
|
||||
bt_mesh_model_elem(model)->addr, state->current);
|
||||
bt_mesh_model_msg_init(msg, BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
|
||||
net_buf_simple_add_u8(msg, state->current);
|
||||
|
||||
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
|
||||
BT_ERR("Unable to send On Off Status response");
|
||||
}
|
||||
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
static void gen_onoff_set_unack(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
struct os_mbuf *msg = model->pub->msg;
|
||||
struct onoff_state *state = model->user_data;
|
||||
int err;
|
||||
|
||||
state->current = net_buf_simple_pull_u8(buf);
|
||||
BT_INFO("addr 0x%02x state 0x%02x",
|
||||
bt_mesh_model_elem(model)->addr, state->current);
|
||||
|
||||
/* Pin set low turns on LED's on the nrf52840-pca10056 board */
|
||||
hal_gpio_write(state->led_gpio_pin,
|
||||
state->current ? 0 : 1);
|
||||
|
||||
/*
|
||||
* If a server has a publish address, it is required to
|
||||
* publish status on a state change
|
||||
*
|
||||
* See Mesh Profile Specification 3.7.6.1.2
|
||||
*
|
||||
* Only publish if there is an assigned address
|
||||
*/
|
||||
|
||||
if (state->previous != state->current &&
|
||||
model->pub->addr != BT_MESH_ADDR_UNASSIGNED) {
|
||||
BT_INFO("publish last 0x%02x cur 0x%02x",
|
||||
state->previous,
|
||||
state->current);
|
||||
state->previous = state->current;
|
||||
bt_mesh_model_msg_init(msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_STATUS);
|
||||
net_buf_simple_add_u8(msg, state->current);
|
||||
err = bt_mesh_model_publish(model);
|
||||
if (err) {
|
||||
BT_ERR("bt_mesh_model_publish err %d", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void gen_onoff_set(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
BT_INFO("");
|
||||
|
||||
gen_onoff_set_unack(model, ctx, buf);
|
||||
gen_onoff_get(model, ctx, buf);
|
||||
}
|
||||
|
||||
static void gen_onoff_status(struct bt_mesh_model *model,
|
||||
struct bt_mesh_msg_ctx *ctx,
|
||||
struct os_mbuf *buf)
|
||||
{
|
||||
u8_t state;
|
||||
|
||||
state = net_buf_simple_pull_u8(buf);
|
||||
|
||||
BT_INFO("Node 0x%04x OnOff status from 0x%04x with state 0x%02x",
|
||||
bt_mesh_model_elem(model)->addr, ctx->addr, state);
|
||||
}
|
||||
|
||||
static int output_number(bt_mesh_output_action_t action, u32_t number)
|
||||
{
|
||||
BT_INFO("OOB Number %u", number);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int output_string(const char *str)
|
||||
{
|
||||
BT_INFO("OOB String %s", str);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void prov_complete(u16_t net_idx, u16_t addr)
|
||||
{
|
||||
BT_INFO("provisioning complete for net_idx 0x%04x addr 0x%04x",
|
||||
net_idx, addr);
|
||||
primary_addr = addr;
|
||||
primary_net_idx = net_idx;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
#define BUTTON_DEBOUNCE_DELAY_MS 250
|
||||
|
||||
/*
|
||||
* Map GPIO pins to button number
|
||||
* Change to select different GPIO input pins
|
||||
*/
|
||||
|
||||
static uint8_t pin_to_sw(int pin_pos)
|
||||
{
|
||||
switch (pin_pos) {
|
||||
case BUTTON_1: return 0;
|
||||
case BUTTON_2: return 1;
|
||||
case BUTTON_3: return 2;
|
||||
case BUTTON_4: return 3;
|
||||
default:break;
|
||||
}
|
||||
|
||||
BT_ERR("No match for GPIO pin 0x%08x", pin_pos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void button_pressed(struct ble_npl_event *ev)
|
||||
{
|
||||
int pin_pos = (int ) ev->arg;
|
||||
/*
|
||||
* One button press within a 1 second interval sends an on message
|
||||
* More than one button press sends an off message
|
||||
*/
|
||||
|
||||
time = k_uptime_get_32();
|
||||
|
||||
/* debounce the switch */
|
||||
if (time < last_time + BUTTON_DEBOUNCE_DELAY_MS) {
|
||||
last_time = time;
|
||||
return;
|
||||
}
|
||||
|
||||
if (button_press_cnt == 0) {
|
||||
ble_npl_callout_reset(&sw.button_timer, ble_npl_time_ms_to_ticks32(K_SECONDS(1)));
|
||||
}
|
||||
|
||||
BT_INFO("button_press_cnt 0x%02x", button_press_cnt);
|
||||
button_press_cnt++;
|
||||
|
||||
/* The variable pin_pos is the pin position in the GPIO register,
|
||||
* not the pin number. It's assumed that only one bit is set.
|
||||
*/
|
||||
|
||||
sw.sw_num = pin_to_sw(pin_pos);
|
||||
last_time = time;
|
||||
}
|
||||
|
||||
/*
|
||||
* Button Count Timer Worker
|
||||
*/
|
||||
|
||||
static void button_cnt_timer(struct ble_npl_event *work)
|
||||
{
|
||||
struct sw *button_sw = work->arg;
|
||||
|
||||
button_sw->onoff_state = button_press_cnt == 1 ? 1 : 0;
|
||||
BT_INFO("button_press_cnt 0x%02x onoff_state 0x%02x",
|
||||
button_press_cnt, button_sw->onoff_state);
|
||||
button_press_cnt = 0;
|
||||
ble_npl_callout_reset(&sw.button_work, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Button Pressed Worker Task
|
||||
*/
|
||||
|
||||
static void button_pressed_worker(struct ble_npl_event *work)
|
||||
{
|
||||
struct os_mbuf *msg = NET_BUF_SIMPLE(1);
|
||||
struct bt_mesh_model *mod_cli, *mod_srv;
|
||||
struct bt_mesh_model_pub *pub_cli, *pub_srv;
|
||||
struct sw *sw = work->arg;
|
||||
u8_t sw_idx = sw->sw_num;
|
||||
int err;
|
||||
|
||||
mod_cli = mod_cli_sw[sw_idx];
|
||||
pub_cli = mod_cli->pub;
|
||||
|
||||
mod_srv = mod_srv_sw[sw_idx];
|
||||
pub_srv = mod_srv->pub;
|
||||
(void)pub_srv;
|
||||
|
||||
/* If unprovisioned, just call the set function.
|
||||
* The intent is to have switch-like behavior
|
||||
* prior to provisioning. Once provisioned,
|
||||
* the button and its corresponding led are no longer
|
||||
* associated and act independently. So, if a button is to
|
||||
* control its associated led after provisioning, the button
|
||||
* must be configured to either publish to the led's unicast
|
||||
* address or a group to which the led is subscribed.
|
||||
*/
|
||||
|
||||
if (primary_addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
struct bt_mesh_msg_ctx ctx = {
|
||||
.addr = sw_idx + primary_addr,
|
||||
};
|
||||
|
||||
/* This is a dummy message sufficient
|
||||
* for the led server
|
||||
*/
|
||||
|
||||
net_buf_simple_add_u8(msg, sw->onoff_state);
|
||||
gen_onoff_set_unack(mod_srv, &ctx, msg);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (pub_cli->addr == BT_MESH_ADDR_UNASSIGNED) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
BT_INFO("publish to 0x%04x onoff 0x%04x sw_idx 0x%04x",
|
||||
pub_cli->addr, sw->onoff_state, sw_idx);
|
||||
bt_mesh_model_msg_init(pub_cli->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET);
|
||||
net_buf_simple_add_u8(pub_cli->msg, sw->onoff_state);
|
||||
net_buf_simple_add_u8(pub_cli->msg, trans_id++);
|
||||
err = bt_mesh_model_publish(mod_cli);
|
||||
if (err) {
|
||||
BT_ERR("bt_mesh_model_publish err %d", err);
|
||||
}
|
||||
|
||||
done:
|
||||
os_mbuf_free_chain(msg);
|
||||
}
|
||||
|
||||
/* Disable OOB security for SILabs Android app */
|
||||
|
||||
static const struct bt_mesh_prov prov = {
|
||||
.uuid = dev_uuid,
|
||||
#if 1
|
||||
.output_size = 6,
|
||||
.output_actions = (BT_MESH_DISPLAY_NUMBER | BT_MESH_DISPLAY_STRING),
|
||||
.output_number = output_number,
|
||||
.output_string = output_string,
|
||||
#else
|
||||
.output_size = 0,
|
||||
.output_actions = 0,
|
||||
.output_number = 0,
|
||||
#endif
|
||||
.complete = prov_complete,
|
||||
.reset = prov_reset,
|
||||
};
|
||||
|
||||
void init_led(u8_t dev)
|
||||
{
|
||||
hal_gpio_init_out(onoff_state_arr[dev].led_gpio_pin, 1);
|
||||
}
|
||||
|
||||
static struct ble_npl_event button_event;
|
||||
|
||||
static void
|
||||
gpio_irq_handler(void *arg)
|
||||
{
|
||||
button_event.arg = arg;
|
||||
ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &button_event);
|
||||
}
|
||||
|
||||
void init_button(int button)
|
||||
{
|
||||
button_event.fn = button_pressed;
|
||||
|
||||
hal_gpio_irq_init(button, gpio_irq_handler, (void *)button,
|
||||
HAL_GPIO_TRIG_FALLING, HAL_GPIO_PULL_UP);
|
||||
hal_gpio_irq_enable(button);
|
||||
}
|
||||
|
||||
static void
|
||||
blemesh_on_reset(int reason)
|
||||
{
|
||||
BLE_HS_LOG(ERROR, "Resetting state; reason=%d\n", reason);
|
||||
}
|
||||
|
||||
static 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");
|
||||
}
|
||||
|
||||
int ble_boot(void)
|
||||
{
|
||||
#ifdef ARCH_sim
|
||||
mcu_sim_parse_args(argc, argv);
|
||||
#endif
|
||||
|
||||
BT_INFO("Initializing...");
|
||||
|
||||
/* Initialize the button debouncer */
|
||||
last_time = k_uptime_get_32();
|
||||
|
||||
/* Initialize button worker task*/
|
||||
ble_npl_callout_init(&sw.button_work, nimble_port_get_dflt_eventq(),
|
||||
button_pressed_worker, &sw);
|
||||
|
||||
/* Initialize button count timer */
|
||||
ble_npl_callout_init(&sw.button_timer, nimble_port_get_dflt_eventq(),
|
||||
button_cnt_timer, &sw);
|
||||
|
||||
/* Initialize LED's */
|
||||
init_led(0);
|
||||
init_led(1);
|
||||
init_led(2);
|
||||
init_led(3);
|
||||
|
||||
init_button(BUTTON_1);
|
||||
init_button(BUTTON_2);
|
||||
init_button(BUTTON_3);
|
||||
init_button(BUTTON_4);
|
||||
|
||||
init_pub();
|
||||
|
||||
/* 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;
|
||||
|
||||
bt_mesh_register_gatt();
|
||||
|
||||
extern void nimble_port_run(void);
|
||||
nimble_port_tencentos_tiny_init(nimble_port_run);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
k_task_t ble_boot_task;
|
||||
k_stack_t ble_boot_stack[512];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
|
||||
/* Initialize OS */
|
||||
tos_knl_init();
|
||||
|
||||
nimble_port_init();
|
||||
|
||||
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
|
||||
4,
|
||||
ble_boot_stack, sizeof(ble_boot_stack),
|
||||
0);
|
||||
tos_knl_start();
|
||||
}
|
||||
|
101
examples/nimble_mesh_models_example_2/README.md
Normal file
101
examples/nimble_mesh_models_example_2/README.md
Normal file
@@ -0,0 +1,101 @@
|
||||
#### Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
|
||||
|
||||
##### Overview
|
||||
********
|
||||
|
||||
This is a application demonstrating a Bluetooth mesh node in
|
||||
which Root element has following models
|
||||
|
||||
- Generic OnOff Server
|
||||
- Generic OnOff Client
|
||||
- Generic Level Server
|
||||
- Generic Level Client
|
||||
- Generic 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.
|
||||
|
96
examples/nimble_mesh_models_example_2/app_gpio.c
Normal file
96
examples/nimble_mesh_models_example_2/app_gpio.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 "mesh/mesh.h"
|
||||
|
||||
#include "app_gpio.h"
|
||||
#include "publisher.h"
|
||||
|
||||
int button_device[] = {
|
||||
BUTTON_1,
|
||||
BUTTON_2,
|
||||
BUTTON_3,
|
||||
BUTTON_4,
|
||||
};
|
||||
|
||||
int led_device[] = {
|
||||
LED_1,
|
||||
LED_2,
|
||||
LED_3,
|
||||
LED_4,
|
||||
};
|
||||
|
||||
static struct ble_npl_callout button_work;
|
||||
|
||||
static void button_pressed(struct ble_npl_event *ev)
|
||||
{
|
||||
ble_npl_callout_reset(&button_work, 0);
|
||||
}
|
||||
|
||||
static struct ble_npl_event button_event;
|
||||
|
||||
static void gpio_irq_handler(void *arg)
|
||||
{
|
||||
button_event.arg = arg;
|
||||
ble_npl_eventq_put(nimble_port_get_dflt_eventq(), &button_event);
|
||||
}
|
||||
|
||||
void app_gpio_init(void)
|
||||
{
|
||||
/* LEDs configiuratin & setting */
|
||||
|
||||
#if 0
|
||||
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 */
|
||||
|
||||
ble_npl_callout_init(&button_work, nimble_port_get_dflt_eventq(), 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]);
|
||||
#endif
|
||||
}
|
||||
|
36
examples/nimble_mesh_models_example_2/app_gpio.h
Normal file
36
examples/nimble_mesh_models_example_2/app_gpio.h
Normal file
@@ -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
|
116
examples/nimble_mesh_models_example_2/ble_mesh.c
Normal file
116
examples/nimble_mesh_models_example_2/ble_mesh.c
Normal file
@@ -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();
|
||||
}
|
73
examples/nimble_mesh_models_example_2/ble_mesh.h
Normal file
73
examples/nimble_mesh_models_example_2/ble_mesh.h
Normal file
@@ -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
|
||||
|
33
examples/nimble_mesh_models_example_2/common.h
Normal file
33
examples/nimble_mesh_models_example_2/common.h
Normal file
@@ -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
|
2778
examples/nimble_mesh_models_example_2/device_composition.c
Normal file
2778
examples/nimble_mesh_models_example_2/device_composition.c
Normal file
File diff suppressed because it is too large
Load Diff
177
examples/nimble_mesh_models_example_2/device_composition.h
Normal file
177
examples/nimble_mesh_models_example_2/device_composition.h
Normal file
@@ -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
|
365
examples/nimble_mesh_models_example_2/main.c
Normal file
365
examples/nimble_mesh_models_example_2/main.c
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* 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 "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;
|
||||
|
||||
|
||||
///////////////////////
|
||||
// stub-s
|
||||
|
||||
/*
|
||||
* The "pull" of the gpio. This is either an input or an output.
|
||||
*/
|
||||
enum hal_gpio_pull {
|
||||
/** Pull-up/down not enabled */
|
||||
HAL_GPIO_PULL_NONE = 0,
|
||||
/** Pull-up enabled */
|
||||
HAL_GPIO_PULL_UP = 1,
|
||||
/** Pull-down enabled */
|
||||
HAL_GPIO_PULL_DOWN = 2
|
||||
};
|
||||
typedef enum hal_gpio_pull hal_gpio_pull_t;
|
||||
|
||||
/*
|
||||
* IRQ trigger type.
|
||||
*/
|
||||
enum hal_gpio_irq_trigger {
|
||||
HAL_GPIO_TRIG_NONE = 0,
|
||||
/** IRQ occurs on rising edge */
|
||||
HAL_GPIO_TRIG_RISING = 1,
|
||||
/** IRQ occurs on falling edge */
|
||||
HAL_GPIO_TRIG_FALLING = 2,
|
||||
/** IRQ occurs on either edge */
|
||||
HAL_GPIO_TRIG_BOTH = 3,
|
||||
/** IRQ occurs when line is low */
|
||||
HAL_GPIO_TRIG_LOW = 4,
|
||||
/** IRQ occurs when line is high */
|
||||
HAL_GPIO_TRIG_HIGH = 5
|
||||
};
|
||||
typedef enum hal_gpio_irq_trigger hal_gpio_irq_trig_t;
|
||||
|
||||
|
||||
/* Function proto for GPIO irq handler functions */
|
||||
typedef void (*hal_gpio_irq_handler_t)(void *arg);
|
||||
|
||||
int hal_gpio_irq_init(int pin, hal_gpio_irq_handler_t handler, void *arg,
|
||||
hal_gpio_irq_trig_t trig, hal_gpio_pull_t pull)
|
||||
{
|
||||
// printf("gpio irq init\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hal_gpio_irq_enable(int pin)
|
||||
{
|
||||
// printf("gpio irq enable\n");
|
||||
}
|
||||
|
||||
void hal_gpio_init_out(int led, int s)
|
||||
{
|
||||
// printf("gpio init out\n");
|
||||
}
|
||||
|
||||
void hal_gpio_write(int led, int s)
|
||||
{
|
||||
// printf("led[%d]: %s\n", s == 0 ? "OFF" : "ON");
|
||||
}
|
||||
|
||||
int hal_gpio_read(int pin)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int __atomic_load_4(int *p)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
int __atomic_fetch_and_4(int *p, int v)
|
||||
{
|
||||
return *p & v;
|
||||
}
|
||||
|
||||
int __atomic_fetch_or_4(int *p, int v)
|
||||
{
|
||||
return *p | v;
|
||||
}
|
||||
|
||||
int __atomic_exchange_4(int *p, int v)
|
||||
{
|
||||
int old = *p;
|
||||
*p = v;
|
||||
return old;
|
||||
}
|
||||
|
||||
void unreachable(void)
|
||||
{
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
|
||||
|
||||
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;
|
||||
ble_npl_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 ble_npl_event *dummy)
|
||||
{
|
||||
reset_counter = 0;
|
||||
save_on_flash(RESET_COUNTER);
|
||||
printk("Reset Counter set to Zero\n");
|
||||
}
|
||||
|
||||
struct ble_npl_callout reset_counter_timer;
|
||||
|
||||
static void init_timers(void)
|
||||
{
|
||||
|
||||
ble_npl_callout_init(&reset_counter_timer, nimble_port_get_dflt_eventq(),
|
||||
reset_counter_timer_handler, NULL);
|
||||
ble_npl_callout_reset(&reset_counter_timer,
|
||||
ble_npl_time_ms_to_ticks32(K_MSEC(7000)));
|
||||
|
||||
no_transition_work_init();
|
||||
}
|
||||
|
||||
void bt_initialized(void)
|
||||
{
|
||||
light_default_status_init();
|
||||
|
||||
update_light_state();
|
||||
|
||||
randomize_publishers_TID();
|
||||
|
||||
short_time_multireset_bt_mesh_unprovisioning();
|
||||
}
|
||||
|
||||
int ble_boot(void)
|
||||
{
|
||||
#ifdef ARCH_sim
|
||||
mcu_sim_parse_args(argc, argv);
|
||||
#endif
|
||||
|
||||
light_default_var_init();
|
||||
|
||||
app_gpio_init();
|
||||
|
||||
init_timers();
|
||||
|
||||
transition_timers_init();
|
||||
|
||||
init_pub();
|
||||
|
||||
#if 0 // disable this...
|
||||
ps_settings_init();
|
||||
#endif
|
||||
|
||||
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;
|
||||
|
||||
extern void nimble_port_run(void);
|
||||
nimble_port_tencentos_tiny_init(nimble_port_run);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
k_task_t ble_boot_task;
|
||||
k_stack_t ble_boot_stack[512];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
|
||||
/* Initialize OS */
|
||||
tos_knl_init();
|
||||
|
||||
nimble_port_init();
|
||||
|
||||
tos_task_create(&ble_boot_task, "boot", ble_boot, NULL,
|
||||
4,
|
||||
ble_boot_stack, sizeof(ble_boot_stack),
|
||||
0);
|
||||
tos_knl_start();
|
||||
}
|
@@ -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 ble_npl_event *work)
|
||||
{
|
||||
gen_onoff_publish(&root_models[2]);
|
||||
gen_level_publish(&root_models[4]);
|
||||
light_lightness_publish(&root_models[11]);
|
||||
light_lightness_linear_publish(&root_models[11]);
|
||||
light_ctl_publish(&root_models[14]);
|
||||
|
||||
gen_level_publish(&s0_models[0]);
|
||||
light_ctl_temp_publish(&s0_models[2]);
|
||||
}
|
||||
|
||||
struct ble_npl_callout unsolicitedly_publish_states_work;
|
||||
|
||||
static void unsolicitedly_publish_states_timer_handler(struct ble_npl_event *dummy)
|
||||
{
|
||||
ble_npl_callout_reset(&unsolicitedly_publish_states_work, 0);
|
||||
}
|
||||
|
||||
struct ble_npl_callout unsolicitedly_publish_states_timer;
|
||||
|
||||
static void save_lightness_temp_last_values_timer_handler(struct ble_npl_event *dummy)
|
||||
{
|
||||
save_on_flash(LIGHTNESS_TEMP_LAST_STATE);
|
||||
}
|
||||
|
||||
struct ble_npl_callout save_lightness_temp_last_values_timer;
|
||||
|
||||
static void no_transition_work_handler(struct ble_npl_event *work)
|
||||
{
|
||||
ble_npl_callout_reset(&unsolicitedly_publish_states_timer,
|
||||
ble_npl_time_ms_to_ticks32(K_MSEC(5000)));
|
||||
|
||||
/* If Lightness & Temperature values remains stable for
|
||||
* 10 Seconds then & then only get stored on SoC flash.
|
||||
*/
|
||||
if (gen_power_onoff_srv_user_data.onpowerup == STATE_RESTORE) {
|
||||
ble_npl_callout_reset(&save_lightness_temp_last_values_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(10000)));
|
||||
}
|
||||
}
|
||||
|
||||
struct ble_npl_callout no_transition_work;
|
||||
|
||||
void no_transition_work_init(void)
|
||||
{
|
||||
ble_npl_callout_init(&no_transition_work, nimble_port_get_dflt_eventq(),
|
||||
no_transition_work_handler, NULL);
|
||||
ble_npl_callout_init(&save_lightness_temp_last_values_timer,
|
||||
nimble_port_get_dflt_eventq(),
|
||||
save_lightness_temp_last_values_timer_handler,
|
||||
NULL);
|
||||
ble_npl_callout_init(&unsolicitedly_publish_states_work, nimble_port_get_dflt_eventq(),
|
||||
unsolicitedly_publish_states_work_handler, NULL);
|
||||
ble_npl_callout_init(&unsolicitedly_publish_states_timer, nimble_port_get_dflt_eventq(),
|
||||
unsolicitedly_publish_states_timer_handler, NULL);
|
||||
}
|
@@ -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
|
265
examples/nimble_mesh_models_example_2/publisher.c
Normal file
265
examples/nimble_mesh_models_example_2/publisher.c
Normal file
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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 "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 ble_npl_event *work)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (is_randomization_of_TIDs_done == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (button_read(button_device[0]) == 0) {
|
||||
#if defined(ONOFF)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(ONOFF_TT)
|
||||
bt_mesh_model_msg_init(root_models[3].pub->msg,
|
||||
BT_MESH_MODEL_OP_GEN_ONOFF_SET_UNACK);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x01);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, tid_onoff++);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x45);
|
||||
net_buf_simple_add_u8(root_models[3].pub->msg, 0x28);
|
||||
err = bt_mesh_model_publish(&root_models[3]);
|
||||
#elif defined(VND_MODEL_TEST)
|
||||
bt_mesh_model_msg_init(vnd_models[0].pub->msg,
|
||||
BT_MESH_MODEL_OP_3(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);
|
||||
}
|
||||
}
|
||||
|
46
examples/nimble_mesh_models_example_2/publisher.h
Normal file
46
examples/nimble_mesh_models_example_2/publisher.h
Normal file
@@ -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 ble_npl_event *work);
|
||||
|
||||
#endif
|
308
examples/nimble_mesh_models_example_2/state_binding.c
Normal file
308
examples/nimble_mesh_models_example_2/state_binding.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
|
53
examples/nimble_mesh_models_example_2/state_binding.h
Normal file
53
examples/nimble_mesh_models_example_2/state_binding.h
Normal file
@@ -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
|
266
examples/nimble_mesh_models_example_2/storage.c
Normal file
266
examples/nimble_mesh_models_example_2/storage.c
Normal file
@@ -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 "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;
|
||||
|
||||
#if 0
|
||||
|
||||
static void save_reset_counter(void)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
settings_str_from_bytes(&reset_counter, sizeof(reset_counter), buf,
|
||||
sizeof(buf));
|
||||
|
||||
settings_save_one("ps/rc", buf);
|
||||
}
|
||||
|
||||
static void save_gen_def_trans_time_state(void)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
settings_str_from_bytes(&gen_def_trans_time_srv_user_data.tt,
|
||||
sizeof(gen_def_trans_time_srv_user_data.tt),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/gdtt", buf);
|
||||
}
|
||||
|
||||
static void save_gen_onpowerup_state(void)
|
||||
{
|
||||
char buf[5];
|
||||
|
||||
settings_str_from_bytes(&gen_power_onoff_srv_user_data.onpowerup,
|
||||
sizeof(gen_power_onoff_srv_user_data.onpowerup),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/gpo", buf);
|
||||
|
||||
if (gen_power_onoff_srv_user_data.onpowerup == 0x02) {
|
||||
save_on_flash(LIGHTNESS_TEMP_LAST_STATE);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_lightness_temp_def_state(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_ctl_srv_user_data.lightness_temp_def =
|
||||
(u32_t) ((light_ctl_srv_user_data.lightness_def << 16) |
|
||||
light_ctl_srv_user_data.temp_def);
|
||||
|
||||
settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_def,
|
||||
sizeof(light_ctl_srv_user_data.lightness_temp_def),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/ltd", buf);
|
||||
}
|
||||
|
||||
static void save_lightness_temp_last_state(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_ctl_srv_user_data.lightness_temp_last =
|
||||
(u32_t) ((light_ctl_srv_user_data.lightness << 16) |
|
||||
light_ctl_srv_user_data.temp);
|
||||
|
||||
settings_str_from_bytes(&light_ctl_srv_user_data.lightness_temp_last,
|
||||
sizeof(light_ctl_srv_user_data.lightness_temp_last),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/ltl", buf);
|
||||
|
||||
printk("Light CTL Last values have beed saved !!\n");
|
||||
}
|
||||
|
||||
static void save_lightness_range(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_lightness_srv_user_data.lightness_range =
|
||||
(u32_t) ((light_lightness_srv_user_data.light_range_max << 16) |
|
||||
light_lightness_srv_user_data.light_range_min);
|
||||
|
||||
settings_str_from_bytes(&light_lightness_srv_user_data.lightness_range,
|
||||
sizeof(light_lightness_srv_user_data.lightness_range),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/lr", buf);
|
||||
}
|
||||
|
||||
static void save_temperature_range(void)
|
||||
{
|
||||
char buf[12];
|
||||
|
||||
light_ctl_srv_user_data.temperature_range =
|
||||
(u32_t) ((light_ctl_srv_user_data.temp_range_max << 16) |
|
||||
light_ctl_srv_user_data.temp_range_min);
|
||||
|
||||
settings_str_from_bytes(&light_ctl_srv_user_data.temperature_range,
|
||||
sizeof(light_ctl_srv_user_data.temperature_range),
|
||||
buf, sizeof(buf));
|
||||
|
||||
settings_save_one("ps/tr", buf);
|
||||
}
|
||||
|
||||
static void storage_work_handler(struct ble_npl_event *work)
|
||||
{
|
||||
switch (storage_id) {
|
||||
case RESET_COUNTER:
|
||||
save_reset_counter();
|
||||
break;
|
||||
case GEN_DEF_TRANS_TIME_STATE:
|
||||
save_gen_def_trans_time_state();
|
||||
break;
|
||||
case GEN_ONPOWERUP_STATE:
|
||||
save_gen_onpowerup_state();
|
||||
break;
|
||||
case LIGHTNESS_TEMP_DEF_STATE:
|
||||
save_lightness_temp_def_state();
|
||||
break;
|
||||
case LIGHTNESS_TEMP_LAST_STATE:
|
||||
save_lightness_temp_last_state();
|
||||
break;
|
||||
case LIGHTNESS_RANGE:
|
||||
save_lightness_range();
|
||||
break;
|
||||
case TEMPERATURE_RANGE:
|
||||
save_temperature_range();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct ble_npl_callout storage_work;
|
||||
|
||||
void save_on_flash(u8_t id)
|
||||
{
|
||||
storage_id = id;
|
||||
ble_npl_callout_reset(&storage_work, 0);
|
||||
}
|
||||
|
||||
static int ps_set(int argc, char **argv, char *val)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (argc == 1) {
|
||||
if (!strcmp(argv[0], "rc")) {
|
||||
len = sizeof(reset_counter);
|
||||
|
||||
return settings_bytes_from_str(val, &reset_counter,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "gdtt")) {
|
||||
len = sizeof(gen_def_trans_time_srv_user_data.tt);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&gen_def_trans_time_srv_user_data.tt, &len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "gpo")) {
|
||||
len = sizeof(gen_power_onoff_srv_user_data.onpowerup);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&gen_power_onoff_srv_user_data.onpowerup, &len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "ltd")) {
|
||||
len = sizeof(light_ctl_srv_user_data.lightness_temp_def);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_ctl_srv_user_data.lightness_temp_def,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "ltl")) {
|
||||
len = sizeof(light_ctl_srv_user_data.
|
||||
lightness_temp_last);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_ctl_srv_user_data.lightness_temp_last,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "lr")) {
|
||||
len = sizeof(light_lightness_srv_user_data.
|
||||
lightness_range);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_lightness_srv_user_data.lightness_range,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[0], "tr")) {
|
||||
len = sizeof(light_ctl_srv_user_data.
|
||||
temperature_range);
|
||||
|
||||
return settings_bytes_from_str(val,
|
||||
&light_ctl_srv_user_data. temperature_range,
|
||||
&len);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static struct conf_handler ps_settings = {
|
||||
.ch_name = "ps",
|
||||
.ch_set = ps_set,
|
||||
};
|
||||
|
||||
int ps_settings_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
ble_npl_callout_init(&storage_work, nimble_port_get_dflt_eventq(),
|
||||
storage_work_handler, NULL);
|
||||
|
||||
err = conf_register(&ps_settings);
|
||||
if (err) {
|
||||
printk("ps_settings_register failed (err %d)", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void save_on_flash(u8_t id)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
47
examples/nimble_mesh_models_example_2/storage.h
Normal file
47
examples/nimble_mesh_models_example_2/storage.h
Normal file
@@ -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 ble_npl_callout storage_work;
|
||||
|
||||
int ps_settings_init(void);
|
||||
void save_on_flash(u8_t id);
|
||||
|
||||
#endif
|
792
examples/nimble_mesh_models_example_2/transition.c
Normal file
792
examples/nimble_mesh_models_example_2/transition.c
Normal file
@@ -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 ble_npl_callout onoff_work;
|
||||
struct ble_npl_callout level_lightness_work;
|
||||
struct ble_npl_callout level_temp_work;
|
||||
struct ble_npl_callout light_lightness_actual_work;
|
||||
struct ble_npl_callout light_lightness_linear_work;
|
||||
struct ble_npl_callout light_ctl_work;
|
||||
struct ble_npl_callout light_ctl_temp_work;
|
||||
|
||||
struct ble_npl_callout dummy_timer;
|
||||
|
||||
u8_t transition_type, default_tt;
|
||||
u32_t *ptr_counter;
|
||||
struct ble_npl_callout *ptr_timer = &dummy_timer;
|
||||
|
||||
struct transition lightness_transition, temp_transition;
|
||||
|
||||
/* Function to calculate Remaining Time (Start) */
|
||||
|
||||
void calculate_rt(struct transition *transition)
|
||||
{
|
||||
u8_t steps, resolution;
|
||||
s32_t duration_remainder;
|
||||
s64_t now;
|
||||
|
||||
if (transition->just_started) {
|
||||
transition->rt = transition->tt;
|
||||
} else {
|
||||
now = k_uptime_get();
|
||||
duration_remainder = transition->total_duration -
|
||||
(now - transition->start_timestamp);
|
||||
|
||||
if (duration_remainder > 620000) {
|
||||
/* > 620 seconds -> resolution = 0b11 [10 minutes] */
|
||||
resolution = 0x03;
|
||||
steps = duration_remainder / 600000;
|
||||
} else if (duration_remainder > 62000) {
|
||||
/* > 62 seconds -> resolution = 0b10 [10 seconds] */
|
||||
resolution = 0x02;
|
||||
steps = duration_remainder / 10000;
|
||||
} else if (duration_remainder > 6200) {
|
||||
/* > 6.2 seconds -> resolution = 0b01 [1 seconds] */
|
||||
resolution = 0x01;
|
||||
steps = duration_remainder / 1000;
|
||||
} else if (duration_remainder > 0) {
|
||||
/* <= 6.2 seconds -> resolution = 0b00 [100 ms] */
|
||||
resolution = 0x00;
|
||||
steps = duration_remainder / 100;
|
||||
} else {
|
||||
resolution = 0x00;
|
||||
steps = 0x00;
|
||||
}
|
||||
|
||||
transition->rt = (resolution << 6) | steps;
|
||||
}
|
||||
}
|
||||
|
||||
/* Function to calculate Remaining Time (End) */
|
||||
|
||||
static void bound_states_transition_type_reassignment(u8_t type)
|
||||
{
|
||||
switch (type) {
|
||||
case ONOFF:
|
||||
case LEVEL:
|
||||
case ACTUAL:
|
||||
case LINEAR:
|
||||
light_ctl_srv_user_data.transition = &lightness_transition;
|
||||
break;
|
||||
case CTL:
|
||||
light_ctl_srv_user_data.transition = &lightness_transition;
|
||||
gen_level_srv_s0_user_data.transition = &lightness_transition;
|
||||
break;
|
||||
case LEVEL_TEMP:
|
||||
case CTL_TEMP:
|
||||
gen_level_srv_s0_user_data.transition = &temp_transition;
|
||||
light_ctl_srv_user_data.transition = &temp_transition;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tt_values_calculator(struct transition *transition)
|
||||
{
|
||||
u8_t steps_multiplier, resolution;
|
||||
|
||||
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 ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
} else {
|
||||
state->transition->start_timestamp = k_uptime_get();
|
||||
|
||||
if (state->target_onoff == STATE_ON) {
|
||||
state->onoff = STATE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state->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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void level_lightness_work_handler(struct ble_npl_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();
|
||||
|
||||
ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void level_temp_work_handler(struct ble_npl_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();
|
||||
|
||||
ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_lightness_actual_work_handler(struct ble_npl_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();
|
||||
|
||||
ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_lightness_linear_work_handler(struct ble_npl_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();
|
||||
|
||||
ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_ctl_work_handler(struct ble_npl_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();
|
||||
|
||||
ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void light_ctl_temp_work_handler(struct ble_npl_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();
|
||||
|
||||
ble_npl_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();
|
||||
|
||||
ble_npl_callout_stop(ptr_timer);
|
||||
}
|
||||
}
|
||||
|
||||
static void dummy_timer_handler(struct ble_npl_event *ev)
|
||||
{ }
|
||||
|
||||
static void onoff_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct generic_onoff_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&onoff_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void level_lightness_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct generic_level_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&level_lightness_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void level_temp_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct generic_level_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&level_temp_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_lightness_actual_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct light_lightness_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&light_lightness_actual_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_lightness_linear_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct light_lightness_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&light_lightness_linear_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_ctl_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct light_ctl_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&light_ctl_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
|
||||
static void light_ctl_temp_tt_handler(struct ble_npl_event *ev)
|
||||
{
|
||||
struct light_ctl_state *state = ev->arg;
|
||||
|
||||
assert(state != NULL);
|
||||
ble_npl_callout_reset(&light_ctl_temp_work, 0);
|
||||
ble_npl_callout_reset(&state->transition->timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(state->transition->quo_tt)));
|
||||
}
|
||||
/* Timers related handlers & threads (End) */
|
||||
|
||||
/* Messages handlers (Start) */
|
||||
void onoff_handler(struct generic_onoff_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
onoff_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void level_lightness_handler(struct generic_level_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
level_lightness_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void level_temp_handler(struct generic_level_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
level_temp_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_lightness_actual_handler(struct light_lightness_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
light_lightness_actual_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_lightness_linear_handler(struct light_lightness_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
light_lightness_linear_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_ctl_handler(struct light_ctl_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
light_ctl_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
|
||||
void light_ctl_temp_handler(struct light_ctl_state *state)
|
||||
{
|
||||
ptr_timer = &state->transition->timer;
|
||||
|
||||
ble_npl_callout_init(ptr_timer, nimble_port_get_dflt_eventq(),
|
||||
light_ctl_temp_tt_handler, NULL);
|
||||
ptr_timer->ev.arg = state;
|
||||
ble_npl_callout_reset(ptr_timer,
|
||||
ble_npl_time_ms_to_ticks32(
|
||||
K_MSEC(5 * state->transition->delay)));
|
||||
}
|
||||
/* Messages handlers (End) */
|
||||
|
||||
void transition_timers_init(void)
|
||||
{
|
||||
ble_npl_callout_init(&onoff_work, nimble_port_get_dflt_eventq(),
|
||||
onoff_work_handler, NULL);
|
||||
|
||||
ble_npl_callout_init(&level_lightness_work, nimble_port_get_dflt_eventq(),
|
||||
level_lightness_work_handler, NULL);
|
||||
ble_npl_callout_init(&level_temp_work, nimble_port_get_dflt_eventq(),
|
||||
level_temp_work_handler, NULL);
|
||||
|
||||
ble_npl_callout_init(&light_lightness_actual_work,
|
||||
nimble_port_get_dflt_eventq(),
|
||||
light_lightness_actual_work_handler, NULL);
|
||||
ble_npl_callout_init(&light_lightness_linear_work,
|
||||
nimble_port_get_dflt_eventq(),
|
||||
light_lightness_linear_work_handler, NULL);
|
||||
|
||||
ble_npl_callout_init(&light_ctl_work, nimble_port_get_dflt_eventq(),
|
||||
light_ctl_work_handler, NULL);
|
||||
ble_npl_callout_init(&light_ctl_temp_work, nimble_port_get_dflt_eventq(),
|
||||
light_ctl_temp_work_handler, NULL);
|
||||
|
||||
ble_npl_callout_init(&dummy_timer, nimble_port_get_dflt_eventq(),
|
||||
dummy_timer_handler, NULL);
|
||||
}
|
||||
|
87
examples/nimble_mesh_models_example_2/transition.h
Normal file
87
examples/nimble_mesh_models_example_2/transition.h
Normal file
@@ -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 ble_npl_callout timer;
|
||||
};
|
||||
|
||||
extern u8_t transition_type, default_tt;
|
||||
extern u32_t *ptr_counter;
|
||||
extern struct ble_npl_callout *ptr_timer;
|
||||
|
||||
extern struct transition lightness_transition, temp_transition;
|
||||
|
||||
extern struct ble_npl_callout dummy_timer;
|
||||
|
||||
void calculate_rt(struct transition *transition);
|
||||
|
||||
|
||||
void onoff_tt_values(struct generic_onoff_state *state, u8_t tt, u8_t delay);
|
||||
void level_tt_values(struct generic_level_state *state, u8_t tt, u8_t delay);
|
||||
void light_lightness_actual_tt_values(struct light_lightness_state *state,
|
||||
u8_t tt, u8_t delay);
|
||||
void light_lightness_linear_tt_values(struct light_lightness_state *state,
|
||||
u8_t tt, u8_t delay);
|
||||
void light_ctl_tt_values(struct light_ctl_state *state, u8_t tt, u8_t delay);
|
||||
void light_ctl_temp_tt_values(struct light_ctl_state *state,
|
||||
u8_t tt, u8_t delay);
|
||||
|
||||
void onoff_handler(struct generic_onoff_state *state);
|
||||
void level_lightness_handler(struct generic_level_state *state);
|
||||
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
|
Reference in New Issue
Block a user