blob: 33ca9781ad50fb89175e5d0ebe64bb9fd1098fcc [file]
/*
* Copyright (c) 2023 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/bluetooth/mesh.h>
#include "net.h"
#include "statistic.h"
static struct bt_mesh_statistic stat;
void bt_mesh_stat_get(struct bt_mesh_statistic *st)
{
memcpy(st, &stat, sizeof(struct bt_mesh_statistic));
}
void bt_mesh_stat_reset(void)
{
memset(&stat, 0, sizeof(struct bt_mesh_statistic));
}
void bt_mesh_stat_planned_count(struct bt_mesh_adv_ctx *ctx)
{
if (ctx->tag == BT_MESH_ADV_TAG_LOCAL) {
stat.tx_local_planned++;
} else if (ctx->tag == BT_MESH_ADV_TAG_RELAY) {
stat.tx_adv_relay_planned++;
} else if (ctx->tag == BT_MESH_ADV_TAG_FRIEND) {
stat.tx_friend_planned++;
}
}
void bt_mesh_stat_succeeded_count(struct bt_mesh_adv_ctx *ctx)
{
if (ctx->tag == BT_MESH_ADV_TAG_LOCAL) {
stat.tx_local_succeeded++;
} else if (ctx->tag == BT_MESH_ADV_TAG_RELAY) {
stat.tx_adv_relay_succeeded++;
} else if (ctx->tag == BT_MESH_ADV_TAG_FRIEND) {
stat.tx_friend_succeeded++;
}
}
void bt_mesh_stat_rx(enum bt_mesh_net_if net_if)
{
switch (net_if) {
case BT_MESH_NET_IF_ADV:
stat.rx_adv++;
break;
case BT_MESH_NET_IF_LOCAL:
stat.rx_loopback++;
break;
case BT_MESH_NET_IF_PROXY:
case BT_MESH_NET_IF_PROXY_CFG:
stat.rx_proxy++;
break;
default:
stat.rx_uknown++;
break;
}
}
#if defined(CONFIG_BT_MESH_LOW_POWER)
static struct bt_mesh_lpn_timing lpn_timing;
static int64_t poll_tx_end_ts;
static int64_t scan_start_ts;
void bt_mesh_stat_lpn_timing_update_poll_tx(void)
{
poll_tx_end_ts = k_uptime_ticks();
}
void bt_mesh_stat_lpn_timing_update_scan_start(void)
{
int64_t now = k_uptime_ticks();
uint32_t delay;
scan_start_ts = now;
if (poll_tx_end_ts == 0) {
return;
}
delay = k_ticks_to_us_floor32(now - poll_tx_end_ts);
lpn_timing.recv_delay_us = delay;
if (lpn_timing.cnt == 0 && lpn_timing.recv_delay_min_us == 0) {
lpn_timing.recv_delay_min_us = delay;
lpn_timing.recv_delay_max_us = delay;
} else {
if (delay < lpn_timing.recv_delay_min_us) {
lpn_timing.recv_delay_min_us = delay;
}
if (delay > lpn_timing.recv_delay_max_us) {
lpn_timing.recv_delay_max_us = delay;
}
}
}
void bt_mesh_stat_lpn_timing_update_response_rx(void)
{
int64_t now = k_uptime_ticks();
uint32_t win;
if (scan_start_ts == 0) {
return;
}
win = k_ticks_to_us_floor32(now - scan_start_ts);
lpn_timing.recv_win_us = win;
if (lpn_timing.cnt == 0) {
lpn_timing.recv_win_min_us = win;
lpn_timing.recv_win_max_us = win;
} else {
if (win < lpn_timing.recv_win_min_us) {
lpn_timing.recv_win_min_us = win;
}
if (win > lpn_timing.recv_win_max_us) {
lpn_timing.recv_win_max_us = win;
}
}
lpn_timing.cnt++;
}
void bt_mesh_stat_lpn_timing_update_win_expired(void)
{
int64_t now = k_uptime_ticks();
if (scan_start_ts == 0) {
return;
}
lpn_timing.recv_win_expected_us = k_ticks_to_us_floor32(now - scan_start_ts);
lpn_timing.cnt_failed++;
}
int bt_mesh_stat_lpn_timing_get(struct bt_mesh_lpn_timing *timing)
{
if (timing == NULL) {
return -EINVAL;
}
memcpy(timing, &lpn_timing, sizeof(*timing));
return 0;
}
void bt_mesh_stat_lpn_timing_reset(void)
{
memset(&lpn_timing, 0, sizeof(lpn_timing));
poll_tx_end_ts = 0;
scan_start_ts = 0;
}
#else /* !CONFIG_BT_MESH_LOW_POWER */
int bt_mesh_stat_lpn_timing_get(struct bt_mesh_lpn_timing *timing)
{
ARG_UNUSED(timing);
return -ENOTSUP;
}
void bt_mesh_stat_lpn_timing_reset(void)
{
}
#endif /* CONFIG_BT_MESH_LOW_POWER */