esp-idf/components/bt/esp_ble_mesh/common/timer.c

248 lines
5.7 KiB
C

/*
* SPDX-FileCopyrightText: 2016 Intel Corporation
* SPDX-FileCopyrightText: 2016 Wind River Systems, Inc.
* SPDX-FileContributor: 2018-2021 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include "osi/hash_map.h"
#include "osi/alarm.h"
#include "osi/hash_functions.h"
#include "mesh/config.h"
#include "mesh/common.h"
static hash_map_t *bm_alarm_hash_map;
static const size_t BLE_MESH_ALARM_HASH_MAP_SIZE = 20 + CONFIG_BLE_MESH_PBA_SAME_TIME +
CONFIG_BLE_MESH_PBG_SAME_TIME;
typedef struct alarm_t {
/* timer id point to here */
esp_timer_handle_t alarm_hdl;
osi_alarm_callback_t cb;
void *cb_data;
int64_t deadline_us;
} osi_alarm_t;
int64_t k_uptime_get(void)
{
/* k_uptime_get_32 is in in milliseconds,
* but esp_timer_get_time is in microseconds
*/
return (esp_timer_get_time() / 1000);
}
uint32_t k_uptime_get_32(void)
{
/* k_uptime_get_32 is in in milliseconds,
* but esp_timer_get_time is in microseconds
*/
return (uint32_t)(esp_timer_get_time() / 1000);
}
void bt_mesh_timer_init(void)
{
bm_alarm_hash_map = hash_map_new(BLE_MESH_ALARM_HASH_MAP_SIZE,
hash_function_pointer, NULL,
(data_free_fn)osi_alarm_free, NULL);
__ASSERT(bm_alarm_hash_map, "Failed to create hash map");
}
#if CONFIG_BLE_MESH_DEINIT
void bt_mesh_timer_deinit(void)
{
if (bm_alarm_hash_map) {
hash_map_free(bm_alarm_hash_map);
bm_alarm_hash_map = NULL;
}
}
#endif /* CONFIG_BLE_MESH_DEINIT */
int k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler)
{
osi_alarm_t *alarm = NULL;
if (!work || !bm_alarm_hash_map) {
BT_ERR("%s, Invalid parameter", __func__);
return -EINVAL;
}
k_work_init(&work->work, handler);
bt_mesh_alarm_lock();
alarm = hash_map_get(bm_alarm_hash_map, work);
if (alarm) {
BT_ERR("Init, alarm already exists");
bt_mesh_alarm_unlock();
return -EEXIST;
}
alarm = osi_alarm_new("bt_mesh", (osi_alarm_callback_t)handler, (void *)&work->work, 0);
if (alarm == NULL) {
BT_ERR("Init, alarm not created");
bt_mesh_alarm_unlock();
return -EIO;
}
if (!hash_map_set(bm_alarm_hash_map, work, (void *)alarm)) {
BT_ERR("Init, alarm not set");
bt_mesh_alarm_unlock();
return -EIO;
}
// Just init the work timer only, don't start it.
osi_alarm_cancel(alarm);
bt_mesh_alarm_unlock();
return 0;
}
int k_delayed_work_submit(struct k_delayed_work *work, int32_t delay)
{
osi_alarm_t *alarm = NULL;
if (!work || !bm_alarm_hash_map) {
BT_ERR("%s, Invalid parameter", __func__);
return -EINVAL;
}
/* If delay is 0, call the corresponding timeout handler. */
if (delay == 0) {
k_work_submit(&work->work);
return 0;
}
bt_mesh_alarm_lock();
alarm = hash_map_get(bm_alarm_hash_map, (void *)work);
if (alarm == NULL) {
BT_WARN("Submit, alarm not found");
bt_mesh_alarm_unlock();
return -EINVAL;
}
// Cancel the alarm first, before start the alarm.
osi_alarm_cancel(alarm);
osi_alarm_set(alarm, delay);
bt_mesh_alarm_unlock();
return 0;
}
int k_delayed_work_submit_periodic(struct k_delayed_work *work, int32_t period)
{
osi_alarm_t *alarm = NULL;
if (!work || !bm_alarm_hash_map) {
BT_ERR("%s, Invalid parameter", __func__);
return -EINVAL;
}
/* If period is 0, call the corresponding timeout handler. */
if (period == 0) {
k_work_submit(&work->work);
return 0;
}
bt_mesh_alarm_lock();
alarm = hash_map_get(bm_alarm_hash_map, (void *)work);
if (alarm == NULL) {
BT_WARN("Submit, alarm not found");
bt_mesh_alarm_unlock();
return -EINVAL;
}
/* Cancel the alarm first before starting it. */
osi_alarm_cancel(alarm);
osi_alarm_set_periodic(alarm, period);
bt_mesh_alarm_unlock();
return 0;
}
int k_delayed_work_cancel(struct k_delayed_work *work)
{
osi_alarm_t *alarm = NULL;
if (!work || !bm_alarm_hash_map) {
BT_ERR("%s, Invalid parameter", __func__);
return -EINVAL;
}
bt_mesh_alarm_lock();
alarm = hash_map_get(bm_alarm_hash_map, (void *)work);
if (alarm == NULL) {
BT_WARN("Cancel, alarm not found");
bt_mesh_alarm_unlock();
return -EINVAL;
}
osi_alarm_cancel(alarm);
alarm->deadline_us = 0;
bt_mesh_alarm_unlock();
return 0;
}
int k_delayed_work_free(struct k_delayed_work *work)
{
osi_alarm_t *alarm = NULL;
if (!work || !bm_alarm_hash_map) {
BT_ERR("%s, Invalid parameter", __func__);
return -EINVAL;
}
bt_mesh_alarm_lock();
alarm = hash_map_get(bm_alarm_hash_map, work);
if (alarm == NULL) {
BT_WARN("Free, alarm not found");
bt_mesh_alarm_unlock();
return -EINVAL;
}
osi_alarm_cancel(alarm);
hash_map_erase(bm_alarm_hash_map, work);
bt_mesh_alarm_unlock();
return 0;
}
int32_t k_delayed_work_remaining_get(struct k_delayed_work *work)
{
osi_alarm_t *alarm = NULL;
int32_t time = 0;
if (!work || !bm_alarm_hash_map) {
BT_ERR("%s, Invalid parameter", __func__);
return 0;
}
bt_mesh_alarm_lock();
alarm = hash_map_get(bm_alarm_hash_map, (void *)work);
if (alarm == NULL) {
BT_WARN("Get time, alarm not found");
bt_mesh_alarm_unlock();
return 0;
}
time = osi_alarm_get_remaining_ms(alarm);
bt_mesh_alarm_unlock();
return time;
}