Merge branch 'bugfix/btdm_osi_alarm' into 'master'
component/bt: use esp_timer instead of FreeRTOS timer to implement osi_alarm in bluedroid See merge request !1506
This commit is contained in:
commit
e24ea6207b
3 changed files with 86 additions and 158 deletions
|
@ -40,7 +40,6 @@ typedef struct {
|
|||
command_complete_cb complete_callback;
|
||||
command_status_cb status_callback;
|
||||
void *context;
|
||||
uint32_t sent_time;
|
||||
BT_HDR *command;
|
||||
} waiting_command_t;
|
||||
|
||||
|
@ -90,9 +89,7 @@ static void hci_layer_deinit_env(void);
|
|||
static void hci_host_thread_handler(void *arg);
|
||||
static void event_command_ready(fixed_queue_t *queue);
|
||||
static void event_packet_ready(fixed_queue_t *queue);
|
||||
static void restart_comamnd_waiting_response_timer(
|
||||
command_waiting_response_t *cmd_wait_q,
|
||||
bool tigger_by_sending_command);
|
||||
static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q);
|
||||
static void command_timed_out(void *context);
|
||||
static void hal_says_packet_ready(BT_HDR *packet);
|
||||
static bool filter_incoming_event(BT_HDR *packet);
|
||||
|
@ -330,8 +327,7 @@ static void event_command_ready(fixed_queue_t *queue)
|
|||
// Send it off
|
||||
packet_fragmenter->fragment_and_dispatch(wait_entry->command);
|
||||
|
||||
wait_entry->sent_time = osi_alarm_now();
|
||||
restart_comamnd_waiting_response_timer(cmd_wait_q, true);
|
||||
restart_command_waiting_response_timer(cmd_wait_q);
|
||||
}
|
||||
|
||||
static void event_packet_ready(fixed_queue_t *queue)
|
||||
|
@ -377,41 +373,18 @@ static void fragmenter_transmit_finished(BT_HDR *packet, bool all_fragments_sent
|
|||
}
|
||||
}
|
||||
|
||||
static void restart_comamnd_waiting_response_timer(
|
||||
command_waiting_response_t *cmd_wait_q,
|
||||
bool tigger_by_sending_command)
|
||||
static void restart_command_waiting_response_timer(command_waiting_response_t *cmd_wait_q)
|
||||
{
|
||||
uint32_t timeout;
|
||||
waiting_command_t *wait_entry;
|
||||
if (!cmd_wait_q) {
|
||||
return;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (cmd_wait_q->timer_is_set) {
|
||||
if (tigger_by_sending_command) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Cancel Previous command timeout timer setted when sending command
|
||||
osi_alarm_cancel(cmd_wait_q->command_response_timer);
|
||||
cmd_wait_q->timer_is_set = false;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&cmd_wait_q->commands_pending_response_lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
wait_entry = (list_is_empty(cmd_wait_q->commands_pending_response) ?
|
||||
NULL : list_front(cmd_wait_q->commands_pending_response));
|
||||
osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
|
||||
|
||||
if (wait_entry == NULL) {
|
||||
return;
|
||||
if (!list_is_empty(cmd_wait_q->commands_pending_response)) {
|
||||
osi_alarm_set(cmd_wait_q->command_response_timer, COMMAND_PENDING_TIMEOUT);
|
||||
cmd_wait_q->timer_is_set = true;
|
||||
}
|
||||
|
||||
timeout = osi_alarm_time_diff(osi_alarm_now(), wait_entry->sent_time);
|
||||
timeout = osi_alarm_time_diff(COMMAND_PENDING_TIMEOUT, timeout);
|
||||
timeout = (timeout <= COMMAND_PENDING_TIMEOUT) ? timeout : COMMAND_PENDING_TIMEOUT;
|
||||
|
||||
cmd_wait_q->timer_is_set = true;
|
||||
osi_alarm_set(cmd_wait_q->command_response_timer, timeout);
|
||||
osi_mutex_unlock(&cmd_wait_q->commands_pending_response_lock);
|
||||
}
|
||||
|
||||
static void command_timed_out(void *context)
|
||||
|
@ -493,7 +466,7 @@ static bool filter_incoming_event(BT_HDR *packet)
|
|||
|
||||
return false;
|
||||
intercepted:
|
||||
restart_comamnd_waiting_response_timer(&hci_host_env.cmd_waiting_q, false);
|
||||
restart_command_waiting_response_timer(&hci_host_env.cmd_waiting_q);
|
||||
|
||||
/*Tell HCI Host Task to continue TX Pending commands*/
|
||||
if (hci_host_env.command_credits &&
|
||||
|
|
|
@ -23,22 +23,18 @@
|
|||
#include "alarm.h"
|
||||
#include "allocator.h"
|
||||
#include "list.h"
|
||||
#include "thread.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "esp_timer.h"
|
||||
#include "btc_task.h"
|
||||
#include "btc_alarm.h"
|
||||
#include "mutex.h"
|
||||
#include "time.h"
|
||||
|
||||
#define RTC_TIMER_TICKS_TO_MS(ticks) (((ticks/625)<<1) + (ticks-(ticks/625)*625)/312)
|
||||
|
||||
|
||||
#define BT_ALARM_START_WAIT_TICKS 100
|
||||
#define BT_ALARM_STOP_WAIT_TICKS 100
|
||||
#define BT_ALARM_FREE_WAIT_TICKS 100
|
||||
#define BT_ALARM_CHG_PERIOD_WAIT_TICKS 100
|
||||
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;
|
||||
|
||||
enum {
|
||||
ALARM_STATE_IDLE,
|
||||
|
@ -50,7 +46,7 @@ static int alarm_state;
|
|||
|
||||
static struct alarm_t alarm_cbs[ALARM_CBS_NUM];
|
||||
|
||||
static int alarm_free(osi_alarm_t *alarm);
|
||||
static osi_alarm_err_t alarm_free(osi_alarm_t *alarm);
|
||||
|
||||
int osi_alarm_create_mux(void)
|
||||
{
|
||||
|
@ -123,17 +119,9 @@ static struct alarm_t *alarm_cbs_lookfor_available(void)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void alarm_cb_handler(TimerHandle_t xTimer)
|
||||
static void alarm_cb_handler(struct alarm_t *alarm)
|
||||
{
|
||||
struct alarm_t *alarm;
|
||||
if (!xTimer) {
|
||||
LOG_ERROR("TimerName: NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
alarm = pvTimerGetTimerID(xTimer);
|
||||
LOG_DEBUG("TimerID %p, Name %s\n", alarm, pcTimerGetTimerName(xTimer));
|
||||
|
||||
LOG_DEBUG("TimerID %p\n", alarm);
|
||||
btc_msg_t msg;
|
||||
btc_alarm_args_t arg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
|
@ -143,7 +131,7 @@ static void alarm_cb_handler(TimerHandle_t xTimer)
|
|||
btc_transfer_context(&msg, &arg, sizeof(btc_alarm_args_t), NULL);
|
||||
}
|
||||
|
||||
osi_alarm_t *osi_alarm_new(char *alarm_name, osi_alarm_callback_t callback, void *data, period_ms_t timer_expire)
|
||||
osi_alarm_t *osi_alarm_new(const char *alarm_name, osi_alarm_callback_t callback, void *data, period_ms_t timer_expire)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
|
@ -164,161 +152,133 @@ osi_alarm_t *osi_alarm_new(char *alarm_name, osi_alarm_callback_t callback, void
|
|||
goto end;
|
||||
}
|
||||
|
||||
if (timer_expire == 0) {
|
||||
timer_expire = 1000;
|
||||
}
|
||||
esp_timer_create_args_t tca;
|
||||
tca.callback = (esp_timer_cb_t)alarm_cb_handler;
|
||||
tca.arg = timer_id;
|
||||
tca.dispatch_method = ESP_TIMER_TASK;
|
||||
tca.name = alarm_name;
|
||||
|
||||
TimerHandle_t t = xTimerCreate(alarm_name, timer_expire / portTICK_PERIOD_MS, pdFALSE, timer_id, alarm_cb_handler);
|
||||
if (!t) {
|
||||
LOG_ERROR("%s failed to create timer\n", __func__);
|
||||
timer_id->cb = callback;
|
||||
timer_id->cb_data = data;
|
||||
timer_id->deadline_us = 0;
|
||||
|
||||
esp_err_t stat = esp_timer_create(&tca, &timer_id->alarm_hdl);
|
||||
if (stat != ESP_OK) {
|
||||
LOG_ERROR("%s failed to create timer, err 0x%x\n", __func__, stat);
|
||||
timer_id = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
timer_id->alarm_hdl = t;
|
||||
timer_id->cb = callback;
|
||||
timer_id->cb_data = data;
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return timer_id;
|
||||
}
|
||||
|
||||
static int alarm_free(osi_alarm_t *alarm)
|
||||
static osi_alarm_err_t alarm_free(osi_alarm_t *alarm)
|
||||
{
|
||||
if (!alarm || alarm->alarm_hdl == NULL) {
|
||||
LOG_ERROR("%s null\n", __func__);
|
||||
return -1;
|
||||
return OSI_ALARM_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (xTimerDelete(alarm->alarm_hdl, BT_ALARM_FREE_WAIT_TICKS) != pdPASS) {
|
||||
LOG_ERROR("%s alarm delete error\n", __func__);
|
||||
return -2;
|
||||
esp_err_t stat = esp_timer_delete(alarm->alarm_hdl);
|
||||
if (stat != ESP_OK) {
|
||||
LOG_ERROR("%s failed to delete timer, err 0x%x\n", __func__, stat);
|
||||
return OSI_ALARM_ERR_FAIL;
|
||||
}
|
||||
|
||||
memset(alarm, 0, sizeof(osi_alarm_t));
|
||||
return 0;
|
||||
return OSI_ALARM_ERR_PASS;
|
||||
}
|
||||
|
||||
int osi_alarm_free(osi_alarm_t *alarm)
|
||||
void osi_alarm_free(osi_alarm_t *alarm)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
int ret = 0;
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
LOG_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
ret = -3;
|
||||
goto end;
|
||||
}
|
||||
alarm_free(alarm);
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return ret;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout)
|
||||
osi_alarm_err_t osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
int ret = 0;
|
||||
osi_alarm_err_t ret = OSI_ALARM_ERR_PASS;
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
LOG_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
ret = -3;
|
||||
ret = OSI_ALARM_ERR_INVALID_STATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!alarm || alarm->alarm_hdl == NULL) {
|
||||
LOG_ERROR("%s null\n", __func__);
|
||||
ret = -1;
|
||||
ret = OSI_ALARM_ERR_INVALID_ARG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int64_t timeout_us = 1000 * (int64_t)timeout;
|
||||
esp_err_t stat = esp_timer_start_once(alarm->alarm_hdl, (uint64_t)timeout_us);
|
||||
if (stat != ESP_OK) {
|
||||
LOG_ERROR("%s failed to start timer, err 0x%x\n", __func__, stat);
|
||||
ret = OSI_ALARM_ERR_FAIL;
|
||||
goto end;
|
||||
}
|
||||
alarm->deadline_us = timeout_us + esp_timer_get_time();
|
||||
|
||||
if (xTimerChangePeriod(alarm->alarm_hdl, timeout / portTICK_PERIOD_MS, BT_ALARM_CHG_PERIOD_WAIT_TICKS) != pdPASS) {
|
||||
LOG_ERROR("%s chg period error\n", __func__);
|
||||
ret = -2;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (xTimerStart(alarm->alarm_hdl, BT_ALARM_START_WAIT_TICKS) != pdPASS) {
|
||||
LOG_ERROR("%s start error\n", __func__);
|
||||
ret = -2;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int osi_alarm_cancel(osi_alarm_t *alarm)
|
||||
osi_alarm_err_t osi_alarm_cancel(osi_alarm_t *alarm)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = OSI_ALARM_ERR_PASS;
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
LOG_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
ret = -3;
|
||||
ret = OSI_ALARM_ERR_INVALID_STATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!alarm || alarm->alarm_hdl == NULL) {
|
||||
LOG_ERROR("%s null\n", __func__);
|
||||
ret = -1;
|
||||
ret = OSI_ALARM_ERR_INVALID_ARG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (xTimerStop(alarm->alarm_hdl, BT_ALARM_STOP_WAIT_TICKS) != pdPASS) {
|
||||
LOG_ERROR("%s failed to stop timer\n", __func__);
|
||||
ret = -2;
|
||||
esp_err_t stat = esp_timer_stop(alarm->alarm_hdl);
|
||||
if (stat != ESP_OK) {
|
||||
LOG_DEBUG("%s failed to stop timer, err 0x%x\n", __func__, stat);
|
||||
ret = OSI_ALARM_ERR_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t alarm_current_tick(void)
|
||||
{
|
||||
return xTaskGetTickCount();
|
||||
}
|
||||
|
||||
// todo: this is not accurate
|
||||
// max return value: 0xffffffff / 312 = 13765920 = 0xD20D20
|
||||
period_ms_t osi_alarm_now(void)
|
||||
{
|
||||
return RTC_TIMER_TICKS_TO_MS((alarm_current_tick()));
|
||||
}
|
||||
|
||||
period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm)
|
||||
{
|
||||
/* TODO: use FreeRTOS timer.c implement ??? */
|
||||
return 0xffffffff;
|
||||
}
|
||||
assert(alarm_mutex != NULL);
|
||||
int64_t dt_us = 0;
|
||||
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
dt_us = alarm->deadline_us - esp_timer_get_time();
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
|
||||
// pre-condition: 0 <= t1, t2 <= 0xD20D20
|
||||
// return value: 0<= ret <=0XD20D20
|
||||
period_ms_t osi_alarm_time_diff(period_ms_t t1, period_ms_t t2)
|
||||
{
|
||||
#define MAX_ALARM_TIME_MS (0xD20D20)
|
||||
int32_t diff = (int32_t)(t1) - (int32_t)(t2);
|
||||
if (diff < 0) {
|
||||
diff += MAX_ALARM_TIME_MS;
|
||||
}
|
||||
return (period_ms_t)diff;
|
||||
return (dt_us > 0) ? (period_ms_t)(dt_us / 1000) : 0;
|
||||
}
|
||||
|
||||
uint32_t osi_time_get_os_boottime_ms(void)
|
||||
{
|
||||
return RTC_TIMER_TICKS_TO_MS((alarm_current_tick()));
|
||||
return (uint32_t)(esp_timer_get_time() / 1000);
|
||||
}
|
||||
|
||||
void osi_delay_ms(uint32_t ms)
|
||||
{
|
||||
vTaskDelay(ms / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
|
|
|
@ -20,20 +20,21 @@
|
|||
#define _ALARM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/timers.h>
|
||||
#include "esp_timer.h"
|
||||
|
||||
typedef uint32_t period_ms_t;
|
||||
typedef void (*osi_alarm_callback_t)(void *data);
|
||||
typedef struct alarm_t osi_alarm_t;
|
||||
typedef uint64_t period_ms_t;
|
||||
typedef esp_timer_cb_t osi_alarm_callback_t;
|
||||
|
||||
typedef enum {
|
||||
OSI_ALARM_ERR_PASS = 0,
|
||||
OSI_ALARM_ERR_FAIL = -1,
|
||||
OSI_ALARM_ERR_INVALID_ARG = -2,
|
||||
OSI_ALARM_ERR_INVALID_STATE = -3,
|
||||
} osi_alarm_err_t;
|
||||
|
||||
#define ALARM_CBS_NUM 30
|
||||
#define ALARM_ID_BASE 1000
|
||||
typedef struct alarm_t {
|
||||
/* timer id point to here */
|
||||
TimerHandle_t alarm_hdl;
|
||||
osi_alarm_callback_t cb;
|
||||
void *cb_data;
|
||||
} osi_alarm_t;
|
||||
|
||||
int osi_alarm_create_mux(void);
|
||||
int osi_alarm_delete_mux(void);
|
||||
|
@ -42,27 +43,25 @@ void osi_alarm_deinit(void);
|
|||
|
||||
// Creates a new alarm object. The returned object must be freed by calling
|
||||
// |alarm_free|. Returns NULL on failure.
|
||||
osi_alarm_t *osi_alarm_new(char *alarm_name, osi_alarm_callback_t callback, void *data, period_ms_t timer_expire);
|
||||
osi_alarm_t *osi_alarm_new(const char *alarm_name, osi_alarm_callback_t callback, void *data, period_ms_t timer_expire);
|
||||
|
||||
// Frees an alarm object created by |alarm_new|. |alarm| may be NULL. If the
|
||||
// alarm is pending, it will be cancelled. It is not safe to call |alarm_free|
|
||||
// from inside the callback of |alarm|.
|
||||
int osi_alarm_free(osi_alarm_t *alarm);
|
||||
void osi_alarm_free(osi_alarm_t *alarm);
|
||||
|
||||
// Sets an alarm to fire |cb| after the given |deadline|. Note that |deadline| is the
|
||||
// number of milliseconds relative to the current time. |data| is a context variable
|
||||
// for the callback and may be NULL. |cb| will be called back in the context of an
|
||||
// unspecified thread (i.e. it will not be called back in the same thread as the caller).
|
||||
// |alarm| and |cb| may not be NULL.
|
||||
int osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout);
|
||||
osi_alarm_err_t osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout);
|
||||
|
||||
// This function cancels the |alarm| if it was previously set. When this call
|
||||
// returns, the caller has a guarantee that the callback is not in progress and
|
||||
// will not be called if it hasn't already been called. This function is idempotent.
|
||||
// |alarm| may not be NULL.
|
||||
int osi_alarm_cancel(osi_alarm_t *alarm);
|
||||
|
||||
period_ms_t osi_alarm_now(void);
|
||||
osi_alarm_err_t osi_alarm_cancel(osi_alarm_t *alarm);
|
||||
|
||||
// Figure out how much time until next expiration.
|
||||
// Returns 0 if not armed. |alarm| may not be NULL.
|
||||
|
@ -72,10 +71,6 @@ period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm);
|
|||
// Alarm-related state cleanup
|
||||
//void alarm_cleanup(void);
|
||||
|
||||
// Compute time difference (t1-t2) considering tick counter wrap
|
||||
// t1 and t2 should be no greater than the time of MAX ticks
|
||||
period_ms_t osi_alarm_time_diff(period_ms_t t1, period_ms_t t2);
|
||||
|
||||
uint32_t osi_time_get_os_boottime_ms(void);
|
||||
|
||||
#endif /*_ALARM_H_*/
|
||||
|
|
Loading…
Reference in a new issue