/* * Copyright (c) 2016 Intel Corporation * Copyright (c) 2016 Wind River Systems, Inc. * Additional Copyright (c) 2018 Espressif Systems (Shanghai) PTE LTD * * SPDX-License-Identifier: Apache-2.0 */ #include #include "sdkconfig.h" #include "osi/hash_map.h" #include "osi/alarm.h" #include "osi/hash_functions.h" #include "common/bt_trace.h" #include "common/bt_defs.h" #include "esp_timer.h" #include "mesh_kernel.h" #include "mesh_trace.h" #include "provisioner_prov.h" static osi_mutex_t bm_alarm_lock; static osi_mutex_t bm_irq_lock; static hash_map_t *bm_alarm_hash_map; static const size_t BLE_MESH_GENERAL_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; static void bt_mesh_alarm_cb(void *data) { assert(data != NULL); struct k_delayed_work *work = (struct k_delayed_work *)data; work->work.handler(&work->work); return; } unsigned int bt_mesh_irq_lock(void) { #if defined(CONFIG_BLE_MESH_IRQ_LOCK) && CONFIG_BLE_MESH_IRQ_LOCK unsigned int key = XTOS_SET_INTLEVEL(XCHAL_EXCM_LEVEL); return key; #else /* Change by Espressif. In BLE Mesh, in order to improve the real-time * requirements of bt controller, we use task lock to replace IRQ lock. */ osi_mutex_lock(&bm_irq_lock, OSI_MUTEX_MAX_TIMEOUT); return 0; #endif } void bt_mesh_irq_unlock(unsigned int key) { #if defined(CONFIG_BLE_MESH_IRQ_LOCK) && CONFIG_BLE_MESH_IRQ_LOCK XTOS_RESTORE_INTLEVEL(key); #else osi_mutex_unlock(&bm_irq_lock); #endif } s64_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); } u32_t k_uptime_get_32(void) { /** k_uptime_get_32 is in in milliseconds, * but esp_timer_get_time is in microseconds */ return (u32_t)(esp_timer_get_time() / 1000); } void k_sleep(s32_t duration) { vTaskDelay(duration / portTICK_PERIOD_MS); return; } void bt_mesh_k_init(void) { osi_mutex_new(&bm_alarm_lock); osi_mutex_new(&bm_irq_lock); bm_alarm_hash_map = hash_map_new(BLE_MESH_GENERAL_ALARM_HASH_MAP_SIZE, hash_function_pointer, NULL, (data_free_fn)osi_alarm_free, NULL); assert(bm_alarm_hash_map != NULL); } void k_delayed_work_init(struct k_delayed_work *work, k_work_handler_t handler) { osi_alarm_t *alarm = NULL; assert(work != NULL && bm_alarm_hash_map != NULL); k_work_init(&work->work, handler); osi_mutex_lock(&bm_alarm_lock, OSI_MUTEX_MAX_TIMEOUT); if (!hash_map_has_key(bm_alarm_hash_map, (void *)work)) { alarm = osi_alarm_new("bt_mesh", bt_mesh_alarm_cb, (void *)work, 0); if (alarm == NULL) { BT_ERR("%s, Unable to create alarm", __func__); return; } if (!hash_map_set(bm_alarm_hash_map, work, (void *)alarm)) { BT_ERR("%s Unable to add the timer to hash map.", __func__); } } osi_mutex_unlock(&bm_alarm_lock); alarm = hash_map_get(bm_alarm_hash_map, work); if (alarm == NULL) { BT_WARN("%s, Unable to find expected alarm in hash map", __func__); return; } // Just init the work timer only, don't start it. osi_alarm_cancel(alarm); return; } int k_delayed_work_submit(struct k_delayed_work *work, s32_t delay) { assert(work != NULL && bm_alarm_hash_map != NULL); osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("%s, Unable to find expected alarm in hash map", __func__); return -EINVAL; } // Cancel the alarm first, before start the alarm. osi_alarm_cancel(alarm); osi_alarm_set(alarm, delay); return 0; } int k_delayed_work_cancel(struct k_delayed_work *work) { assert(work != NULL && bm_alarm_hash_map != NULL); osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("%s, Unable to find expected alarm in hash map", __func__); return -EINVAL; } osi_alarm_cancel(alarm); alarm->deadline_us = 0; return 0; } int k_delayed_work_free(struct k_delayed_work *work) { assert(work != NULL && bm_alarm_hash_map != NULL); osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, work); if (alarm == NULL) { BT_WARN("%s Unable to find expected alarm in hash map", __func__); return -EINVAL; } hash_map_erase(bm_alarm_hash_map, work); return 0; } s32_t k_delayed_work_remaining_get(struct k_delayed_work *work) { assert(work != NULL && bm_alarm_hash_map != NULL); osi_alarm_t *alarm = hash_map_get(bm_alarm_hash_map, (void *)work); if (alarm == NULL) { BT_WARN("%s Unable to find expected alarm in hash map", __func__); return 0; } if (!alarm->deadline_us) { return 0; } s32_t remain_time = 0; int64_t now = esp_timer_get_time(); if ((alarm->deadline_us - now) < 0x1FFFFFFFFFF) { remain_time = (alarm->deadline_us - now) / 1000; } else { return 0; } return remain_time; }