Hello everybody,
I'm trying to develop simple time synchronization system upon mesh time model, but after sending bt_mesh_time_cli_time_set, first of all my time_update_cb in time_server model is not invoked by handle_time_set function, and then time_status handler should be called after my time_client receives a time status message, but again there's no such action, so i don't really get why it's behaving that way.
This is client model_handler code, where I think whole client init routine is set up properly, same for bt_mesh_time_status struct in set_tai function:
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh/models.h>
#include <dk_buttons_and_leds.h>
#include "model_handler.h"
#define GET_DATA_INTERVAL 3000
static struct bt_mesh_time_status bt_time_status;
static struct bt_mesh_time_tai tai;
static struct tm timeptr = {
.tm_year = 2021-1900,
.tm_mon = 05,
.tm_mday = 24,
.tm_hour = 23,
.tm_min = 51,
.tm_sec = 59,
};
static void time_status(struct bt_mesh_time_cli *cli, struct bt_mesh_msg_ctx *ctx, const struct bt_mesh_time_status *status){
printk("time_status");
printk("Tai sec: %"PRId64"\n", status->tai.sec);
printk("Tai subsec: %"PRId64"\n", status->tai.subsec);
}
static const struct bt_mesh_time_cli_handlers bt_mesh_time_cli_handlers = {
.time_status = time_status,
};
static struct bt_mesh_time_cli time_cli = BT_MESH_TIME_CLI_INIT(&bt_mesh_time_cli_handlers);
static void set_tai(struct k_work *work){
printk("set_tai\n");
int err;
err = ts_to_tai(&tai, &timeptr);
if(err){
printk("ts_to_tai err (%d)", err);
}
printk("Tai sec: %"PRId64"\n", tai.sec);
printk("Tai subsec: %"PRId64"\n", tai.subsec);
bt_time_status.tai = tai;
bt_time_status.is_authority = true;
err = bt_mesh_time_cli_time_set(&time_cli, NULL, &bt_time_status, NULL);
if(err){
printk("Error setting server time (%d)\n", err);
}
printk("Server time set (%d)\n", err);
}
K_WORK_DEFINE(set_tai_work, set_tai);
/* Set up a repeating delayed work to blink the DK's LEDs when attention is
* requested.
*/
static struct k_delayed_work attention_blink_work;
static void attention_blink(struct k_work *work){
static int idx;
const uint8_t pattern[] = {
BIT(0) | BIT(1),
BIT(1) | BIT(2),
BIT(2) | BIT(3),
BIT(3) | BIT(0),
};
dk_set_leds(pattern[idx++ % ARRAY_SIZE(pattern)]);
k_delayed_work_submit(&attention_blink_work, K_MSEC(30));
}
static void attention_on(struct bt_mesh_model *mod){
k_delayed_work_submit(&attention_blink_work, K_NO_WAIT);
}
static void attention_off(struct bt_mesh_model *mod){
k_delayed_work_cancel(&attention_blink_work);
dk_set_leds(DK_NO_LEDS_MSK);
}
static const struct bt_mesh_health_srv_cb health_srv_cb = {
.attn_on = attention_on,
.attn_off = attention_off,
};
static struct bt_mesh_health_srv health_srv = {
.cb = &health_srv_cb,
};
BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(1, BT_MESH_MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv, &health_pub),
BT_MESH_MODEL_TIME_CLI(&time_cli)), BT_MESH_MODEL_NONE),
};
static const struct bt_mesh_comp comp = {
.cid = CONFIG_BT_COMPANY_ID,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
static void button_handler_cb(uint32_t pressed, uint32_t changed){
printk("button_handler_cb\n");
int err = bt_mesh_time_cli_time_get(&time_cli, NULL, NULL);
if(err){
printk("Error time get (%d)\n", err);
}else{
printk("Time get ok\n");
}
if ((pressed & BIT(0))) {
k_work_submit(&set_tai_work);
}
}
static struct button_handler button_handler = {
.cb = button_handler_cb,
};
const struct bt_mesh_comp *model_handler_init(void){
k_delayed_work_init(&attention_blink_work, attention_blink);
dk_button_handler_add(&button_handler);
return ∁
}
Time_server:
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh/models.h>
#include <dk_buttons_and_leds.h>
#include "model_handler.h"
#include <sys/util.h>
#include <sys/printk.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
static void time_update_cb(struct bt_mesh_time_srv *srv, struct bt_mesh_msg_ctx *ctx, enum bt_mesh_time_update_types type);
static struct bt_mesh_time_srv time_srv = BT_MESH_TIME_SRV_INIT(&time_update_cb);
static void start_led(struct k_timer *dummy);
K_TIMER_DEFINE(my_led_timer, start_led, NULL);
const uint8_t pattern[] = {
BIT(0) | BIT(1),
BIT(1) | BIT(2),
BIT(2) | BIT(3),
BIT(3) | BIT(0),
};
static int32_t prev_pres;
/* The columns (temperature ranges) for relative
* runtime in a chip temperature
*/
static const struct bt_mesh_sensor_column columns[] = {
{ { 0 }, { 20 } },
{ { 20 }, { 25 } },
{ { 25 }, { 30 } },
{ { 30 }, { 100 } },
};
static const struct device *dev;
static uint32_t tot_temp_samps;
static uint32_t col_samps[ARRAY_SIZE(columns)];
static int chip_temp_get(struct bt_mesh_sensor *sensor,struct bt_mesh_msg_ctx *ctx, struct sensor_value *rsp){
int err;
sensor_sample_fetch(dev);
err = sensor_channel_get(dev, SENSOR_CHAN_DIE_TEMP, rsp);
if (err) {
printk("Error getting temperature sensor data (%d)\n", err);
}
for (int i = 0; i < ARRAY_SIZE(columns); ++i) {
if (bt_mesh_sensor_value_in_column(rsp, &columns[i])) {
col_samps[i]++;
break;
}
}
tot_temp_samps++;
return err;
}
static struct bt_mesh_sensor chip_temp = {
.type = &bt_mesh_sensor_present_dev_op_temp,
.get = chip_temp_get,
};
static int relative_runtime_in_chip_temp_get(struct bt_mesh_sensor *sensor, struct bt_mesh_msg_ctx *ctx,const struct bt_mesh_sensor_column *column, struct sensor_value *value){
if (tot_temp_samps) {
int32_t index = column - &columns[0];
uint8_t percent_steps = (200 * col_samps[index]) / tot_temp_samps;
value[0].val1 = percent_steps / 2;
value[0].val2 = (percent_steps % 2) * 500000;
} else {
value[0].val1 = 0;
value[0].val2 = 0;
}
value[1] = column->start;
value[2] = column->end;
return 0;
}
static struct bt_mesh_sensor rel_chip_temp_runtime = {
.type = &bt_mesh_sensor_rel_runtime_in_a_dev_op_temp_range,
.series = {columns,
ARRAY_SIZE(columns),
relative_runtime_in_chip_temp_get,
},
};
static struct bt_mesh_sensor presence_sensor = {
.type = &bt_mesh_sensor_presence_detected,
};
static int time_since_presence_detected_get(struct bt_mesh_sensor *sensor,struct bt_mesh_msg_ctx *ctx,struct sensor_value *rsp){
if (prev_pres) {
rsp->val1 = (k_uptime_get_32() - prev_pres) / MSEC_PER_SEC;
} else {
rsp->val1 = 0;
}
return 0;
}
static struct bt_mesh_sensor time_since_presence_detected = {
.type = &bt_mesh_sensor_time_since_presence_detected,
.get = time_since_presence_detected_get,
};
static struct bt_mesh_sensor *const sensors[] = {
&chip_temp,
&rel_chip_temp_runtime,
&presence_sensor,
&time_since_presence_detected,
};
static struct bt_mesh_sensor_srv sensor_srv = BT_MESH_SENSOR_SRV_INIT(sensors, ARRAY_SIZE(sensors));
struct k_timer my_led_timer;
static struct k_delayed_work attention_blink_work;
void my_work_handler(struct k_work *work){
printk("start_led\n");
int err;
/* This sensor value must be boolean -
* .val1 can only be '0' or '1' */
struct sensor_value val = {
.val1 = 1,
};
err = bt_mesh_sensor_srv_pub(&sensor_srv, NULL,&presence_sensor, &val);
if (err) {
printk("Error publishing presence (%d)\n", err);
}
//printk("publishing presence\n");
}
K_WORK_DEFINE(my_work, my_work_handler);
static void start_led(struct k_timer *dummy){
k_work_submit(&my_work);
}
static void time_update_cb(struct bt_mesh_time_srv *srv, struct bt_mesh_msg_ctx *ctx, enum bt_mesh_time_update_types type){
printk("time_update_cb\n");
time_srv.data.sync.status.tai = srv->data.sync.status.tai;
k_delayed_work_submit(&attention_blink_work, K_MSEC(30));
/*struct tm *today = bt_mesh_time_srv_localtime(&time_srv, k_uptime_get());
if (!today) {
return;
}
const char *weekdays[] = {
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
};
struct tm action = {
.tm_year = today->tm_year,
.tm_mon = today->tm_mon,
.tm_mday = today->tm_mday,
.tm_hour = today->tm_hour,
.tm_min = today->tm_min + 1,
.tm_sec = 59,
};
int64_t uptime = bt_mesh_time_srv_mktime(&time_srv, &action);
struct tm *a = bt_mesh_time_srv_localtime(&time_srv, uptime);
//printk("tm_year: %d, tm_mon: %d, tm_mday: %d, tm_hour: %d, tm_min: %d, tm_sec: %d\n", a->tm_year, a->tm_mon, a->tm_mday, a->tm_hour, a->tm_min, a->tm_sec);
int64_t period = uptime - k_uptime_get();
printk("Period: %"PRId64"\n", period);
if (uptime < 0) {
printk("uptime < 0\n");
return;
}*/
k_timer_start(&my_led_timer, K_SECONDS(59), K_NO_WAIT);
}
static void schedule_led(){
k_timer_start(&my_led_timer, K_SECONDS(59), K_NO_WAIT);
}
static struct k_delayed_work end_of_presence_work;
static void end_of_presence(struct k_work *work){
int err;
/* This sensor value must be boolean -
* .val1 can only be '0' or '1'
*/
struct sensor_value val = {
.val1 = 0,
};
err = bt_mesh_sensor_srv_pub(&sensor_srv, NULL, &presence_sensor, &val);
if (err) {
printk("Error publishing end of presence (%d)\n", err);
}
}
static void button_handler_cb(uint32_t pressed, uint32_t changed){
if ((pressed & BIT(0))) {
int err;
/* This sensor value must be boolean -
* .val1 can only be '0' or '1' */
struct sensor_value val = {
.val1 = 1,
};
err = bt_mesh_sensor_srv_pub(&sensor_srv, NULL,&presence_sensor, &val);
err = bt_mesh_time_srv_time_status_send(&time_srv, NULL);
if (err) {
printk("Error publishing presence (%d)\n", err);
}
prev_pres = k_uptime_get_32();
k_delayed_work_submit(&end_of_presence_work, K_MSEC(2000));
}
}
static struct button_handler button_handler = {
.cb = button_handler_cb,
};
/* Set up a repeating delayed work to blink the DK's LEDs when attention is
* requested.
*/
static void attention_blink(struct k_work *work){
static int idx;
dk_set_leds(pattern[idx++ % ARRAY_SIZE(pattern)]);
k_delayed_work_submit(&attention_blink_work, K_MSEC(30));
}
static void attention_on(struct bt_mesh_model *mod){
k_delayed_work_submit(&attention_blink_work, K_NO_WAIT);
}
static void attention_off(struct bt_mesh_model *mod){
k_delayed_work_cancel(&attention_blink_work);
dk_set_leds(DK_NO_LEDS_MSK);
}
static const struct bt_mesh_health_srv_cb health_srv_cb = {
.attn_on = attention_on,
.attn_off = attention_off,
};
static struct bt_mesh_health_srv health_srv = {
.cb = &health_srv_cb,
};
BT_MESH_HEALTH_PUB_DEFINE(health_pub, 0);
static struct bt_mesh_elem elements[] = {
BT_MESH_ELEM(1,BT_MESH_MODEL_LIST(BT_MESH_MODEL_CFG_SRV, BT_MESH_MODEL_HEALTH_SRV(&health_srv,&health_pub), BT_MESH_MODEL_SENSOR_SRV(&sensor_srv)),
BT_MESH_MODEL_NONE),
BT_MESH_ELEM(2, BT_MESH_MODEL_LIST(BT_MESH_MODEL_TIME_SRV(&time_srv)),BT_MESH_MODEL_NONE),
};
static const struct bt_mesh_comp comp = {
.cid = CONFIG_BT_COMPANY_ID,
.elem = elements,
.elem_count = ARRAY_SIZE(elements),
};
const struct bt_mesh_comp *model_handler_init(void){
//SENSOR
k_delayed_work_init(&attention_blink_work, attention_blink);
k_delayed_work_init(&end_of_presence_work, end_of_presence);
dev = device_get_binding(DT_PROP(DT_NODELABEL(temp), label));
if (dev == NULL) {
printk("Could not initiate temperature sensor\n");
} else {
printk("Temperature sensor (%s) initiated\n", dev->name);
}
dk_button_handler_add(&button_handler);
time_srv.data.sync.status.tai.sec = 677807519;
time_srv.data.sync.status.tai.subsec = 17716744536;
time_srv.data.sync.uptime = k_uptime_get();
//schedule_led();
return ∁
}
Additional infos:
- I'm using dongle as time_server and nrf52840dk as client
- Ncs v1.5.1
- Client was configured to publish to all nodes, same server
So if you have any ideas what's wrong/see any bugs in my code or have other sugestions, I'm appreciate them.