BlueSync - BLE Time Sync for Zephyr
High-precision time synchronization for BLE Mesh networks
Loading...
Searching...
No Matches
bluesync.c
Go to the documentation of this file.
1/*
2 * Copyright 2025 Tobias Moullet
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * File: bluesync.c
17 * Description: Private API for the BlueSync time synchronization module.
18 *
19 * Project: BlueSync - BLE Time Sync for Zephyr
20 * Repository: https://github.com/Tobi15/zephyr-bluesync-ble
21 */
22
23#include <zephyr/kernel.h>
24#include <zephyr/bluetooth/bluetooth.h>
25#include <zephyr/bluetooth/hci.h>
26#include <zephyr/bluetooth/mesh.h>
27#include <zephyr/sys/byteorder.h>
28#include <zephyr/sys/util.h>
29
30#include <math.h>
31
32#include <zephyr/sys/util.h>
33
34#if defined(CONFIG_BLUESYNC_USED_IN_MESH)
35#include <zephyr/bluetooth/mesh.h>
36#endif
37
38#include <bluesync/bluesync.h>
39#include "bluesync.h"
40#include "bs_state_machine.h"
41#include "bluesync_bitfields.h"
42#include "local_time.h"
43
44
45#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
47#endif
48
49#include <zephyr/logging/log.h>
50LOG_MODULE_REGISTER(bluesync, CONFIG_BLUESYNC_LOG_LEVEL);
51
52#define BT_UNIT_MS_TO_TICKS(_ms) ((_ms) * 8 / 5)
53#define BLUESYNC_BT_MIN_ADV_INT BT_UNIT_MS_TO_TICKS(30)
54#define BLUESYNC_BT_MAX_ADV_INT BT_UNIT_MS_TO_TICKS(60)
55#define BLUESYNC_BT_SCAN_INT BT_UNIT_MS_TO_TICKS(60)
56#define BLUESYNC_BT_SCAN_WIND_SIZE BT_UNIT_MS_TO_TICKS(60)
57
58//bluesync node param
59
60static struct bluesync_param param = {
61 .timeslot_index = 0,
62 .local = {
63 .timer_ticks = {0},
64 .bitfield = {0},
65 },
66 .local_mutex = Z_MUTEX_INITIALIZER(param.local_mutex),
67 .local_history = {
68 [0 ... BURST_WINDOWS_SIZE-1] = {
69 .timer_ticks = {0},
70 .bitfield = {0},
71 }
72 },
73 .local_head = 0,
74 .local_count = 0,
75 .local_history_mutex = Z_MUTEX_INITIALIZER(param.local_history_mutex),
76
77 .rcv = {
78 .timer_ticks = {0},
79 .bitfield = {0},
80 },
81 .rcv_mutex = Z_MUTEX_INITIALIZER(param.rcv_mutex),
82 .rcv_history = {
83 [0 ... BURST_WINDOWS_SIZE-1] = {
84 .timer_ticks = {0},
85 .bitfield = {0},
86 }
87 },
88 .rcv_head = 0,
89 .rcv_count = 0,
90 .rcv_history_mutex = Z_MUTEX_INITIALIZER(param.rcv_history_mutex),
91
92 .current_round_id = 0xFF,
93 .adv_param = BT_LE_ADV_PARAM_INIT(
94 BT_LE_ADV_OPT_EXT_ADV |
95 BT_LE_ADV_OPT_USE_IDENTITY |
96 BT_LE_ADV_OPT_CODED ,
99 NULL
100 ),
101 .scan_param = BT_LE_SCAN_PARAM_INIT(
102 BT_LE_SCAN_TYPE_PASSIVE,
103 BT_LE_SCAN_OPT_CODED |
104 BT_LE_SCAN_OPT_NO_1M,
107 ),
108 .mutex = Z_MUTEX_INITIALIZER(param.mutex),
109};
110
111// Define the stack space for the thread
112K_THREAD_STACK_DEFINE(bluesync_thread_stack, CONFIG_BLUESYNC_THREAD_STACK_SIZE);
113
114K_MSGQ_DEFINE(bluesync_rx_msgq, sizeof(struct bluesync_msg_client), 17, 1);
115K_SEM_DEFINE(bluesync_end_sync_sem, 0, 1);
116K_SEM_DEFINE(bluesync_start_new_sync_sem, 0, 1);
117K_SEM_DEFINE(bluesync_role_assign_sem, 0, 1);
118
120 memset(&elem->bitfield, 0, sizeof(elem->bitfield));
121 memset(&elem->timer_ticks, 0, sizeof(elem->timer_ticks));
122}
123
125 ,uint8_t pos
126 ,int64_t ticks
127#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
128 ,uint64_t est_ticks
129#endif
130 )
131{
132 elem->timer_ticks[pos] = ticks;
133#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
134 elem->remote_est_ticks[pos] = est_ticks;
135#endif
136 set_bit(&elem->bitfield[0], (size_t)pos);
137}
138
141
142 k_mutex_lock(&param.local_mutex, K_FOREVER);
143 {
145 }
146 k_mutex_unlock(&param.local_mutex);
147 k_mutex_lock(&param.rcv_mutex, K_FOREVER);
148 {
150 }
151 k_mutex_unlock(&param.rcv_mutex);
152}
153
155 double *slope,
156 double *offset,
157 size_t min_nb_timestamp)
158{
159
160 double sum_x = 0, sum_y = 0;
161 size_t n = 0;
162
163 // Accumulate
164 for (int burst = 0; burst < param.rcv_count; burst++) {
167
168 uint8_t burst_bitfield[NB_BYTES_BITFIELD] = {0};
170
171 for (int i = 0; i < SLOT_NUMBER; i++) {
172 if (is_bit_set(burst_bitfield, i)) {
173 sum_x += (double)local->timer_ticks[i];
174 sum_y += (double)rcv->timer_ticks[i];
175 n++;
176 }
177 }
178 }
179
180 if (n == 0) {
181 LOG_ERR("No valid data in history for regression.");
183 } else if (n < min_nb_timestamp) {
184 LOG_ERR("Not enough valid samples in history (min = %zu, got = %zu)", min_nb_timestamp, n);
186 }
187
188 double mean_x = sum_x / n;
189 double mean_y = sum_y / n;
190
191 double sum_cov = 0.0;
192 double sum_var = 0.0;
193
194 // Now second pass: accumulate covariance and variance
195 for (int burst = 0; burst < param.rcv_count; burst++) {
198
199 uint8_t burst_bitfield[NB_BYTES_BITFIELD] = {0};
201
202 for (int i = 0; i < SLOT_NUMBER; i++) {
203 if (is_bit_set(burst_bitfield, i)) {
204 double x = (double)local->timer_ticks[i] - mean_x;
205 double y = (double)rcv->timer_ticks[i] - mean_y;
206 sum_cov += x * y;
207 sum_var += x * x;
208 }
209 }
210 }
211
212 if (fabs(sum_var) < 1e-12) {
213 LOG_ERR("Variance too small → numerical instability (%e)", sum_var);
215 }
216
217 *slope = sum_cov / sum_var;
218 *offset = mean_y - (*slope * mean_x);
219
221}
222
223static void bluesync_decode_msg(struct bluesync_msg_client *msg, struct net_buf_simple *buf){
224 msg->client_timer_ticks = k_uptime_ticks();
225 msg->rcv.round_id = net_buf_simple_pull_u8(buf);
226 msg->rcv.index_timeslot = net_buf_simple_pull_u8(buf);
227 msg->rcv.master_timer_ticks = net_buf_simple_pull_le64(buf);
228#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
229 msg->master_estimation_ticks = get_logical_time_ticks();
230#endif
231}
232
234 k_mutex_lock(&param.mutex, K_FOREVER);
235 {
236 k_mutex_lock(&param.rcv_history_mutex, K_FOREVER);
237 {
242 }
243 }
244 k_mutex_unlock(&param.rcv_history_mutex);
245
246 k_mutex_lock(&param.local_history_mutex, K_FOREVER);
247 {
252 }
253 }
254 k_mutex_unlock(&param.local_history_mutex);
255 }
256 k_mutex_unlock(&param.mutex);
257}
258
260 LOG_DBG("method: %s", __func__);
261
262#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
264#endif
265
266 // Save the burst
268
269 double slope_ticks = 0.0;
270 double offset_ticks = 0.0;
271
272 bluesync_status_t err = 0;
273 err = calculate_lr_from_history(&slope_ticks, &offset_ticks, SLOT_NUMBER/2);
274
275 if (err != BLUESYNC_SUCCESS_STATUS){
276 return err;
277 }
278
279 apply_timer_sync(slope_ticks, offset_ticks);
280
281 k_mutex_lock(&param.mutex, K_FOREVER);
282 {
284 }
285 k_mutex_unlock(&param.mutex);
287}
288
289void drift_estimation_handler(struct k_timer *timer_id){
290 k_sem_give(&bluesync_end_sync_sem);
291}
292
294 struct bluesync_msg_client msg;
295 int ret = k_msgq_get(&bluesync_rx_msgq, &msg, K_FOREVER);
296 if (ret != 0) {
297 LOG_ERR("No message available (err: %d)", ret);
298 return;
299 }
300
301 uint8_t current_round_id = msg.rcv.round_id;
302 uint8_t current_timeslot_idx = msg.rcv.index_timeslot;
303
305
306 if (current_state == BS_SCAN_WAIT_FOR_SYNC)
307 {
308 if (current_round_id == param.current_round_id){
309 return; // already synchronized to this round
310 }
311 k_mutex_lock(&param.mutex, K_FOREVER);
312 {
313 param.new_round_id = current_round_id;
314 }
315 k_mutex_unlock(&param.mutex);
316
317 int remaining_slots = BLUESYNC_TIMESTAMP_ARRAY_SIZE + 1 - current_timeslot_idx;
318 k_timer_start(&param.drift_estimation_timer, K_MSEC(remaining_slots * CONFIG_BLUESYNC_ADV_INT_MS), K_NO_WAIT);
319
321
322 }
323
324 if(current_timeslot_idx > SLOT_NUMBER){
325 LOG_ERR("Index too large: %u (max %u)", current_timeslot_idx, SLOT_NUMBER);
326 return;
327 }
328
329 // add timestamp to local set if index is between the range
330 if(current_timeslot_idx >= 0 && current_timeslot_idx < SLOT_NUMBER){
331 k_mutex_lock(&param.local_mutex, K_FOREVER);
332 {
334 , current_timeslot_idx
336#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
337 , msg.master_estimation_ticks
338#endif
339 );
340 }
341 k_mutex_unlock(&param.local_mutex);
342 }
343
344 // add timestamp to master set if index is between the range
345 if(current_timeslot_idx >= 1 && current_timeslot_idx <= SLOT_NUMBER){
346 k_mutex_lock(&param.rcv_mutex, K_FOREVER);
347 {
349 , current_timeslot_idx-1
351#if defined(CONFIG_BLUESYNC_TEST_BABBLESIM_SUPPORT)
352 , 0
353#endif
354 );
355 }
356 k_mutex_unlock(&param.rcv_mutex);
357 }
358}
359
360static uint8_t bt_packet_buf[sizeof(uint16_t) + sizeof(struct bluesync_msg)] = {0};
361
362static bluesync_status_t bluesync_encode_msg(struct bt_data *bt_pkt, uint8_t current_round_id,
363 uint8_t current_timeslot_idx,
364 int64_t time_ticks){
365
366 memset(bt_packet_buf, 0, sizeof(bt_packet_buf));
367
368 struct bluesync_msg msg = {
369 .round_id = current_round_id,
370 .index_timeslot = current_timeslot_idx,
371 .master_timer_ticks = time_ticks
372 };
373
374 uint16_t manufacturer_id = MY_MANUFACTURER_ID;
375
376 // Copy Manufacturer ID (Little Endian format)
377 bt_packet_buf[0] = manufacturer_id & 0xFF;
378 bt_packet_buf[1] = (manufacturer_id >> 8) & 0xFF;
379
380 // Copy the struct data into the buffer
381 memcpy(&bt_packet_buf[2], &msg, sizeof(struct bluesync_msg));
382
383 bt_pkt[0].type = BT_DATA_FLAGS;
384 bt_pkt[0].data_len = 1;
385 bt_pkt[0].data = (uint8_t []) { BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR };
386
387 bt_pkt[1].type = BT_DATA_MANUFACTURER_DATA;
388 bt_pkt[1].data_len = sizeof(bt_packet_buf);
389 bt_pkt[1].data = bt_packet_buf;
390
392}
393
394static void bluesync_send_adv(){
395 struct bt_data bt_packet[2];
396
397 if (param.timeslot_index == 0){
399 }
400 else {
403 }
404
405 int err = bt_le_ext_adv_set_data(param.adv, bt_packet, ARRAY_SIZE(bt_packet), NULL, 0);
406 if (err) {
407 LOG_ERR("Failed to set advertising data (err %d)", err);
408 return;
409 }
410
411 struct bt_le_ext_adv_start_param start = {
412 .num_events = 1,
413 };
414
415#if defined(CONFIG_BLUESYNC_USED_IN_MESH)
416 bt_mesh_scan_disable();
417#endif
418
419 err = bt_le_ext_adv_start(param.adv, &start);
420 if (err) {
421 LOG_ERR("Failed to start extended advertising (err %d)", err);
422 return;
423 }
424}
425
426// SCANNING PART ********************************************
427
428void scan_cb(const bt_addr_le_t *addr, int8_t rssi, struct net_buf_simple *buf){
429
430 // Check if there is enough data in the buffer
431 if (buf->len < 2) {
432 LOG_ERR("Error: Not enough data for extended advertising");
433 return;
434 }
435 // Parse length and type fields
436 // Parse AD_ELEMENT_FLAG
437 uint8_t len_ad_flag = net_buf_simple_pull_u8(buf);
438 if (len_ad_flag > 0){
439 net_buf_simple_pull_mem(buf, len_ad_flag);
440 }
441 // Parse AD_ELEMENT_MANUFACTURER_SPECIFIC
442 uint8_t len = net_buf_simple_pull_u8(buf);
443 if (len > buf->len) {
444 LOG_ERR("Error: Buffer length mismatch");
445 return;
446 }
447 uint8_t type = net_buf_simple_pull_u8(buf);
448 if (type == BT_DATA_MANUFACTURER_DATA){
449 // get manufacturer id
450 net_buf_simple_pull_be16(buf);
451 // Verify that the payload length matches the expected size
452 if (len - 3 != sizeof(struct bluesync_msg)) {
453 LOG_ERR("Error: Unexpected manufacturer data size");
454 return;
455 }
456
457 struct bluesync_msg_client msg;
458
459 bluesync_decode_msg(&msg, buf);
460
461 int ret = k_msgq_put(&bluesync_rx_msgq, &msg, K_NO_WAIT);
462
463 if (ret != 0 ) {
464 LOG_ERR("Failed to put message in msgq");
465 }
466
467 } else {
468 LOG_ERR("Error: Unsupported advertising data type (0x%02X)", type);
469 }
470}
471
472#if !defined(CONFIG_BLUESYNC_USED_IN_MESH)
473static void bt_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
474 uint8_t adv_type, struct net_buf_simple *buf){
475 if (adv_type == BT_GAP_ADV_TYPE_EXT_ADV){
476 scan_cb(addr, rssi, buf);
477 }
478}
479#endif
480
482#if defined(CONFIG_BLUESYNC_USED_IN_MESH)
483 bt_mesh_register_aux_scan_cb(BT_GAP_ADV_TYPE_EXT_ADV, &scan_cb);
484#else
485 int err = bt_le_scan_start(&param.scan_param, &bt_scan_cb);
486 if (err) {
487 LOG_ERR("Failed to start scanning (err %d)", err);
488 } else {
489 LOG_DBG("Scanning started.");
490 }
491#endif
492}
493
494static void bluesync_scan_stop(){
495#if defined(CONFIG_BLUESYNC_USED_IN_MESH)
496 bt_mesh_unregister_aux_scan_cb();
497#else
498 int err = bt_le_scan_stop();
499 if (err == -EALREADY) {
500 LOG_ERR("Scanning was not active.");
501 } else if (err) {
502 LOG_ERR("Failed to stop scanning (err %d)", err);
503 } else {
504 LOG_DBG("Scanning stopped.");
505 }
506#endif
507}
508
509// ADVERTISING PART ******************************************
510
511static void bluesync_adv_process() {
512 for (int i = 0; i <= SLOT_NUMBER; i++){
514 k_sleep(K_MSEC(CONFIG_BLUESYNC_ADV_INT_MS));
515 }
516}
517
518void adv_sent_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_sent_info *info)
519{
520 k_mutex_lock(&param.mutex, K_FOREVER);
521 {
522 if (info->num_sent >= 1) {
525 }
527 }
528 }
529 k_mutex_unlock(&param.mutex);
530#if defined(CONFIG_BLUESYNC_USED_IN_MESH)
531 bt_mesh_scan_enable();
532#endif
533
534}
535
536static struct bt_le_ext_adv_cb bt_callbacks = {
537 .sent = adv_sent_cb,
538};
539
540static void bluesync_init_adv(){
541 int err = bt_le_ext_adv_create(&param.adv_param, &bt_callbacks, &param.adv);
542 if (err) {
543 LOG_ERR("Failed to create extended advertising set (err %d)", err);
544 return;
545 }
546}
547
548// BLUESYNC_STATE_MACHINE CALLBACKS *********************************************
549
551 LOG_DBG("method: %s",__func__);
553
555}
556
558 LOG_DBG("method: %s",__func__);
559}
560
562 LOG_DBG("method: %s",__func__);
565
566 if(status != BLUESYNC_SUCCESS_STATUS){
568 return;
569 }
570
572}
573
574void bs_adv_handler(void){
575 LOG_DBG("method: %s",__func__);
576
580}
581
583 LOG_DBG("method: %s",__func__);
584}
585
588 .bs_sync_cb = bs_sync_handler,
589 .bs_update_cb = bs_update_handler,
590 .bs_adv_cb = bs_adv_handler,
591 .bs_stop_cb = bs_stop_handler,
592};
593
594
595// BLUESYNC THREAD *********************************
596
597void bluesync_thread_fnt(void *arg1, void *arg2, void *arg3)
598{
599 // Define the event array
600 struct k_poll_event events[] = {
601 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
602 K_POLL_MODE_NOTIFY_ONLY,
603 &bluesync_start_new_sync_sem),
604 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_MSGQ_DATA_AVAILABLE,
605 K_POLL_MODE_NOTIFY_ONLY,
606 &bluesync_rx_msgq),
607 K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SEM_AVAILABLE,
608 K_POLL_MODE_NOTIFY_ONLY,
609 &bluesync_end_sync_sem),
610 };
611
615
616 k_sem_take(&bluesync_role_assign_sem, K_FOREVER);
618
619 while (1)
620 {
621 k_poll(events, ARRAY_SIZE(events), K_FOREVER);
622
623 if(events[0].state == K_POLL_STATE_SEM_AVAILABLE){
624 k_sem_take(&bluesync_start_new_sync_sem, K_NO_WAIT);
626 }
627
628 if(events[1].state == K_POLL_STATE_MSGQ_DATA_AVAILABLE){
630 }
631
632 if(events[2].state == K_POLL_STATE_SEM_AVAILABLE){
633 k_sem_take(&bluesync_end_sync_sem, K_NO_WAIT);
635 }
636
637 // clear events
638 events[0].state = K_POLL_STATE_NOT_READY;
639 events[1].state = K_POLL_STATE_NOT_READY;
640 events[2].state = K_POLL_STATE_NOT_READY;
641 }
642}
643
644// PUBLIC ******************************************
645
647 LOG_DBG("bluesync init");
648
649 k_tid_t thread_id = k_thread_create(&param.bluesync_thread, bluesync_thread_stack,
650 K_THREAD_STACK_SIZEOF(bluesync_thread_stack),
651 bluesync_thread_fnt, &param, NULL, NULL,
652 CONFIG_BLUESYNC_THREAD_PRIORITY, 0, K_NO_WAIT);
653 k_thread_name_set(thread_id, "bluesync_thread");
654}
655
657 if (role != BLUESYNC_NONE_ROLE) {
659 k_sem_give(&bluesync_role_assign_sem);
660 }
661 else {
662 LOG_ERR("Wrong type given");
663 }
664}
665
666
669 k_mutex_lock(&param.mutex, K_FOREVER);
670 {
672 }
673 k_mutex_unlock(&param.mutex);
674 k_sem_give(&bluesync_start_new_sync_sem);
675 }
676}
677
680 //set the new reference unix_epoch
681 set_new_epoch_unix_ref(unix_epoch_us);
682
683 //start a new sync in the network
685 }
686}
void bs_scan_wait_for_sync_handler(void)
Definition bluesync.c:550
static void bluesync_send_adv()
Definition bluesync.c:394
void drift_estimation_handler(struct k_timer *timer_id)
Definition bluesync.c:289
static bluesync_status_t bluesync_encode_msg(struct bt_data *bt_pkt, uint8_t current_round_id, uint8_t current_timeslot_idx, int64_t time_ticks)
Definition bluesync.c:362
void bluesync_thread_fnt(void *arg1, void *arg2, void *arg3)
Definition bluesync.c:597
static void bluesync_store_current_burst()
Definition bluesync.c:233
LOG_MODULE_REGISTER(bluesync, CONFIG_BLUESYNC_LOG_LEVEL)
static void bluesync_scan_start()
Definition bluesync.c:481
void bs_stop_handler(void)
Definition bluesync.c:582
void adv_sent_cb(struct bt_le_ext_adv *adv, struct bt_le_ext_adv_sent_info *info)
Definition bluesync.c:518
void scan_cb(const bt_addr_le_t *addr, int8_t rssi, struct net_buf_simple *buf)
Definition bluesync.c:428
void bs_update_handler(void)
Definition bluesync.c:561
K_MSGQ_DEFINE(bluesync_rx_msgq, sizeof(struct bluesync_msg_client), 17, 1)
K_THREAD_STACK_DEFINE(bluesync_thread_stack, CONFIG_BLUESYNC_THREAD_STACK_SIZE)
struct bs_sm_handlers handlers
Definition bluesync.c:586
#define BLUESYNC_BT_MAX_ADV_INT
Definition bluesync.c:54
static bluesync_status_t calculate_lr_from_history(double *slope, double *offset, size_t min_nb_timestamp)
Definition bluesync.c:154
static uint8_t bt_packet_buf[sizeof(uint16_t)+sizeof(struct bluesync_msg)]
Definition bluesync.c:360
static void bluesync_scan_stop()
Definition bluesync.c:494
static void bluesync_adv_process()
Definition bluesync.c:511
static void bluesync_scan_packet_process()
Definition bluesync.c:293
void bs_adv_handler(void)
Definition bluesync.c:574
void bs_sync_handler()
Definition bluesync.c:557
K_SEM_DEFINE(bluesync_end_sync_sem, 0, 1)
static void reset_bluesync_timestamps(bluesync_timestamps_t *elem)
Definition bluesync.c:119
#define BLUESYNC_BT_MIN_ADV_INT
Definition bluesync.c:53
static void bluesync_decode_msg(struct bluesync_msg_client *msg, struct net_buf_simple *buf)
Definition bluesync.c:223
static void bluesync_reset_param()
Definition bluesync.c:139
static void bt_scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t adv_type, struct net_buf_simple *buf)
Definition bluesync.c:473
static void add_bluesync_timestamps(bluesync_timestamps_t *elem, uint8_t pos, int64_t ticks)
Definition bluesync.c:124
#define BLUESYNC_BT_SCAN_INT
Definition bluesync.c:55
static void bluesync_init_adv()
Definition bluesync.c:540
#define BLUESYNC_BT_SCAN_WIND_SIZE
Definition bluesync.c:56
static bluesync_status_t end_sync_timeslot_process()
Definition bluesync.c:259
static struct bt_le_ext_adv_cb bt_callbacks
Definition bluesync.c:536
static struct bluesync_param param
Definition bluesync.c:60
void bitwise_and_bitfields(uint8_t *result, const bluesync_timestamps_t *rcv, const bluesync_timestamps_t *local, size_t num_bytes)
Perform a bitwise AND between two bitfields and store the result.
void set_bit(uint8_t *bitfield, size_t bit_index)
Set a specific bit in the bitfield.
bool is_bit_set(uint8_t *bitfield, size_t bit_index)
Check if a specific bit is set in the bitfield.
void statistic_bluesync_status(bluesync_timestamps_t *elem_master, bluesync_timestamps_t *elem_slave, size_t size)
Analyze and log synchronization statistics based on a series of timestamps.
bs_sm_state_t bs_state_machine_get_state()
Get the current state.
void bs_state_machine_init(struct bs_sm_handlers *handlers)
Init the state machine by passing the list of callbacks.
void bs_state_machine_set_role(bluesync_role_t role)
Indicate the role to the state machine.
bluesync_role_t bs_state_machine_get_role()
Get the node role.
void bs_state_machine_run(bs_sm_event_t event)
Annonce an event to the state machine.
bs_sm_state_t
Type definition representing the states.
@ BS_SCAN_WAIT_FOR_SYNC
@ EVENT_ADV_EXPIRED
@ EVENT_SYNC_EXPIRED
@ EVENT_UPDATE_FAILED
@ EVENT_NEW_SYNC_RCV
@ EVENT_NEW_NET_SYNC
@ EVENT_INIT
@ EVENT_UPDATE_SUCCESS
void bluesync_set_role(bluesync_role_t role)
Sets the operational role of the BlueSync node.
Definition bluesync.c:656
void bluesync_start_net_sync_with_unix_epoch_us(uint64_t unix_epoch_us)
Starts a synchronization round using a known UNIX epoch time.
Definition bluesync.c:678
void bluesync_start_net_sync()
Starts a BlueSync synchronization round as the time authority.
Definition bluesync.c:667
bluesync_role_t
Defines the operational roles for a BlueSync node.
Definition bluesync.h:44
void bluesync_init()
Initializes the BlueSync time synchronization module.
Definition bluesync.c:646
@ BLUESYNC_NONE_ROLE
Definition bluesync.h:45
@ BLUESYNC_AUTHORITY_ROLE
Definition bluesync.h:46
Public API for the BlueSync time synchronization module.
void set_new_epoch_unix_ref(uint64_t epoch_ref_us)
Set the new epoch unix ref value. Before the authority node starts a new network synchronisation,...
Definition local_time.c:112
void apply_timer_sync(double new_slope, double new_offset)
Apply the synchronisation parameters. Once the LR is made, The result of it gives a drift value (slop...
Definition local_time.c:101
uint64_t get_logical_time_ticks()
Get the logical time ticks value. This is the corrected ticks value after synchronisation....
Definition local_time.c:97
static struct local_time local
Definition local_time.c:53
bluesync_status_t
Definition bluesync.h:38
@ BLUESYNC_NO_ENOUGH_DATA_STATUS
Definition bluesync.h:41
@ BLUESYNC_NO_VALID_DATA_STATUS
Definition bluesync.h:40
@ BLUESYNC_SUCCESS_STATUS
Definition bluesync.h:39
@ BLUESYNC_DENOMINATOR_TOO_SMALL
Definition bluesync.h:42
#define BURST_WINDOWS_SIZE
Definition bluesync.h:34
#define MY_MANUFACTURER_ID
Definition bluesync.h:36
#define BLUESYNC_TIMESTAMP_ARRAY_SIZE
Definition bluesync.h:32
#define NB_BYTES_BITFIELD
Definition bluesync.h:31
#define SLOT_NUMBER
Definition bluesync.h:30
Encapsulated BlueSync message received by the client during synchronization.
Definition bluesync.h:124
uint64_t client_timer_ticks
Definition bluesync.h:126
struct bluesync_msg rcv
Definition bluesync.h:125
Message structure used in BlueSync time synchronization exchanges.
Definition bluesync.h:110
uint8_t round_id
Definition bluesync.h:111
uint8_t index_timeslot
Definition bluesync.h:112
uint64_t master_timer_ticks
Definition bluesync.h:113
uint8_t rcv_head
Definition bluesync.h:69
uint8_t current_round_id
Definition bluesync.h:96
struct k_mutex local_history_mutex
Definition bluesync.h:82
bluesync_timestamps_t local
Definition bluesync.h:75
struct k_thread bluesync_thread
Definition bluesync.h:100
struct k_mutex mutex
Definition bluesync.h:99
uint8_t rcv_count
Definition bluesync.h:70
struct bt_le_scan_param scan_param
Definition bluesync.h:87
uint8_t local_head
Definition bluesync.h:80
struct k_timer drift_estimation_timer
Definition bluesync.h:91
struct k_mutex rcv_history_mutex
Definition bluesync.h:71
bluesync_timestamps_t local_history[BURST_WINDOWS_SIZE]
Definition bluesync.h:79
uint8_t local_count
Definition bluesync.h:81
struct bt_le_ext_adv * adv
Definition bluesync.h:85
uint8_t new_round_id
Definition bluesync.h:97
struct k_mutex rcv_mutex
Definition bluesync.h:65
bluesync_timestamps_t rcv
Definition bluesync.h:64
struct k_mutex local_mutex
Definition bluesync.h:76
uint8_t timeslot_index
Definition bluesync.h:60
bluesync_timestamps_t rcv_history[BURST_WINDOWS_SIZE]
Definition bluesync.h:68
struct bt_le_adv_param adv_param
Definition bluesync.h:86
uint64_t timer_ticks[SLOT_NUMBER]
Definition bluesync.h:52
uint8_t bitfield[NB_BYTES_BITFIELD]
Definition bluesync.h:51
Struct defining the callbacks of the state machine.
void(* bs_scan_wait_for_sync_cb)(void)
This callback is called when entering in wait_for_sync state.