add nimble mesh example

need meshctl installed on raspberrypi. nimble offical samples have a lot of pit ...
This commit is contained in:
daishengdong
2019-11-28 11:12:16 +08:00
parent b2afa0c172
commit b2983383bb
192 changed files with 41667 additions and 279927 deletions

564
examples/nimble_mesh/main.c Normal file
View 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();
}

View 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
}

View 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

View 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();
}

View 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

View 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__ */

View 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.

View 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();
}

View File

@@ -0,0 +1,101 @@
#### Bluetooth: Mesh Generic OnOff, Generic Level, Lighting & Vendor Models
##### Overview
********
This is a application demonstrating a Bluetooth mesh node in
which Root element has following models
- Generic OnOff Server
- Generic OnOff Client
- Generic Level Server
- Generic Level Client
- Generic 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.

View 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
}

View 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

View 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();
}

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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();
}

View File

@@ -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);
}

View File

@@ -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

View 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);
}
}

View 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

View 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;
}
}

View 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

View 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

View 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

View 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);
}

View 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