Fork ESP-IDF's bluetooth component
i want better sbc encoding, and no cla will stop me
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include "esp_blufi_api.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "osi/future.h"
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks)
|
||||
{
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
if (callbacks == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
btc_blufi_set_callbacks(callbacks);
|
||||
return (btc_profile_cb_set(BTC_PID_BLUFI, callbacks->event_cb) == 0 ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_t opmode, esp_blufi_sta_conn_state_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *extra_info)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = BTC_BLUFI_ACT_SEND_CFG_REPORT;
|
||||
arg.wifi_conn_report.opmode = opmode;
|
||||
arg.wifi_conn_report.sta_conn_state = sta_conn_state;
|
||||
arg.wifi_conn_report.softap_conn_num = softap_conn_num;
|
||||
arg.wifi_conn_report.extra_info = extra_info;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_blufi_args_t), btc_blufi_call_deep_copy,
|
||||
btc_blufi_call_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_send_wifi_list(uint16_t apCount, esp_blufi_ap_record_t *list)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = BTC_BLUFI_ACT_SEND_WIFI_LIST;
|
||||
arg.wifi_list.apCount = apCount;
|
||||
arg.wifi_list.list = list;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_blufi_args_t), btc_blufi_call_deep_copy,
|
||||
btc_blufi_call_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_profile_init(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = BTC_BLUFI_ACT_INIT;
|
||||
|
||||
return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_profile_deinit(void)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = BTC_BLUFI_ACT_DEINIT;
|
||||
|
||||
return (btc_transfer_context(&msg, NULL, 0, NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
uint16_t esp_blufi_get_version(void)
|
||||
{
|
||||
return btc_blufi_get_version();
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_send_error_info(esp_blufi_error_state_t state)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = BTC_BLUFI_ACT_SEND_ERR_INFO;
|
||||
arg.blufi_err_infor.state = state;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_blufi_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_send_custom_data(uint8_t *data, uint32_t data_len)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
btc_blufi_args_t arg;
|
||||
if(data == NULL || data_len == 0) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = BTC_BLUFI_ACT_SEND_CUSTOM_DATA;
|
||||
arg.custom_data.data = data;
|
||||
arg.custom_data.data_len = data_len;
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_blufi_args_t), btc_blufi_call_deep_copy,
|
||||
btc_blufi_call_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
@@ -0,0 +1,436 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_BLUFI_API_H__
|
||||
#define __ESP_BLUFI_API_H__
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ESP_BLUFI_EVENT_INIT_FINISH = 0, /*<! When BLUFI init complete, this event happen */
|
||||
ESP_BLUFI_EVENT_DEINIT_FINISH, /*<! When BLUFI deinit complete, this event happen */
|
||||
ESP_BLUFI_EVENT_SET_WIFI_OPMODE, /*<! When Phone set ESP32 wifi operation mode(AP/STA/AP_STA), this event happen */
|
||||
ESP_BLUFI_EVENT_BLE_CONNECT, /*<! When Phone connect to ESP32 with BLE, this event happen */
|
||||
ESP_BLUFI_EVENT_BLE_DISCONNECT, /*<! When Phone disconnect with BLE, this event happen */
|
||||
ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP, /*<! When Phone request ESP32's STA connect to AP, this event happen */
|
||||
ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP, /*<! When Phone request ESP32's STA disconnect from AP, this event happen */
|
||||
ESP_BLUFI_EVENT_GET_WIFI_STATUS, /*<! When Phone get ESP32 wifi status, this event happen */
|
||||
ESP_BLUFI_EVENT_DEAUTHENTICATE_STA, /*<! When Phone deauthenticate sta from SOFTAP, this event happen */
|
||||
/* recv data */
|
||||
ESP_BLUFI_EVENT_RECV_STA_BSSID, /*<! When Phone send STA BSSID to ESP32 to connect, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_STA_SSID, /*<! When Phone send STA SSID to ESP32 to connect, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_STA_PASSWD, /*<! When Phone send STA PASSWORD to ESP32 to connect, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SOFTAP_SSID, /*<! When Phone send SOFTAP SSID to ESP32 to start SOFTAP, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD, /*<! When Phone send SOFTAP PASSWORD to ESP32 to start SOFTAP, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM, /*<! When Phone send SOFTAP max connection number to ESP32 to start SOFTAP, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE, /*<! When Phone send SOFTAP authentication mode to ESP32 to start SOFTAP, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL, /*<! When Phone send SOFTAP channel to ESP32 to start SOFTAP, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_USERNAME, /*<! When Phone send username to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_CA_CERT, /*<! When Phone send CA certificate to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_CLIENT_CERT, /*<! When Phone send Client certificate to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SERVER_CERT, /*<! When Phone send Server certificate to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY, /*<! When Phone send Client Private key to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY, /*<! When Phone send Server Private key to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE, /*<! When Phone send Disconnect key to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_GET_WIFI_LIST, /*<! When Phone send get wifi list command to ESP32, this event happen */
|
||||
ESP_BLUFI_EVENT_REPORT_ERROR, /*<! When Blufi report error, this event happen */
|
||||
ESP_BLUFI_EVENT_RECV_CUSTOM_DATA, /*<! When Phone send custom data to ESP32, this event happen */
|
||||
} esp_blufi_cb_event_t;
|
||||
|
||||
/// BLUFI config status
|
||||
typedef enum {
|
||||
ESP_BLUFI_STA_CONN_SUCCESS = 0x00,
|
||||
ESP_BLUFI_STA_CONN_FAIL = 0x01,
|
||||
ESP_BLUFI_STA_CONNECTING = 0x02,
|
||||
ESP_BLUFI_STA_NO_IP = 0x03,
|
||||
} esp_blufi_sta_conn_state_t;
|
||||
|
||||
/// BLUFI init status
|
||||
typedef enum {
|
||||
ESP_BLUFI_INIT_OK = 0,
|
||||
ESP_BLUFI_INIT_FAILED,
|
||||
} esp_blufi_init_state_t;
|
||||
|
||||
/// BLUFI deinit status
|
||||
typedef enum {
|
||||
ESP_BLUFI_DEINIT_OK = 0,
|
||||
ESP_BLUFI_DEINIT_FAILED,
|
||||
} esp_blufi_deinit_state_t;
|
||||
|
||||
typedef enum {
|
||||
ESP_BLUFI_SEQUENCE_ERROR = 0,
|
||||
ESP_BLUFI_CHECKSUM_ERROR,
|
||||
ESP_BLUFI_DECRYPT_ERROR,
|
||||
ESP_BLUFI_ENCRYPT_ERROR,
|
||||
ESP_BLUFI_INIT_SECURITY_ERROR,
|
||||
ESP_BLUFI_DH_MALLOC_ERROR,
|
||||
ESP_BLUFI_DH_PARAM_ERROR,
|
||||
ESP_BLUFI_READ_PARAM_ERROR,
|
||||
ESP_BLUFI_MAKE_PUBLIC_ERROR,
|
||||
ESP_BLUFI_DATA_FORMAT_ERROR,
|
||||
ESP_BLUFI_CALC_MD5_ERROR,
|
||||
ESP_BLUFI_WIFI_SCAN_FAIL,
|
||||
ESP_BLUFI_MSG_STATE_ERROR,
|
||||
} esp_blufi_error_state_t;
|
||||
|
||||
/**
|
||||
* @brief BLUFI extra information structure
|
||||
*/
|
||||
typedef struct {
|
||||
//station
|
||||
uint8_t sta_bssid[6]; /*!< BSSID of station interface */
|
||||
bool sta_bssid_set; /*!< is BSSID of station interface set */
|
||||
uint8_t *sta_ssid; /*!< SSID of station interface */
|
||||
int sta_ssid_len; /*!< length of SSID of station interface */
|
||||
uint8_t *sta_passwd; /*!< password of station interface */
|
||||
int sta_passwd_len; /*!< length of password of station interface */
|
||||
uint8_t *softap_ssid; /*!< SSID of softap interface */
|
||||
int softap_ssid_len; /*!< length of SSID of softap interface */
|
||||
uint8_t *softap_passwd; /*!< password of station interface */
|
||||
int softap_passwd_len; /*!< length of password of station interface */
|
||||
uint8_t softap_authmode; /*!< authentication mode of softap interface */
|
||||
bool softap_authmode_set; /*!< is authentication mode of softap interface set */
|
||||
uint8_t softap_max_conn_num; /*!< max connection number of softap interface */
|
||||
bool softap_max_conn_num_set; /*!< is max connection number of softap interface set */
|
||||
uint8_t softap_channel; /*!< channel of softap interface */
|
||||
bool softap_channel_set; /*!< is channel of softap interface set */
|
||||
uint8_t sta_max_conn_retry; /*!< max retry of sta establish connection */
|
||||
bool sta_max_conn_retry_set; /*!< is max retry of sta establish connection set */
|
||||
uint8_t sta_conn_end_reason; /*!< reason of sta connection end */
|
||||
bool sta_conn_end_reason_set; /*!< is reason of sta connection end set */
|
||||
int8_t sta_conn_rssi; /*!< rssi of sta connection */
|
||||
bool sta_conn_rssi_set; /*!< is rssi of sta connection set */
|
||||
} esp_blufi_extra_info_t;
|
||||
|
||||
/** @brief Description of an WiFi AP */
|
||||
typedef struct {
|
||||
uint8_t ssid[33]; /**< SSID of AP */
|
||||
int8_t rssi; /**< signal strength of AP */
|
||||
} esp_blufi_ap_record_t;
|
||||
|
||||
/// Bluetooth address length
|
||||
#define ESP_BLUFI_BD_ADDR_LEN 6
|
||||
/// Bluetooth device address
|
||||
typedef uint8_t esp_blufi_bd_addr_t[ESP_BLUFI_BD_ADDR_LEN];
|
||||
|
||||
/**
|
||||
* @brief BLUFI callback parameters union
|
||||
*/
|
||||
typedef union {
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_INIT_FINISH
|
||||
*/
|
||||
struct blufi_init_finish_evt_param {
|
||||
esp_blufi_init_state_t state; /*!< Initial status */
|
||||
} init_finish; /*!< Blufi callback param of ESP_BLUFI_EVENT_INIT_FINISH */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_DEINIT_FINISH
|
||||
*/
|
||||
struct blufi_deinit_finish_evt_param {
|
||||
esp_blufi_deinit_state_t state; /*!< De-initial status */
|
||||
} deinit_finish; /*!< Blufi callback param of ESP_BLUFI_EVENT_DEINIT_FINISH */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_SET_WIFI_MODE
|
||||
*/
|
||||
struct blufi_set_wifi_mode_evt_param {
|
||||
wifi_mode_t op_mode; /*!< Wifi operation mode */
|
||||
} wifi_mode; /*!< Blufi callback param of ESP_BLUFI_EVENT_INIT_FINISH */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_CONNECT
|
||||
*/
|
||||
struct blufi_connect_evt_param {
|
||||
esp_blufi_bd_addr_t remote_bda; /*!< Blufi Remote bluetooth device address */
|
||||
uint8_t server_if; /*!< server interface */
|
||||
uint16_t conn_id; /*!< Connection id */
|
||||
} connect; /*!< Blufi callback param of ESP_BLUFI_EVENT_CONNECT */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_DISCONNECT
|
||||
*/
|
||||
struct blufi_disconnect_evt_param {
|
||||
esp_blufi_bd_addr_t remote_bda; /*!< Blufi Remote bluetooth device address */
|
||||
} disconnect; /*!< Blufi callback param of ESP_BLUFI_EVENT_DISCONNECT */
|
||||
|
||||
/* ESP_BLUFI_EVENT_REQ_WIFI_CONNECT */ /* No callback param */
|
||||
/* ESP_BLUFI_EVENT_REQ_WIFI_DISCONNECT */ /* No callback param */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_RECV_STA_BSSID
|
||||
*/
|
||||
struct blufi_recv_sta_bssid_evt_param {
|
||||
uint8_t bssid[6]; /*!< BSSID */
|
||||
} sta_bssid; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_STA_BSSID */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_RECV_STA_SSID
|
||||
*/
|
||||
struct blufi_recv_sta_ssid_evt_param {
|
||||
uint8_t *ssid; /*!< SSID */
|
||||
int ssid_len; /*!< SSID length */
|
||||
} sta_ssid; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_STA_SSID */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* ESP_BLUFI_EVENT_RECV_STA_PASSWD
|
||||
*/
|
||||
struct blufi_recv_sta_passwd_evt_param {
|
||||
uint8_t *passwd; /*!< Password */
|
||||
int passwd_len; /*!< Password Length */
|
||||
} sta_passwd; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_STA_PASSWD */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_RECV_SOFTAP_SSID
|
||||
*/
|
||||
struct blufi_recv_softap_ssid_evt_param {
|
||||
uint8_t *ssid; /*!< SSID */
|
||||
int ssid_len; /*!< SSID length */
|
||||
} softap_ssid; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SOFTAP_SSID */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD
|
||||
*/
|
||||
struct blufi_recv_softap_passwd_evt_param {
|
||||
uint8_t *passwd; /*!< Password */
|
||||
int passwd_len; /*!< Password Length */
|
||||
} softap_passwd; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM
|
||||
*/
|
||||
struct blufi_recv_softap_max_conn_num_evt_param {
|
||||
int max_conn_num; /*!< SSID */
|
||||
} softap_max_conn_num; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE
|
||||
*/
|
||||
struct blufi_recv_softap_auth_mode_evt_param {
|
||||
wifi_auth_mode_t auth_mode; /*!< Authentication mode */
|
||||
} softap_auth_mode; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE */
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL
|
||||
*/
|
||||
struct blufi_recv_softap_channel_evt_param {
|
||||
uint8_t channel; /*!< Authentication mode */
|
||||
} softap_channel; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL */
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_RECV_USERNAME
|
||||
*/
|
||||
struct blufi_recv_username_evt_param {
|
||||
uint8_t *name; /*!< Username point */
|
||||
int name_len; /*!< Username length */
|
||||
} username; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_USERNAME*/
|
||||
|
||||
/**
|
||||
* @brief ESP_BLUFI_EVENT_RECV_CA_CERT
|
||||
*/
|
||||
struct blufi_recv_ca_evt_param {
|
||||
uint8_t *cert; /*!< CA certificate point */
|
||||
int cert_len; /*!< CA certificate length */
|
||||
} ca; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_CA_CERT */
|
||||
|
||||
/**
|
||||
* ESP_BLUFI_EVENT_RECV_CLIENT_CERT
|
||||
*/
|
||||
struct blufi_recv_client_cert_evt_param {
|
||||
uint8_t *cert; /*!< Client certificate point */
|
||||
int cert_len; /*!< Client certificate length */
|
||||
} client_cert; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_CLIENT_CERT */
|
||||
|
||||
/**
|
||||
* ESP_BLUFI_EVENT_RECV_SERVER_CERT
|
||||
*/
|
||||
struct blufi_recv_server_cert_evt_param {
|
||||
uint8_t *cert; /*!< Client certificate point */
|
||||
int cert_len; /*!< Client certificate length */
|
||||
} server_cert; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SERVER_CERT */
|
||||
|
||||
/**
|
||||
* ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY
|
||||
*/
|
||||
struct blufi_recv_client_pkey_evt_param {
|
||||
uint8_t *pkey; /*!< Client Private Key point, if Client certificate not contain Key */
|
||||
int pkey_len; /*!< Client Private key length */
|
||||
} client_pkey; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY */
|
||||
/**
|
||||
* ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY
|
||||
*/
|
||||
struct blufi_recv_server_pkey_evt_param {
|
||||
uint8_t *pkey; /*!< Client Private Key point, if Client certificate not contain Key */
|
||||
int pkey_len; /*!< Client Private key length */
|
||||
} server_pkey; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY */
|
||||
/**
|
||||
* @brief
|
||||
* ESP_BLUFI_EVENT_REPORT_ERROR
|
||||
*/
|
||||
struct blufi_get_error_evt_param {
|
||||
esp_blufi_error_state_t state; /*!< Blufi error state */
|
||||
} report_error; /*!< Blufi callback param of ESP_BLUFI_EVENT_REPORT_ERROR */
|
||||
/**
|
||||
* @brief
|
||||
* ESP_BLUFI_EVENT_RECV_CUSTOM_DATA
|
||||
*/
|
||||
struct blufi_recv_custom_data_evt_param {
|
||||
uint8_t *data; /*!< Custom data */
|
||||
uint32_t data_len; /*!< Custom data Length */
|
||||
} custom_data; /*!< Blufi callback param of ESP_BLUFI_EVENT_RECV_CUSTOM_DATA */
|
||||
} esp_blufi_cb_param_t;
|
||||
|
||||
/**
|
||||
* @brief BLUFI event callback function type
|
||||
* @param event : Event type
|
||||
* @param param : Point to callback parameter, currently is union type
|
||||
*/
|
||||
typedef void (* esp_blufi_event_cb_t)(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);
|
||||
|
||||
/* security function declare */
|
||||
|
||||
/**
|
||||
* @brief BLUFI negotiate data handler
|
||||
* @param data : data from phone
|
||||
* @param len : length of data from phone
|
||||
* @param output_data : data want to send to phone
|
||||
* @param output_len : length of data want to send to phone
|
||||
* @param need_free : output reporting if memory needs to be freed or not *
|
||||
*/
|
||||
typedef void (*esp_blufi_negotiate_data_handler_t)(uint8_t *data, int len, uint8_t **output_data, int *output_len, bool *need_free);
|
||||
|
||||
/**
|
||||
* @brief BLUFI encrypt the data after negotiate a share key
|
||||
* @param iv8 : initial vector(8bit), normally, blufi core will input packet sequence number
|
||||
* @param crypt_data : plain text and encrypted data, the encrypt function must support autochthonous encrypt
|
||||
* @param crypt_len : length of plain text
|
||||
* @return Nonnegative number is encrypted length, if error, return negative number;
|
||||
*/
|
||||
typedef int (* esp_blufi_encrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
|
||||
|
||||
/**
|
||||
* @brief BLUFI decrypt the data after negotiate a share key
|
||||
* @param iv8 : initial vector(8bit), normally, blufi core will input packet sequence number
|
||||
* @param crypt_data : encrypted data and plain text, the encrypt function must support autochthonous decrypt
|
||||
* @param crypt_len : length of encrypted text
|
||||
* @return Nonnegative number is decrypted length, if error, return negative number;
|
||||
*/
|
||||
typedef int (* esp_blufi_decrypt_func_t)(uint8_t iv8, uint8_t *crypt_data, int crypt_len);
|
||||
|
||||
/**
|
||||
* @brief BLUFI checksum
|
||||
* @param iv8 : initial vector(8bit), normally, blufi core will input packet sequence number
|
||||
* @param data : data need to checksum
|
||||
* @param len : length of data
|
||||
*/
|
||||
typedef uint16_t (*esp_blufi_checksum_func_t)(uint8_t iv8, uint8_t *data, int len);
|
||||
|
||||
/**
|
||||
* @brief BLUFI callback functions type
|
||||
*/
|
||||
typedef struct {
|
||||
esp_blufi_event_cb_t event_cb; /*!< BLUFI event callback */
|
||||
esp_blufi_negotiate_data_handler_t negotiate_data_handler; /*!< BLUFI negotiate data function for negotiate share key */
|
||||
esp_blufi_encrypt_func_t encrypt_func; /*!< BLUFI encrypt data function with share key generated by negotiate_data_handler */
|
||||
esp_blufi_decrypt_func_t decrypt_func; /*!< BLUFI decrypt data function with share key generated by negotiate_data_handler */
|
||||
esp_blufi_checksum_func_t checksum_func; /*!< BLUFI check sum function (FCS) */
|
||||
} esp_blufi_callbacks_t;
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to receive blufi callback event
|
||||
*
|
||||
* @param[in] callbacks: callback functions
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_register_callbacks(esp_blufi_callbacks_t *callbacks);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to initialize blufi_profile
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_profile_init(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to de-initialize blufi_profile
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_profile_deinit(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to send wifi connection report
|
||||
* @param opmode : wifi opmode
|
||||
* @param sta_conn_state : station is already in connection or not
|
||||
* @param softap_conn_num : softap connection number
|
||||
* @param extra_info : extra information, such as sta_ssid, softap_ssid and etc.
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_send_wifi_conn_report(wifi_mode_t opmode, esp_blufi_sta_conn_state_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *extra_info);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to send wifi list
|
||||
* @param apCount : wifi list count
|
||||
* @param list : wifi list
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_send_wifi_list(uint16_t apCount, esp_blufi_ap_record_t *list);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Get BLUFI profile version
|
||||
*
|
||||
* @return Most 8bit significant is Great version, Least 8bit is Sub version
|
||||
*
|
||||
*/
|
||||
uint16_t esp_blufi_get_version(void);
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to send blufi error information
|
||||
* @param state : error state
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_send_error_info(esp_blufi_error_state_t state);
|
||||
/**
|
||||
*
|
||||
* @brief This function is called to custom data
|
||||
* @param data : custom data value
|
||||
* @param data_len : the length of custom data
|
||||
*
|
||||
* @return ESP_OK - success, other - failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_send_custom_data(uint8_t *data, uint32_t data_len);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ESP_BLUFI_API_ */
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_alarm.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
void btc_alarm_handler(btc_msg_t *msg)
|
||||
{
|
||||
btc_alarm_args_t *arg = (btc_alarm_args_t *)msg->arg;
|
||||
|
||||
BTC_TRACE_DEBUG("%s act %d\n", __FUNCTION__, msg->act);
|
||||
|
||||
if (arg->cb) {
|
||||
arg->cb(arg->cb_data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include "btc/btc_task.h"
|
||||
#include "osi/thread.h"
|
||||
|
||||
#if BTC_DYNAMIC_MEMORY == FALSE
|
||||
void *btc_profile_cb_tab[BTC_PID_NUM] = {};
|
||||
#else
|
||||
void **btc_profile_cb_tab;
|
||||
#endif
|
||||
|
||||
void esp_profile_cb_reset(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BTC_PID_NUM; i++) {
|
||||
btc_profile_cb_tab[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int btc_profile_cb_set(btc_pid_t profile_id, void *cb)
|
||||
{
|
||||
if (profile_id < 0 || profile_id >= BTC_PID_NUM) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
btc_profile_cb_tab[profile_id] = cb;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *btc_profile_cb_get(btc_pid_t profile_id)
|
||||
{
|
||||
if (profile_id < 0 || profile_id >= BTC_PID_NUM) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return btc_profile_cb_tab[profile_id];
|
||||
}
|
||||
@@ -0,0 +1,549 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "btc/btc_task.h"
|
||||
#include "osi/thread.h"
|
||||
#include "esp_log.h"
|
||||
#include "bt_common.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "btc/btc_alarm.h"
|
||||
|
||||
#include "btc/btc_manage.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "blufi_int.h"
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "common/bt_target.h"
|
||||
#include "btc/btc_main.h"
|
||||
#include "btc/btc_dev.h"
|
||||
#include "btc_gatts.h"
|
||||
#include "btc_gattc.h"
|
||||
#include "btc_gatt_common.h"
|
||||
#include "btc_gap_ble.h"
|
||||
#include "btc/btc_dm.h"
|
||||
#include "bta/bta_gatt_api.h"
|
||||
#if CLASSIC_BT_INCLUDED
|
||||
#include "btc/btc_profile_queue.h"
|
||||
#if (BTC_GAP_BT_INCLUDED == TRUE)
|
||||
#include "btc_gap_bt.h"
|
||||
#endif /* BTC_GAP_BT_INCLUDED == TRUE */
|
||||
#if BTC_AV_INCLUDED
|
||||
#include "btc_av.h"
|
||||
#include "btc_avrc.h"
|
||||
#include "btc_av_co.h"
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
||||
#if (BTC_SPP_INCLUDED == TRUE)
|
||||
#include "btc_spp.h"
|
||||
#endif /* #if (BTC_SPP_INCLUDED == TRUE) */
|
||||
#if (BTC_L2CAP_INCLUDED == TRUE)
|
||||
#include "btc_l2cap.h"
|
||||
#endif /* #if (BTC_L2CAP_INCLUDED == TRUE) */
|
||||
#if (BTC_SDP_INCLUDED == TRUE)
|
||||
#include "btc_sdp.h"
|
||||
#endif /* #if (BTC_SDP_INCLUDED == TRUE) */
|
||||
#if BTC_HF_INCLUDED
|
||||
#include "btc_hf_ag.h"
|
||||
#endif/* #if BTC_HF_INCLUDED */
|
||||
#if BTC_HF_CLIENT_INCLUDED
|
||||
#include "btc_hf_client.h"
|
||||
#endif /* #if BTC_HF_CLIENT_INCLUDED */
|
||||
#if BTC_HD_INCLUDED == TRUE
|
||||
#include "btc_hd.h"
|
||||
#endif /* BTC_HD_INCLUDED */
|
||||
#if BTC_HH_INCLUDED == TRUE
|
||||
#include "btc_hh.h"
|
||||
#endif /* BTC_HH_INCLUDED */
|
||||
#endif /* #if CLASSIC_BT_INCLUDED */
|
||||
#endif
|
||||
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
#include "btc_gap_ble.h"
|
||||
#endif
|
||||
|
||||
#if CONFIG_BLE_MESH
|
||||
#include "btc_ble_mesh_ble.h"
|
||||
#include "btc_ble_mesh_prov.h"
|
||||
#include "btc_ble_mesh_health_model.h"
|
||||
#include "btc_ble_mesh_config_model.h"
|
||||
#include "btc_ble_mesh_agg_model.h"
|
||||
#include "btc_ble_mesh_brc_model.h"
|
||||
#include "btc_ble_mesh_df_model.h"
|
||||
#include "btc_ble_mesh_lcd_model.h"
|
||||
#include "btc_ble_mesh_odp_model.h"
|
||||
#include "btc_ble_mesh_prb_model.h"
|
||||
#include "btc_ble_mesh_rpr_model.h"
|
||||
#include "btc_ble_mesh_sar_model.h"
|
||||
#include "btc_ble_mesh_srpl_model.h"
|
||||
#include "btc_ble_mesh_generic_model.h"
|
||||
#include "btc_ble_mesh_lighting_model.h"
|
||||
#include "btc_ble_mesh_sensor_model.h"
|
||||
#include "btc_ble_mesh_time_scene_model.h"
|
||||
#include "btc_ble_mesh_mbt_model.h"
|
||||
#endif /* #if CONFIG_BLE_MESH */
|
||||
|
||||
#define BTC_TASK_PINNED_TO_CORE (TASK_PINNED_TO_CORE)
|
||||
#define BTC_TASK_STACK_SIZE (BT_BTC_TASK_STACK_SIZE + BT_TASK_EXTRA_STACK_SIZE) //by menuconfig
|
||||
#define BTC_TASK_NAME "BTC_TASK"
|
||||
#define BTC_TASK_PRIO (BT_TASK_MAX_PRIORITIES - 6)
|
||||
#define BTC_TASK_WORKQUEUE_NUM (2)
|
||||
#define BTC_TASK_WORKQUEUE0_LEN (0)
|
||||
#define BTC_TASK_WORKQUEUE1_LEN (5)
|
||||
|
||||
osi_thread_t *btc_thread;
|
||||
|
||||
static const btc_func_t profile_tab[BTC_PID_NUM] = {
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
[BTC_PID_MAIN_INIT] = {btc_main_call_handler, NULL },
|
||||
[BTC_PID_DEV] = {btc_dev_call_handler, NULL },
|
||||
#if (GATTS_INCLUDED == TRUE)
|
||||
[BTC_PID_GATTS] = {btc_gatts_call_handler, btc_gatts_cb_handler },
|
||||
#endif ///GATTS_INCLUDED == TRUE
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
[BTC_PID_GATTC] = {btc_gattc_call_handler, btc_gattc_cb_handler },
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
#if (GATTS_INCLUDED == TRUE || GATTC_INCLUDED == TRUE)
|
||||
[BTC_PID_GATT_COMMON] = {btc_gatt_com_call_handler, NULL },
|
||||
#endif //GATTC_INCLUDED == TRUE || GATTS_INCLUDED == TRUE
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
[BTC_PID_GAP_BLE] = {btc_gap_ble_call_handler, btc_gap_ble_cb_handler },
|
||||
#else
|
||||
[BTC_PID_GAP_BLE] = {NULL, NULL},
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
[BTC_PID_BLE_HID] = {NULL, NULL},
|
||||
[BTC_PID_SPPLIKE] = {NULL, NULL},
|
||||
[BTC_PID_DM_SEC] = {NULL, btc_dm_sec_cb_handler },
|
||||
#endif
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
[BTC_PID_BLUFI] = {btc_blufi_call_handler, btc_blufi_cb_handler },
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
[BTC_PID_ALARM] = {btc_alarm_handler, NULL },
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#if CLASSIC_BT_INCLUDED
|
||||
#if (BTC_GAP_BT_INCLUDED == TRUE)
|
||||
[BTC_PID_GAP_BT] = {btc_gap_bt_call_handler, btc_gap_bt_cb_handler },
|
||||
#endif /* (BTC_GAP_BT_INCLUDED == TRUE) */
|
||||
[BTC_PID_PRF_QUE] = {btc_profile_queue_handler, NULL },
|
||||
#if BTC_AV_INCLUDED
|
||||
[BTC_PID_A2DP] = {btc_a2dp_call_handler, btc_a2dp_cb_handler },
|
||||
[BTC_PID_AVRC_CT] = {btc_avrc_ct_call_handler, NULL },
|
||||
[BTC_PID_AVRC_TG] = {btc_avrc_tg_call_handler, NULL },
|
||||
#endif /* #if BTC_AV_INCLUDED */
|
||||
#if (BTC_SPP_INCLUDED == TRUE)
|
||||
[BTC_PID_SPP] = {btc_spp_call_handler, btc_spp_cb_handler },
|
||||
#endif /* #if (BTC_SPP_INCLUDED == TRUE) */
|
||||
#if (BTC_L2CAP_INCLUDED == TRUE)
|
||||
[BTC_PID_L2CAP] = {btc_l2cap_call_handler, btc_l2cap_cb_handler },
|
||||
#endif /* #if (BTC_L2CAP_INCLUDED == TRUE) */
|
||||
#if (BTC_SDP_INCLUDED == TRUE)
|
||||
[BTC_PID_SDP] = {btc_sdp_call_handler, btc_sdp_cb_handler },
|
||||
#endif /* #if (BTC_SDP_INCLUDED == TRUE) */
|
||||
#if BTC_HF_INCLUDED
|
||||
[BTC_PID_HF] = {btc_hf_call_handler, btc_hf_cb_handler},
|
||||
#endif /* #if BTC_HF_INCLUDED */
|
||||
#if BTC_HF_CLIENT_INCLUDED
|
||||
[BTC_PID_HF_CLIENT] = {btc_hf_client_call_handler, btc_hf_client_cb_handler},
|
||||
#endif /* #if BTC_HF_CLIENT_INCLUDED */
|
||||
#if BTC_HD_INCLUDED
|
||||
[BTC_PID_HD] = {btc_hd_call_handler, btc_hd_cb_handler },
|
||||
#endif
|
||||
#if BTC_HH_INCLUDED
|
||||
[BTC_PID_HH] = {btc_hh_call_handler, btc_hh_cb_handler },
|
||||
#endif
|
||||
#endif /* #if CLASSIC_BT_INCLUDED */
|
||||
#endif
|
||||
#if CONFIG_BLE_MESH
|
||||
[BTC_PID_PROV] = {btc_ble_mesh_prov_call_handler, btc_ble_mesh_prov_cb_handler },
|
||||
[BTC_PID_MODEL] = {btc_ble_mesh_model_call_handler, btc_ble_mesh_model_cb_handler },
|
||||
#if CONFIG_BLE_MESH_HEALTH_CLI
|
||||
[BTC_PID_HEALTH_CLIENT] = {btc_ble_mesh_health_client_call_handler, btc_ble_mesh_health_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_HEALTH_CLI */
|
||||
#if CONFIG_BLE_MESH_HEALTH_SRV
|
||||
[BTC_PID_HEALTH_SERVER] = {btc_ble_mesh_health_server_call_handler, btc_ble_mesh_health_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_HEALTH_SRV */
|
||||
#if CONFIG_BLE_MESH_CFG_CLI
|
||||
[BTC_PID_CONFIG_CLIENT] = {btc_ble_mesh_config_client_call_handler, btc_ble_mesh_config_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_CFG_CLI */
|
||||
[BTC_PID_CONFIG_SERVER] = {NULL, btc_ble_mesh_config_server_cb_handler },
|
||||
#if CONFIG_BLE_MESH_AGG_CLI
|
||||
[BTC_PID_AGG_CLIENT] = {btc_ble_mesh_agg_client_call_handler, btc_ble_mesh_agg_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_AGG_CLI */
|
||||
#if CONFIG_BLE_MESH_AGG_SRV
|
||||
[BTC_PID_AGG_SERVER] = {NULL, btc_ble_mesh_agg_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_AGG_SRV */
|
||||
#if CONFIG_BLE_MESH_BRC_CLI
|
||||
[BTC_PID_BRC_CLIENT] = {btc_ble_mesh_brc_client_call_handler, btc_ble_mesh_brc_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_BRC_CLI */
|
||||
#if CONFIG_BLE_MESH_BRC_SRV
|
||||
[BTC_PID_BRC_SERVER] = {NULL, btc_ble_mesh_brc_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_BRC_SRV */
|
||||
#if CONFIG_BLE_MESH_DF_CLI
|
||||
[BTC_PID_DF_CLIENT] = {btc_ble_mesh_df_client_call_handler, btc_ble_mesh_df_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_DF_CLI */
|
||||
#if CONFIG_BLE_MESH_DF_SRV
|
||||
[BTC_PID_DF_SERVER] = {NULL, btc_ble_mesh_df_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_DF_SRV */
|
||||
#if CONFIG_BLE_MESH_LCD_CLI
|
||||
[BTC_PID_LCD_CLIENT] = {btc_ble_mesh_lcd_client_call_handler, btc_ble_mesh_lcd_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_LCD_CLI */
|
||||
#if CONFIG_BLE_MESH_LCD_SRV
|
||||
[BTC_PID_LCD_SERVER] = {NULL, btc_ble_mesh_lcd_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_LCD_SRV */
|
||||
#if CONFIG_BLE_MESH_ODP_CLI
|
||||
[BTC_PID_ODP_CLIENT] = {btc_ble_mesh_odp_client_call_handler, btc_ble_mesh_odp_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_ODP_CLI */
|
||||
#if CONFIG_BLE_MESH_ODP_SRV
|
||||
[BTC_PID_ODP_SERVER] = {NULL, btc_ble_mesh_odp_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_ODP_SRV */
|
||||
#if CONFIG_BLE_MESH_PRB_CLI
|
||||
[BTC_PID_PRB_CLIENT] = {btc_ble_mesh_prb_client_call_handler, btc_ble_mesh_prb_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_PRB_CLI */
|
||||
#if CONFIG_BLE_MESH_PRB_SRV
|
||||
[BTC_PID_PRB_SERVER] = {NULL, btc_ble_mesh_prb_server_cb_handler },
|
||||
#endif /*CONFIG_BLE_MESH_PRB_SRV*/
|
||||
#if CONFIG_BLE_MESH_RPR_CLI
|
||||
[BTC_PID_RPR_CLIENT] = {btc_ble_mesh_rpr_client_call_handler, btc_ble_mesh_rpr_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_RPR_CLI */
|
||||
#if CONFIG_BLE_MESH_RPR_SRV
|
||||
[BTC_PID_RPR_SERVER] = {NULL, btc_ble_mesh_rpr_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_RPR_SRV */
|
||||
#if CONFIG_BLE_MESH_SAR_CLI
|
||||
[BTC_PID_SAR_CLIENT] = {btc_ble_mesh_sar_client_call_handler, btc_ble_mesh_sar_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_SAR_CLI */
|
||||
#if CONFIG_BLE_MESH_SAR_SRV
|
||||
[BTC_PID_SAR_SERVER] = {NULL, btc_ble_mesh_sar_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_SAR_SRV */
|
||||
#if CONFIG_BLE_MESH_SRPL_CLI
|
||||
[BTC_PID_SRPL_CLIENT] = {btc_ble_mesh_srpl_client_call_handler, btc_ble_mesh_srpl_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_SRPL_CLI */
|
||||
#if CONFIG_BLE_MESH_SRPL_SRV
|
||||
[BTC_PID_SRPL_SERVER] = {NULL, btc_ble_mesh_srpl_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_SRPL_SRV */
|
||||
#if CONFIG_BLE_MESH_GENERIC_CLIENT
|
||||
[BTC_PID_GENERIC_CLIENT] = {btc_ble_mesh_generic_client_call_handler, btc_ble_mesh_generic_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_GENERIC_CLIENT */
|
||||
#if CONFIG_BLE_MESH_LIGHTING_CLIENT
|
||||
[BTC_PID_LIGHTING_CLIENT] = {btc_ble_mesh_lighting_client_call_handler, btc_ble_mesh_lighting_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_LIGHTING_CLIENT */
|
||||
#if CONFIG_BLE_MESH_SENSOR_CLI
|
||||
[BTC_PID_SENSOR_CLIENT] = {btc_ble_mesh_sensor_client_call_handler, btc_ble_mesh_sensor_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_SENSOR_CLI */
|
||||
#if CONFIG_BLE_MESH_TIME_SCENE_CLIENT
|
||||
[BTC_PID_TIME_SCENE_CLIENT] = {btc_ble_mesh_time_scene_client_call_handler, btc_ble_mesh_time_scene_client_cb_handler},
|
||||
#endif /* CONFIG_BLE_MESH_TIME_SCENE_CLIENT */
|
||||
#if CONFIG_BLE_MESH_GENERIC_SERVER
|
||||
[BTC_PID_GENERIC_SERVER] = {NULL, btc_ble_mesh_generic_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_GENERIC_SERVER */
|
||||
#if CONFIG_BLE_MESH_LIGHTING_SERVER
|
||||
[BTC_PID_LIGHTING_SERVER] = {NULL, btc_ble_mesh_lighting_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_LIGHTING_SERVER */
|
||||
#if CONFIG_BLE_MESH_SENSOR_SERVER
|
||||
[BTC_PID_SENSOR_SERVER] = {NULL, btc_ble_mesh_sensor_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_SENSOR_SERVER */
|
||||
#if CONFIG_BLE_MESH_TIME_SCENE_SERVER
|
||||
[BTC_PID_TIME_SCENE_SERVER] = {NULL, btc_ble_mesh_time_scene_server_cb_handler},
|
||||
#endif /* CONFIG_BLE_MESH_TIME_SCENE_SERVER */
|
||||
#if CONFIG_BLE_MESH_MBT_CLI
|
||||
[BTC_PID_MBT_CLIENT] = {btc_ble_mesh_mbt_client_call_handler, btc_ble_mesh_mbt_client_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_MBT_CLI */
|
||||
#if CONFIG_BLE_MESH_MBT_SRV
|
||||
[BTC_PID_MBT_SERVER] = {btc_ble_mesh_mbt_server_call_handler, btc_ble_mesh_mbt_server_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_MBT_SRV */
|
||||
#if CONFIG_BLE_MESH_BLE_COEX_SUPPORT
|
||||
[BTC_PID_BLE_MESH_BLE_COEX] = {btc_ble_mesh_ble_call_handler, btc_ble_mesh_ble_cb_handler },
|
||||
#endif /* CONFIG_BLE_MESH_BLE_COEX_SUPPORT */
|
||||
#endif /* #if CONFIG_BLE_MESH */
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
**
|
||||
** Function btc_task
|
||||
**
|
||||
** Description Process profile Task Thread.
|
||||
******************************************************************************/
|
||||
static void btc_thread_handler(void *arg)
|
||||
{
|
||||
btc_msg_t *msg = (btc_msg_t *)arg;
|
||||
|
||||
BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg->sig, msg->pid, msg->act, msg->arg);
|
||||
switch (msg->sig) {
|
||||
case BTC_SIG_API_CALL:
|
||||
profile_tab[msg->pid].btc_call(msg);
|
||||
break;
|
||||
case BTC_SIG_API_CB:
|
||||
profile_tab[msg->pid].btc_cb(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
osi_free(msg);
|
||||
}
|
||||
|
||||
static bt_status_t btc_task_post(btc_msg_t *msg, uint32_t timeout)
|
||||
{
|
||||
if (osi_thread_post(btc_thread, btc_thread_handler, msg, 0, timeout) == false) {
|
||||
return BT_STATUS_BUSY;
|
||||
}
|
||||
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* transfer an message to another module in the different task.
|
||||
* @param msg message
|
||||
* @param arg paramter
|
||||
* @param arg_len length of paramter
|
||||
* @param copy_func deep copy function
|
||||
* @param free_func deep free function
|
||||
* @return BT_STATUS_SUCCESS: success
|
||||
* others: fail
|
||||
*/
|
||||
bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg_deep_copy_t copy_func,
|
||||
btc_arg_deep_free_t free_func)
|
||||
{
|
||||
btc_msg_t* lmsg;
|
||||
bt_status_t ret;
|
||||
// arg XOR arg_len
|
||||
if ((msg == NULL) || ((arg == NULL) == !(arg_len == 0))) {
|
||||
BTC_TRACE_WARNING("%s Invalid parameters\n", __func__);
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
}
|
||||
|
||||
BTC_TRACE_DEBUG("%s msg %u %u %u %p\n", __func__, msg->sig, msg->pid, msg->act, arg);
|
||||
|
||||
lmsg = (btc_msg_t *)osi_malloc(sizeof(btc_msg_t) + arg_len);
|
||||
if (lmsg == NULL) {
|
||||
BTC_TRACE_WARNING("%s No memory\n", __func__);
|
||||
return BT_STATUS_NOMEM;
|
||||
}
|
||||
|
||||
memcpy(lmsg, msg, sizeof(btc_msg_t));
|
||||
if (arg) {
|
||||
memset(lmsg->arg, 0x00, arg_len); //important, avoid arg which have no length
|
||||
memcpy(lmsg->arg, arg, arg_len);
|
||||
if (copy_func) {
|
||||
copy_func(lmsg, lmsg->arg, arg);
|
||||
}
|
||||
}
|
||||
|
||||
ret = btc_task_post(lmsg, OSI_THREAD_MAX_TIMEOUT);
|
||||
if (ret != BT_STATUS_SUCCESS) {
|
||||
if (copy_func && free_func) {
|
||||
free_func(lmsg);
|
||||
}
|
||||
osi_free(lmsg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* transfer an message to another module in tha same task.
|
||||
* @param msg message
|
||||
* @return BT_STATUS_SUCCESS: success
|
||||
* others: fail
|
||||
*/
|
||||
bt_status_t btc_inter_profile_call(btc_msg_t *msg)
|
||||
{
|
||||
if (msg == NULL) {
|
||||
return BT_STATUS_PARM_INVALID;
|
||||
}
|
||||
|
||||
switch (msg->sig) {
|
||||
case BTC_SIG_API_CALL:
|
||||
profile_tab[msg->pid].btc_call(msg);
|
||||
break;
|
||||
case BTC_SIG_API_CB:
|
||||
profile_tab[msg->pid].btc_cb(msg);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#if BTC_DYNAMIC_MEMORY
|
||||
|
||||
static void btc_deinit_mem(void) {
|
||||
if (btc_dm_cb_ptr) {
|
||||
osi_free(btc_dm_cb_ptr);
|
||||
btc_dm_cb_ptr = NULL;
|
||||
}
|
||||
|
||||
if (btc_profile_cb_tab) {
|
||||
osi_free(btc_profile_cb_tab);
|
||||
btc_profile_cb_tab = NULL;
|
||||
}
|
||||
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
if (gl_bta_adv_data_ptr) {
|
||||
osi_free(gl_bta_adv_data_ptr);
|
||||
gl_bta_adv_data_ptr = NULL;
|
||||
}
|
||||
|
||||
if (gl_bta_scan_rsp_data_ptr) {
|
||||
osi_free(gl_bta_scan_rsp_data_ptr);
|
||||
gl_bta_scan_rsp_data_ptr = NULL;
|
||||
}
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
|
||||
#if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE
|
||||
if (btc_creat_tab_env_ptr) {
|
||||
osi_free(btc_creat_tab_env_ptr);
|
||||
btc_creat_tab_env_ptr = NULL;
|
||||
}
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
if (blufi_env_ptr) {
|
||||
osi_free(blufi_env_ptr);
|
||||
blufi_env_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE
|
||||
if (hf_client_local_param_ptr) {
|
||||
osi_free(hf_client_local_param_ptr);
|
||||
hf_client_local_param_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE
|
||||
if (btc_rc_cb_ptr) {
|
||||
osi_free(btc_rc_cb_ptr);
|
||||
btc_rc_cb_ptr = NULL;
|
||||
}
|
||||
if (bta_av_co_cb_ptr) {
|
||||
osi_free(bta_av_co_cb_ptr);
|
||||
bta_av_co_cb_ptr = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bt_status_t btc_init_mem(void) {
|
||||
if ((btc_dm_cb_ptr = (btc_dm_cb_t *)osi_malloc(sizeof(btc_dm_cb_t))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)btc_dm_cb_ptr, 0, sizeof(btc_dm_cb_t));
|
||||
|
||||
if ((btc_profile_cb_tab = (void **)osi_malloc(sizeof(void *) * BTC_PID_NUM)) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)btc_profile_cb_tab, 0, sizeof(void *) * BTC_PID_NUM);
|
||||
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
if ((gl_bta_adv_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)gl_bta_adv_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA));
|
||||
|
||||
if ((gl_bta_scan_rsp_data_ptr = (tBTA_BLE_ADV_DATA *)osi_malloc(sizeof(tBTA_BLE_ADV_DATA))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)gl_bta_scan_rsp_data_ptr, 0, sizeof(tBTA_BLE_ADV_DATA));
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
|
||||
#if GATTS_INCLUDED == TRUE && GATT_DYNAMIC_MEMORY == TRUE
|
||||
if ((btc_creat_tab_env_ptr = (esp_btc_creat_tab_t *)osi_malloc(sizeof(esp_btc_creat_tab_t))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)btc_creat_tab_env_ptr, 0, sizeof(esp_btc_creat_tab_t));
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
if ((blufi_env_ptr = (tBLUFI_ENV *)osi_malloc(sizeof(tBLUFI_ENV))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)blufi_env_ptr, 0, sizeof(tBLUFI_ENV));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BTC_HF_CLIENT_INCLUDED == TRUE && HFP_DYNAMIC_MEMORY == TRUE
|
||||
if ((hf_client_local_param_ptr = (hf_client_local_param_t *)osi_malloc(sizeof(hf_client_local_param_t))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)hf_client_local_param_ptr, 0, sizeof(hf_client_local_param_t));
|
||||
#endif
|
||||
|
||||
#if BTC_AV_INCLUDED == TRUE && AVRC_DYNAMIC_MEMORY == TRUE
|
||||
if ((btc_rc_cb_ptr = (btc_rc_cb_t *)osi_malloc(sizeof(btc_rc_cb_t))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)btc_rc_cb_ptr, 0, sizeof(btc_rc_cb_t));
|
||||
if ((bta_av_co_cb_ptr = (tBTA_AV_CO_CB *)osi_malloc(sizeof(tBTA_AV_CO_CB))) == NULL) {
|
||||
goto error_exit;
|
||||
}
|
||||
memset((void *)bta_av_co_cb_ptr, 0, sizeof(tBTA_AV_CO_CB));
|
||||
#endif
|
||||
|
||||
return BT_STATUS_SUCCESS;
|
||||
|
||||
error_exit:;
|
||||
btc_deinit_mem();
|
||||
return BT_STATUS_NOMEM;
|
||||
}
|
||||
#endif ///BTC_DYNAMIC_MEMORY
|
||||
|
||||
bt_status_t btc_init(void)
|
||||
{
|
||||
const size_t workqueue_len[] = {BTC_TASK_WORKQUEUE0_LEN, BTC_TASK_WORKQUEUE1_LEN};
|
||||
btc_thread = osi_thread_create(BTC_TASK_NAME, BTC_TASK_STACK_SIZE, BTC_TASK_PRIO, BTC_TASK_PINNED_TO_CORE,
|
||||
BTC_TASK_WORKQUEUE_NUM, workqueue_len);
|
||||
if (btc_thread == NULL) {
|
||||
return BT_STATUS_NOMEM;
|
||||
}
|
||||
|
||||
#if BTC_DYNAMIC_MEMORY
|
||||
if (btc_init_mem() != BT_STATUS_SUCCESS){
|
||||
return BT_STATUS_NOMEM;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
btc_gap_callback_init();
|
||||
btc_gap_ble_init();
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
|
||||
#if SCAN_QUEUE_CONGEST_CHECK
|
||||
btc_adv_list_init();
|
||||
#endif
|
||||
/* TODO: initial the profile_tab */
|
||||
return BT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void btc_deinit(void)
|
||||
{
|
||||
#if BTC_DYNAMIC_MEMORY
|
||||
btc_deinit_mem();
|
||||
#endif
|
||||
|
||||
osi_thread_free(btc_thread);
|
||||
btc_thread = NULL;
|
||||
#if (BLE_INCLUDED == TRUE)
|
||||
btc_gap_ble_deinit();
|
||||
#endif ///BLE_INCLUDED == TRUE
|
||||
#if SCAN_QUEUE_CONGEST_CHECK
|
||||
btc_adv_list_deinit();
|
||||
#endif
|
||||
}
|
||||
|
||||
bool btc_check_queue_is_congest(void)
|
||||
{
|
||||
if (osi_thread_queue_wait_size(btc_thread, 0) >= BT_QUEUE_CONGEST_SIZE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int get_btc_work_queue_size(void)
|
||||
{
|
||||
return osi_thread_queue_wait_size(btc_thread, 0);
|
||||
}
|
||||
|
||||
osi_thread_t *btc_get_current_thread(void)
|
||||
{
|
||||
return btc_thread;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __BTC_ALARM_H__
|
||||
#define __BTC_ALARM_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "osi/alarm.h"
|
||||
|
||||
/* btc_alarm_args_t */
|
||||
typedef struct {
|
||||
osi_alarm_callback_t cb;
|
||||
void *cb_data;
|
||||
} btc_alarm_args_t;
|
||||
|
||||
void btc_alarm_handler(btc_msg_t *msg);
|
||||
|
||||
#endif /* __BTC_ALARM_H__ */
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BTC_MANAGE_H__
|
||||
#define __BTC_MANAGE_H__
|
||||
|
||||
#include "btc/btc_task.h"
|
||||
|
||||
#if BTC_DYNAMIC_MEMORY == FALSE
|
||||
extern void *btc_profile_cb_tab[BTC_PID_NUM];
|
||||
#else
|
||||
extern void **btc_profile_cb_tab;
|
||||
#endif
|
||||
/* reset gatt callback table */
|
||||
void esp_profile_cb_reset(void);
|
||||
|
||||
int btc_profile_cb_set(btc_pid_t profile_id, void *cb);
|
||||
void *btc_profile_cb_get(btc_pid_t profile_id);
|
||||
|
||||
#endif /* __BTC_MANAGE_H__ */
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BTC_TASK_H__
|
||||
#define __BTC_TASK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bt_common.h"
|
||||
#include "osi/thread.h"
|
||||
|
||||
#if CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "common/bt_target.h"
|
||||
#endif
|
||||
|
||||
typedef struct btc_msg {
|
||||
uint8_t sig; //event signal
|
||||
uint8_t aid; //application id
|
||||
uint8_t pid; //profile id
|
||||
uint8_t act; //profile action, defined in seprerate header files
|
||||
UINT8 arg[0]; //param for btc function or function param
|
||||
} btc_msg_t;
|
||||
|
||||
typedef struct btc_adv_packet {
|
||||
uint8_t addr[6];
|
||||
uint8_t addr_type;
|
||||
} btc_adv_packet_t;
|
||||
|
||||
typedef enum {
|
||||
BTC_SIG_API_CALL = 0, // APP TO STACK
|
||||
BTC_SIG_API_CB, // STACK TO APP
|
||||
BTC_SIG_NUM,
|
||||
} btc_sig_t; //btc message type
|
||||
|
||||
typedef enum {
|
||||
BTC_PID_MAIN_INIT = 0,
|
||||
BTC_PID_DEV,
|
||||
BTC_PID_GATTS,
|
||||
#if (GATTC_INCLUDED == TRUE)
|
||||
BTC_PID_GATTC,
|
||||
#endif ///GATTC_INCLUDED == TRUE
|
||||
BTC_PID_GATT_COMMON,
|
||||
BTC_PID_GAP_BLE,
|
||||
BTC_PID_BLE_HID,
|
||||
BTC_PID_SPPLIKE,
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
BTC_PID_BLUFI,
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
BTC_PID_DM_SEC,
|
||||
BTC_PID_ALARM,
|
||||
#if (CLASSIC_BT_INCLUDED == TRUE)
|
||||
BTC_PID_GAP_BT,
|
||||
BTC_PID_PRF_QUE,
|
||||
BTC_PID_A2DP,
|
||||
BTC_PID_AVRC_CT,
|
||||
BTC_PID_AVRC_TG,
|
||||
BTC_PID_SPP,
|
||||
BTC_PID_HD,
|
||||
BTC_PID_HH,
|
||||
BTC_PID_L2CAP,
|
||||
BTC_PID_SDP,
|
||||
#if (BTC_HF_INCLUDED == TRUE)
|
||||
BTC_PID_HF,
|
||||
#endif /* BTC_HF_INCLUDED */
|
||||
#if (BTC_HF_CLIENT_INCLUDED == TRUE)
|
||||
BTC_PID_HF_CLIENT,
|
||||
#endif /* BTC_HF_CLIENT_INCLUDED */
|
||||
#endif /* CLASSIC_BT_INCLUDED */
|
||||
#if CONFIG_BLE_MESH
|
||||
BTC_PID_PROV,
|
||||
BTC_PID_MODEL,
|
||||
BTC_PID_HEALTH_CLIENT,
|
||||
BTC_PID_HEALTH_SERVER,
|
||||
BTC_PID_CONFIG_CLIENT,
|
||||
BTC_PID_CONFIG_SERVER,
|
||||
BTC_PID_AGG_CLIENT,
|
||||
BTC_PID_AGG_SERVER,
|
||||
BTC_PID_BRC_CLIENT,
|
||||
BTC_PID_BRC_SERVER,
|
||||
BTC_PID_DF_CLIENT,
|
||||
BTC_PID_DF_SERVER,
|
||||
BTC_PID_LCD_CLIENT,
|
||||
BTC_PID_LCD_SERVER,
|
||||
BTC_PID_ODP_CLIENT,
|
||||
BTC_PID_ODP_SERVER,
|
||||
BTC_PID_PRB_CLIENT,
|
||||
BTC_PID_PRB_SERVER,
|
||||
BTC_PID_RPR_CLIENT,
|
||||
BTC_PID_RPR_SERVER,
|
||||
BTC_PID_SAR_CLIENT,
|
||||
BTC_PID_SAR_SERVER,
|
||||
BTC_PID_SRPL_CLIENT,
|
||||
BTC_PID_SRPL_SERVER,
|
||||
BTC_PID_GENERIC_CLIENT,
|
||||
BTC_PID_LIGHTING_CLIENT,
|
||||
BTC_PID_SENSOR_CLIENT,
|
||||
BTC_PID_TIME_SCENE_CLIENT,
|
||||
BTC_PID_GENERIC_SERVER,
|
||||
BTC_PID_LIGHTING_SERVER,
|
||||
BTC_PID_SENSOR_SERVER,
|
||||
BTC_PID_TIME_SCENE_SERVER,
|
||||
BTC_PID_MBT_CLIENT,
|
||||
BTC_PID_MBT_SERVER,
|
||||
BTC_PID_BLE_MESH_BLE_COEX,
|
||||
#endif /* CONFIG_BLE_MESH */
|
||||
BTC_PID_NUM,
|
||||
} btc_pid_t; //btc profile id
|
||||
|
||||
typedef struct {
|
||||
void (* btc_call)(btc_msg_t *msg);
|
||||
void (* btc_cb)(btc_msg_t *msg);
|
||||
} btc_func_t;
|
||||
|
||||
typedef void (* btc_arg_deep_copy_t)(btc_msg_t *msg, void *dst, void *src);
|
||||
typedef void (* btc_arg_deep_free_t)(btc_msg_t *msg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* transfer an message to another module in the different task.
|
||||
* @param msg message
|
||||
* @param arg paramter
|
||||
* @param arg_len length of paramter
|
||||
* @param copy_func deep copy function
|
||||
* @param free_func deep free function
|
||||
* @return BT_STATUS_SUCCESS: success
|
||||
* others: fail
|
||||
*/
|
||||
bt_status_t btc_transfer_context(btc_msg_t *msg, void *arg, int arg_len, btc_arg_deep_copy_t copy_func,
|
||||
btc_arg_deep_free_t free_func);
|
||||
|
||||
/**
|
||||
* transfer an message to another module in tha same task.
|
||||
* @param msg message
|
||||
* @return BT_STATUS_SUCCESS: success
|
||||
* others: fail
|
||||
*/
|
||||
bt_status_t btc_inter_profile_call(btc_msg_t *msg);
|
||||
|
||||
bt_status_t btc_init(void);
|
||||
void btc_deinit(void);
|
||||
bool btc_check_queue_is_congest(void);
|
||||
int get_btc_work_queue_size(void);
|
||||
|
||||
/**
|
||||
* get the BTC thread handle
|
||||
* @return NULL: fail
|
||||
* others: pointer of osi_thread structure of BTC
|
||||
*/
|
||||
osi_thread_t *btc_get_current_thread(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __BTC_TASK_H__ */
|
||||
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "osi/allocator.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_manage.h"
|
||||
#include "blufi_int.h"
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_blufi_api.h"
|
||||
|
||||
#include "common/bt_target.h"
|
||||
#include "common/bt_trace.h"
|
||||
#include "stack/bt_types.h"
|
||||
#include "stack/gatt_api.h"
|
||||
#include "bta/bta_api.h"
|
||||
#include "bta/bta_gatt_api.h"
|
||||
#include "bta_gatts_int.h"
|
||||
#include "btc_gatt_util.h"
|
||||
#include "btc_gatts.h"
|
||||
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_gap_ble_api.h"
|
||||
#include "esp_gatt_common_api.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_blufi.h"
|
||||
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
static uint8_t server_if;
|
||||
static uint16_t conn_id;
|
||||
static uint8_t blufi_service_uuid128[32] = {
|
||||
/* LSB <--------------------------------------------------------------------------------> MSB */
|
||||
//first uuid, 16bit, [12],[13] is the value
|
||||
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00,
|
||||
};
|
||||
|
||||
static esp_ble_adv_data_t blufi_adv_data = {
|
||||
.set_scan_rsp = false,
|
||||
.include_name = true,
|
||||
.include_txpower = true,
|
||||
.min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
|
||||
.max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
|
||||
.appearance = 0x00,
|
||||
.manufacturer_len = 0,
|
||||
.p_manufacturer_data = NULL,
|
||||
.service_data_len = 0,
|
||||
.p_service_data = NULL,
|
||||
.service_uuid_len = 16,
|
||||
.p_service_uuid = blufi_service_uuid128,
|
||||
.flag = 0x6,
|
||||
};
|
||||
|
||||
static esp_ble_adv_params_t blufi_adv_params = {
|
||||
.adv_int_min = 0x100,
|
||||
.adv_int_max = 0x100,
|
||||
.adv_type = ADV_TYPE_IND,
|
||||
.own_addr_type = BLE_ADDR_TYPE_PUBLIC,
|
||||
//.peer_addr =
|
||||
//.peer_addr_type =
|
||||
.channel_map = ADV_CHNL_ALL,
|
||||
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
|
||||
};
|
||||
|
||||
void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
|
||||
esp_ble_gap_start_advertising(&blufi_adv_params);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// static functions declare
|
||||
static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data);
|
||||
|
||||
void blufi_create_service(void)
|
||||
{
|
||||
if (!blufi_env.enabled) {
|
||||
BTC_TRACE_ERROR("blufi service added error.");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.srvc_inst = 0x00;
|
||||
BTA_GATTS_CreateService(blufi_env.gatt_if, &blufi_srvc_uuid, blufi_env.srvc_inst, BLUFI_HDL_NUM, true);
|
||||
}
|
||||
|
||||
uint8_t esp_blufi_init(void)
|
||||
{
|
||||
|
||||
/* register the BLUFI profile to the BTA_GATTS module*/
|
||||
BTA_GATTS_AppRegister(&blufi_app_uuid, blufi_profile_cb);
|
||||
return GATT_SUCCESS;
|
||||
}
|
||||
|
||||
static void blufi_profile_cb(tBTA_GATTS_EVT event, tBTA_GATTS *p_data)
|
||||
{
|
||||
tBTA_GATTS_RSP rsp;
|
||||
BLUFI_TRACE_DEBUG("blufi profile cb event = %x\n", event);
|
||||
|
||||
switch (event) {
|
||||
case BTA_GATTS_REG_EVT:
|
||||
BLUFI_TRACE_DEBUG("REG: status %d, app_uuid %04x, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.uuid.uu.uuid16, p_data->reg_oper.server_if);
|
||||
|
||||
if (p_data->reg_oper.status != BTA_GATT_OK) {
|
||||
BLUFI_TRACE_ERROR("BLUFI profile register failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.gatt_if = p_data->reg_oper.server_if;
|
||||
blufi_env.enabled = true;
|
||||
|
||||
//create the blufi service to the service data base.
|
||||
if (p_data->reg_oper.uuid.uu.uuid16 == BLUFI_APP_UUID) {
|
||||
BLUFI_TRACE_DEBUG("%s %d\n", __func__, __LINE__);
|
||||
blufi_create_service();
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_DEREG_EVT: {
|
||||
esp_blufi_cb_param_t param;
|
||||
btc_msg_t msg;
|
||||
|
||||
BLUFI_TRACE_DEBUG("DEREG: status %d, gatt_if %d\n", p_data->reg_oper.status, p_data->reg_oper.server_if);
|
||||
|
||||
if (p_data->reg_oper.status != BTA_GATT_OK) {
|
||||
BLUFI_TRACE_ERROR("BLUFI profile unregister failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.enabled = false;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
|
||||
param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_READ_EVT:
|
||||
memset(&rsp, 0, sizeof(tBTA_GATTS_API_RSP));
|
||||
rsp.attr_value.handle = p_data->req_data.p_data->read_req.handle;
|
||||
rsp.attr_value.len = 1;
|
||||
rsp.attr_value.value[0] = 0x00;
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
p_data->req_data.status, &rsp);
|
||||
break;
|
||||
case BTA_GATTS_WRITE_EVT: {
|
||||
if (p_data->req_data.p_data->write_req.is_prep) {
|
||||
tBTA_GATT_STATUS status = GATT_SUCCESS;
|
||||
|
||||
if (blufi_env.prepare_buf == NULL) {
|
||||
blufi_env.prepare_buf = osi_malloc(BLUFI_PREPAIR_BUF_MAX_SIZE);
|
||||
blufi_env.prepare_len = 0;
|
||||
if (blufi_env.prepare_buf == NULL) {
|
||||
BLUFI_TRACE_ERROR("Blufi prep no mem\n");
|
||||
status = GATT_NO_RESOURCES;
|
||||
}
|
||||
} else {
|
||||
if (p_data->req_data.p_data->write_req.offset > BLUFI_PREPAIR_BUF_MAX_SIZE) {
|
||||
status = GATT_INVALID_OFFSET;
|
||||
} else if ((p_data->req_data.p_data->write_req.offset + p_data->req_data.p_data->write_req.len) > BLUFI_PREPAIR_BUF_MAX_SIZE) {
|
||||
status = GATT_INVALID_ATTR_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
memset(&rsp, 0, sizeof(tGATTS_RSP));
|
||||
rsp.attr_value.handle = p_data->req_data.p_data->write_req.handle;
|
||||
rsp.attr_value.len = p_data->req_data.p_data->write_req.len;
|
||||
rsp.attr_value.offset = p_data->req_data.p_data->write_req.offset;
|
||||
memcpy(rsp.attr_value.value, p_data->req_data.p_data->write_req.value, p_data->req_data.p_data->write_req.len);
|
||||
|
||||
BLUFI_TRACE_DEBUG("prep write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
|
||||
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
status, &rsp);
|
||||
|
||||
if (status != GATT_SUCCESS) {
|
||||
if (blufi_env.prepare_buf) {
|
||||
osi_free(blufi_env.prepare_buf);
|
||||
blufi_env.prepare_buf = NULL;
|
||||
blufi_env.prepare_len = 0;
|
||||
}
|
||||
BLUFI_TRACE_ERROR("write data error , error code 0x%x\n", status);
|
||||
return;
|
||||
}
|
||||
memcpy(blufi_env.prepare_buf + p_data->req_data.p_data->write_req.offset,
|
||||
p_data->req_data.p_data->write_req.value,
|
||||
p_data->req_data.p_data->write_req.len);
|
||||
blufi_env.prepare_len += p_data->req_data.p_data->write_req.len;
|
||||
|
||||
return;
|
||||
} else {
|
||||
BLUFI_TRACE_DEBUG("norm write, len=%d, offset=%d\n", p_data->req_data.p_data->write_req.len, p_data->req_data.p_data->write_req.offset);
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
p_data->req_data.status, NULL);
|
||||
}
|
||||
|
||||
if (p_data->req_data.p_data->write_req.handle == blufi_env.handle_char_p2e) {
|
||||
btc_blufi_recv_handler(&p_data->req_data.p_data->write_req.value[0],
|
||||
p_data->req_data.p_data->write_req.len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_EXEC_WRITE_EVT:
|
||||
BLUFI_TRACE_DEBUG("exec write exec %d\n", p_data->req_data.p_data->exec_write);
|
||||
|
||||
BTA_GATTS_SendRsp(p_data->req_data.conn_id, p_data->req_data.trans_id,
|
||||
GATT_SUCCESS, NULL);
|
||||
|
||||
if (blufi_env.prepare_buf && p_data->req_data.p_data->exec_write == GATT_PREP_WRITE_EXEC) {
|
||||
btc_blufi_recv_handler(blufi_env.prepare_buf, blufi_env.prepare_len);
|
||||
}
|
||||
|
||||
if (blufi_env.prepare_buf) {
|
||||
osi_free(blufi_env.prepare_buf);
|
||||
blufi_env.prepare_buf = NULL;
|
||||
blufi_env.prepare_len = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
case BTA_GATTS_MTU_EVT:
|
||||
BLUFI_TRACE_DEBUG("MTU size %d\n", p_data->req_data.p_data->mtu);
|
||||
blufi_env.frag_size = (p_data->req_data.p_data->mtu < BLUFI_MAX_DATA_LEN ? p_data->req_data.p_data->mtu : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
|
||||
break;
|
||||
case BTA_GATTS_CONF_EVT:
|
||||
BLUFI_TRACE_DEBUG("CONFIRM EVT\n");
|
||||
/* Nothing */
|
||||
break;
|
||||
case BTA_GATTS_CREATE_EVT:
|
||||
blufi_env.handle_srvc = p_data->create.service_id;
|
||||
|
||||
//add the frist blufi characteristic --> write characteristic
|
||||
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_p2e,
|
||||
(GATT_PERM_WRITE),
|
||||
(GATT_CHAR_PROP_BIT_WRITE),
|
||||
NULL, NULL);
|
||||
break;
|
||||
case BTA_GATTS_ADD_CHAR_EVT:
|
||||
switch (p_data->add_result.char_uuid.uu.uuid16) {
|
||||
case BLUFI_CHAR_P2E_UUID: /* Phone to ESP32 */
|
||||
blufi_env.handle_char_p2e = p_data->add_result.attr_id;
|
||||
|
||||
BTA_GATTS_AddCharacteristic(blufi_env.handle_srvc, &blufi_char_uuid_e2p,
|
||||
(GATT_PERM_READ),
|
||||
(GATT_CHAR_PROP_BIT_READ | GATT_CHAR_PROP_BIT_NOTIFY),
|
||||
NULL, NULL);
|
||||
break;
|
||||
case BLUFI_CHAR_E2P_UUID: /* ESP32 to Phone */
|
||||
blufi_env.handle_char_e2p = p_data->add_result.attr_id;
|
||||
|
||||
BTA_GATTS_AddCharDescriptor (blufi_env.handle_srvc,
|
||||
(GATT_PERM_READ | GATT_PERM_WRITE),
|
||||
&blufi_descr_uuid_e2p,
|
||||
NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BTA_GATTS_ADD_CHAR_DESCR_EVT: {
|
||||
/* call init finish */
|
||||
esp_blufi_cb_param_t param;
|
||||
btc_msg_t msg;
|
||||
|
||||
blufi_env.handle_descr_e2p = p_data->add_result.attr_id;
|
||||
//start the blufi service after created
|
||||
BTA_GATTS_StartService(blufi_env.handle_srvc, BTA_GATT_TRANSPORT_LE);
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_INIT_FINISH;
|
||||
param.init_finish.state = ESP_BLUFI_INIT_OK;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_CONNECT_EVT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
//set the connection flag to true
|
||||
BLUFI_TRACE_API("\ndevice is connected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
|
||||
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
|
||||
p_data->conn.reason, p_data->conn.conn_id);
|
||||
|
||||
memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
|
||||
blufi_env.conn_id = p_data->conn.conn_id;
|
||||
blufi_env.is_connected = true;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
|
||||
memcpy(param.connect.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
|
||||
param.connect.conn_id = BTC_GATT_GET_CONN_ID(p_data->conn.conn_id);
|
||||
conn_id = param.connect.conn_id;
|
||||
server_if = p_data->conn.server_if;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_DISCONNECT_EVT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
blufi_env.is_connected = false;
|
||||
//set the connection flag to true
|
||||
BLUFI_TRACE_API("\ndevice is disconnected "BT_BD_ADDR_STR", server_if=%d,reason=0x%x,connect_id=%d\n",
|
||||
BT_BD_ADDR_HEX(p_data->conn.remote_bda), p_data->conn.server_if,
|
||||
p_data->conn.reason, p_data->conn.conn_id);
|
||||
|
||||
memcpy(blufi_env.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
|
||||
blufi_env.conn_id = p_data->conn.conn_id;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.sec_mode = 0x0;
|
||||
blufi_env.offset = 0;
|
||||
|
||||
if (blufi_env.aggr_buf != NULL) {
|
||||
osi_free(blufi_env.aggr_buf);
|
||||
blufi_env.aggr_buf = NULL;
|
||||
}
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
|
||||
memcpy(param.disconnect.remote_bda, p_data->conn.remote_bda, ESP_BLUFI_BD_ADDR_LEN);
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
}
|
||||
case BTA_GATTS_OPEN_EVT:
|
||||
break;
|
||||
case BTA_GATTS_CLOSE_EVT:
|
||||
break;
|
||||
case BTA_GATTS_CONGEST_EVT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void esp_blufi_send_notify(void *arg)
|
||||
{
|
||||
struct pkt_info *pkts = (struct pkt_info *) arg;
|
||||
uint16_t conn_id = blufi_env.conn_id;
|
||||
uint16_t attr_id = blufi_env.handle_char_e2p;
|
||||
bool rsp = false;
|
||||
BTA_GATTS_HandleValueIndication(conn_id, attr_id, pkts->pkt_len,
|
||||
pkts->pkt, rsp);
|
||||
|
||||
}
|
||||
|
||||
void esp_blufi_deinit(void)
|
||||
{
|
||||
BTA_GATTS_StopService(blufi_env.handle_srvc);
|
||||
BTA_GATTS_DeleteService(blufi_env.handle_srvc);
|
||||
/* register the BLUFI profile to the BTA_GATTS module*/
|
||||
BTA_GATTS_AppDeregister(blufi_env.gatt_if);
|
||||
}
|
||||
|
||||
void esp_blufi_adv_start(void)
|
||||
{
|
||||
esp_ble_gap_set_device_name(BLUFI_DEVICE_NAME);
|
||||
esp_ble_gap_config_adv_data(&blufi_adv_data);
|
||||
}
|
||||
|
||||
void esp_blufi_adv_stop(void)
|
||||
{
|
||||
esp_ble_gap_stop_advertising();
|
||||
}
|
||||
|
||||
void esp_blufi_send_encap(void *arg)
|
||||
{
|
||||
struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
|
||||
retry:
|
||||
if (blufi_env.is_connected == false) {
|
||||
BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
|
||||
return;
|
||||
}
|
||||
if (esp_ble_get_cur_sendable_packets_num(BTC_GATT_GET_CONN_ID(blufi_env.conn_id)) > 0) {
|
||||
btc_blufi_send_notify((uint8_t *)hdr,
|
||||
((hdr->fc & BLUFI_FC_CHECK) ?
|
||||
hdr->data_len + sizeof(struct blufi_hdr) + 2 :
|
||||
hdr->data_len + sizeof(struct blufi_hdr)));
|
||||
} else {
|
||||
BTC_TRACE_WARNING("%s wait to send blufi custom data\n", __func__);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_blufi_close(esp_gatt_if_t gatts_if, uint16_t conn_id)
|
||||
{
|
||||
ESP_BLE_HOST_STATUS_CHECK(ESP_BLE_HOST_STATUS_ENABLED);
|
||||
btc_msg_t msg;
|
||||
btc_ble_gatts_args_t arg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_GATTS;
|
||||
msg.act = BTC_GATTS_ACT_CLOSE;
|
||||
arg.close.conn_id = BTC_GATT_CREATE_CONN_ID(gatts_if, conn_id);
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_ble_gatts_args_t), NULL, NULL)
|
||||
== BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
void esp_blufi_disconnect()
|
||||
{
|
||||
int rc;
|
||||
rc = esp_blufi_close(server_if, conn_id);
|
||||
assert (rc == 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,901 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
#include "osi/allocator.h"
|
||||
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_manage.h"
|
||||
|
||||
#include "blufi_int.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_blufi.h"
|
||||
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
#if GATT_DYNAMIC_MEMORY == FALSE
|
||||
tBLUFI_ENV blufi_env;
|
||||
#else
|
||||
tBLUFI_ENV *blufi_env_ptr;
|
||||
#endif
|
||||
|
||||
// static functions declare
|
||||
static void btc_blufi_send_ack(uint8_t seq);
|
||||
|
||||
inline void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
|
||||
{
|
||||
esp_blufi_event_cb_t btc_blufi_cb = (esp_blufi_event_cb_t)btc_profile_cb_get(BTC_PID_BLUFI);
|
||||
if (btc_blufi_cb) {
|
||||
btc_blufi_cb(event, param);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t btc_blufi_profile_init(void)
|
||||
{
|
||||
esp_blufi_callbacks_t *store_p = blufi_env.cbs;
|
||||
|
||||
uint8_t rc;
|
||||
if (blufi_env.enabled) {
|
||||
BLUFI_TRACE_ERROR("BLUFI already initialized");
|
||||
return ESP_BLUFI_ERROR;
|
||||
}
|
||||
|
||||
memset(&blufi_env, 0x0, sizeof(blufi_env));
|
||||
blufi_env.cbs = store_p; /* if set callback prior, restore the point */
|
||||
blufi_env.frag_size = BLUFI_FRAG_DATA_DEFAULT_LEN;
|
||||
rc = esp_blufi_init();
|
||||
if(rc != 0 ){
|
||||
return rc;
|
||||
}
|
||||
|
||||
return ESP_BLUFI_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t btc_blufi_profile_deinit(void)
|
||||
{
|
||||
if (!blufi_env.enabled) {
|
||||
BTC_TRACE_ERROR("BLUFI already de-initialized");
|
||||
return ESP_BLUFI_ERROR;
|
||||
}
|
||||
|
||||
esp_blufi_deinit();
|
||||
return ESP_BLUFI_SUCCESS;
|
||||
}
|
||||
|
||||
void btc_blufi_send_notify(uint8_t *pkt, int pkt_len)
|
||||
{
|
||||
struct pkt_info pkts;
|
||||
pkts.pkt = pkt;
|
||||
pkts.pkt_len = pkt_len;
|
||||
esp_blufi_send_notify(&pkts);
|
||||
}
|
||||
|
||||
void btc_blufi_report_error(esp_blufi_error_state_t state)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_REPORT_ERROR;
|
||||
esp_blufi_cb_param_t param;
|
||||
param.report_error.state = state;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
}
|
||||
|
||||
void btc_blufi_recv_handler(uint8_t *data, int len)
|
||||
{
|
||||
struct blufi_hdr *hdr = (struct blufi_hdr *)data;
|
||||
uint16_t checksum, checksum_pkt;
|
||||
int ret;
|
||||
|
||||
if (hdr->seq != blufi_env.recv_seq) {
|
||||
BTC_TRACE_ERROR("%s seq %d is not expect %d\n", __func__, hdr->seq, blufi_env.recv_seq + 1);
|
||||
btc_blufi_report_error(ESP_BLUFI_SEQUENCE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
blufi_env.recv_seq++;
|
||||
|
||||
// first step, decrypt
|
||||
if (BLUFI_FC_IS_ENC(hdr->fc)
|
||||
&& (blufi_env.cbs && blufi_env.cbs->decrypt_func)) {
|
||||
ret = blufi_env.cbs->decrypt_func(hdr->seq, hdr->data, hdr->data_len);
|
||||
if (ret != hdr->data_len) { /* enc must be success and enc len must equal to plain len */
|
||||
BTC_TRACE_ERROR("%s decrypt error %d\n", __func__, ret);
|
||||
btc_blufi_report_error(ESP_BLUFI_DECRYPT_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// second step, check sum
|
||||
if (BLUFI_FC_IS_CHECK(hdr->fc)
|
||||
&& (blufi_env.cbs && blufi_env.cbs->checksum_func)) {
|
||||
checksum = blufi_env.cbs->checksum_func(hdr->seq, &hdr->seq, hdr->data_len + 2);
|
||||
checksum_pkt = hdr->data[hdr->data_len] | (((uint16_t) hdr->data[hdr->data_len + 1]) << 8);
|
||||
if (checksum != checksum_pkt) {
|
||||
BTC_TRACE_ERROR("%s checksum error %04x, pkt %04x\n", __func__, checksum, checksum_pkt);
|
||||
btc_blufi_report_error(ESP_BLUFI_CHECKSUM_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (BLUFI_FC_IS_REQ_ACK(hdr->fc)) {
|
||||
btc_blufi_send_ack(hdr->seq);
|
||||
}
|
||||
|
||||
if (BLUFI_FC_IS_FRAG(hdr->fc)) {
|
||||
if (blufi_env.offset == 0) {
|
||||
/*
|
||||
blufi_env.aggr_buf should be NULL if blufi_env.offset is 0.
|
||||
It is possible that the process of sending fragment packet
|
||||
has not been completed
|
||||
*/
|
||||
if (blufi_env.aggr_buf) {
|
||||
BTC_TRACE_ERROR("%s msg error, blufi_env.aggr_buf is not freed\n", __func__);
|
||||
btc_blufi_report_error(ESP_BLUFI_MSG_STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
blufi_env.total_len = hdr->data[0] | (((uint16_t) hdr->data[1]) << 8);
|
||||
blufi_env.aggr_buf = osi_malloc(blufi_env.total_len);
|
||||
if (blufi_env.aggr_buf == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem, len %d\n", __func__, blufi_env.total_len);
|
||||
btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (blufi_env.offset + hdr->data_len - 2 <= blufi_env.total_len){
|
||||
memcpy(blufi_env.aggr_buf + blufi_env.offset, hdr->data + 2, hdr->data_len - 2);
|
||||
blufi_env.offset += (hdr->data_len - 2);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s payload is longer than packet length, len %d \n", __func__, blufi_env.total_len);
|
||||
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (blufi_env.offset > 0) { /* if previous pkt is frag */
|
||||
/* blufi_env.aggr_buf should not be NULL */
|
||||
if (blufi_env.aggr_buf == NULL) {
|
||||
BTC_TRACE_ERROR("%s buffer is NULL\n", __func__);
|
||||
btc_blufi_report_error(ESP_BLUFI_DH_MALLOC_ERROR);
|
||||
return;
|
||||
}
|
||||
/* payload length should be equal to total_len */
|
||||
if ((blufi_env.offset + hdr->data_len) != blufi_env.total_len) {
|
||||
BTC_TRACE_ERROR("%s payload is longer than packet length, len %d \n", __func__, blufi_env.total_len);
|
||||
btc_blufi_report_error(ESP_BLUFI_DATA_FORMAT_ERROR);
|
||||
return;
|
||||
}
|
||||
memcpy(blufi_env.aggr_buf + blufi_env.offset, hdr->data, hdr->data_len);
|
||||
|
||||
btc_blufi_protocol_handler(hdr->type, blufi_env.aggr_buf, blufi_env.total_len);
|
||||
blufi_env.offset = 0;
|
||||
osi_free(blufi_env.aggr_buf);
|
||||
blufi_env.aggr_buf = NULL;
|
||||
} else {
|
||||
btc_blufi_protocol_handler(hdr->type, hdr->data, hdr->data_len);
|
||||
blufi_env.offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
void btc_blufi_send_encap(uint8_t type, uint8_t *data, int total_data_len)
|
||||
{
|
||||
struct blufi_hdr *hdr = NULL;
|
||||
int remain_len = total_data_len;
|
||||
uint16_t checksum;
|
||||
int ret;
|
||||
|
||||
if (blufi_env.is_connected == false) {
|
||||
BTC_TRACE_ERROR("blufi connection has been disconnected \n");
|
||||
return;
|
||||
}
|
||||
|
||||
while (remain_len > 0) {
|
||||
if (remain_len > blufi_env.frag_size) {
|
||||
hdr = osi_malloc(sizeof(struct blufi_hdr) + 2 + blufi_env.frag_size + 2);
|
||||
if (hdr == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem\n", __func__);
|
||||
return;
|
||||
}
|
||||
hdr->fc = 0x0;
|
||||
hdr->data_len = blufi_env.frag_size + 2;
|
||||
hdr->data[0] = remain_len & 0xff;
|
||||
hdr->data[1] = (remain_len >> 8) & 0xff;
|
||||
memcpy(hdr->data + 2, &data[total_data_len - remain_len], blufi_env.frag_size); //copy first, easy for check sum
|
||||
hdr->fc |= BLUFI_FC_FRAG;
|
||||
} else {
|
||||
hdr = osi_malloc(sizeof(struct blufi_hdr) + remain_len + 2);
|
||||
if (hdr == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem\n", __func__);
|
||||
return;
|
||||
}
|
||||
hdr->fc = 0x0;
|
||||
hdr->data_len = remain_len;
|
||||
memcpy(hdr->data, &data[total_data_len - remain_len], hdr->data_len); //copy first, easy for check sum
|
||||
}
|
||||
|
||||
hdr->type = type;
|
||||
hdr->fc |= BLUFI_FC_DIR_E2P;
|
||||
hdr->seq = blufi_env.send_seq++;
|
||||
|
||||
if (BLUFI_TYPE_IS_CTRL(hdr->type)) {
|
||||
if ((blufi_env.sec_mode & BLUFI_CTRL_SEC_MODE_CHECK_MASK)
|
||||
&& (blufi_env.cbs && blufi_env.cbs->checksum_func)) {
|
||||
hdr->fc |= BLUFI_FC_CHECK;
|
||||
checksum = blufi_env.cbs->checksum_func(hdr->seq, &hdr->seq, hdr->data_len + 2);
|
||||
memcpy(&hdr->data[hdr->data_len], &checksum, 2);
|
||||
}
|
||||
} else if (!BLUFI_TYPE_IS_DATA_NEG(hdr->type) && !BLUFI_TYPE_IS_DATA_ERROR_INFO(hdr->type)) {
|
||||
if ((blufi_env.sec_mode & BLUFI_DATA_SEC_MODE_CHECK_MASK)
|
||||
&& (blufi_env.cbs && blufi_env.cbs->checksum_func)) {
|
||||
hdr->fc |= BLUFI_FC_CHECK;
|
||||
checksum = blufi_env.cbs->checksum_func(hdr->seq, &hdr->seq, hdr->data_len + 2);
|
||||
memcpy(&hdr->data[hdr->data_len], &checksum, 2);
|
||||
}
|
||||
|
||||
if ((blufi_env.sec_mode & BLUFI_DATA_SEC_MODE_ENC_MASK)
|
||||
&& (blufi_env.cbs && blufi_env.cbs->encrypt_func)) {
|
||||
ret = blufi_env.cbs->encrypt_func(hdr->seq, hdr->data, hdr->data_len);
|
||||
if (ret == hdr->data_len) { /* enc must be success and enc len must equal to plain len */
|
||||
hdr->fc |= BLUFI_FC_ENC;
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s encrypt error %d\n", __func__, ret);
|
||||
btc_blufi_report_error(ESP_BLUFI_ENCRYPT_ERROR);
|
||||
osi_free(hdr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hdr->fc & BLUFI_FC_FRAG) {
|
||||
remain_len -= (hdr->data_len - 2);
|
||||
} else {
|
||||
remain_len -= hdr->data_len;
|
||||
}
|
||||
|
||||
esp_blufi_send_encap(hdr);
|
||||
|
||||
osi_free(hdr);
|
||||
hdr = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_blufi_wifi_conn_report(uint8_t opmode, uint8_t sta_conn_state, uint8_t softap_conn_num, esp_blufi_extra_info_t *info, int info_len)
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t *data;
|
||||
int data_len;
|
||||
uint8_t *p;
|
||||
|
||||
data_len = info_len + 3;
|
||||
p = data = osi_malloc(data_len);
|
||||
if (data == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
type = BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_WIFI_REP);
|
||||
*p++ = opmode;
|
||||
*p++ = sta_conn_state;
|
||||
*p++ = softap_conn_num;
|
||||
|
||||
if (info) {
|
||||
if (info->sta_bssid_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID;
|
||||
*p++ = 6;
|
||||
memcpy(p, info->sta_bssid, 6);
|
||||
p += 6;
|
||||
}
|
||||
if (info->sta_ssid) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_SSID;
|
||||
*p++ = info->sta_ssid_len;
|
||||
memcpy(p, info->sta_ssid, info->sta_ssid_len);
|
||||
p += info->sta_ssid_len;
|
||||
}
|
||||
if (info->sta_passwd) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD;
|
||||
*p++ = info->sta_passwd_len;
|
||||
memcpy(p, info->sta_passwd, info->sta_passwd_len);
|
||||
p += info->sta_passwd_len;
|
||||
}
|
||||
if (info->softap_ssid) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID;
|
||||
*p++ = info->softap_ssid_len;
|
||||
memcpy(p, info->softap_ssid, info->softap_ssid_len);
|
||||
p += info->softap_ssid_len;
|
||||
}
|
||||
if (info->softap_passwd) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD;
|
||||
*p++ = info->softap_passwd_len;
|
||||
memcpy(p, info->softap_passwd, info->softap_passwd_len);
|
||||
p += info->softap_passwd_len;
|
||||
}
|
||||
if (info->softap_authmode_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE;
|
||||
*p++ = 1;
|
||||
*p++ = info->softap_authmode;
|
||||
}
|
||||
if (info->softap_max_conn_num_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM;
|
||||
*p++ = 1;
|
||||
*p++ = info->softap_max_conn_num;
|
||||
}
|
||||
if (info->softap_channel_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL;
|
||||
*p++ = 1;
|
||||
*p++ = info->softap_channel;
|
||||
}
|
||||
if (info->sta_max_conn_retry_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_MAX_CONN_RETRY;
|
||||
*p++ = 1;
|
||||
*p++ = info->sta_max_conn_retry;
|
||||
}
|
||||
if (info->sta_conn_end_reason_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_END_REASON;
|
||||
*p++ = 1;
|
||||
*p++ = info->sta_conn_end_reason;
|
||||
}
|
||||
if (info->sta_conn_rssi_set) {
|
||||
*p++ = BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_RSSI;
|
||||
*p++ = 1;
|
||||
*p++ = info->sta_conn_rssi;
|
||||
}
|
||||
}
|
||||
if (p - data > data_len) {
|
||||
BTC_TRACE_ERROR("%s len error %d %d\n", __func__, (int)(p - data), data_len);
|
||||
}
|
||||
|
||||
btc_blufi_send_encap(type, data, data_len);
|
||||
osi_free(data);
|
||||
}
|
||||
|
||||
void btc_blufi_send_wifi_list(uint16_t apCount, esp_blufi_ap_record_t *list)
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t *data;
|
||||
int data_len;
|
||||
uint8_t *p;
|
||||
// malloc size: (len + RSSI + ssid buffer) * apCount;
|
||||
uint32_t malloc_size = (1 + 1 + sizeof(list->ssid)) * apCount;
|
||||
p = data = osi_malloc(malloc_size);
|
||||
if (data == NULL) {
|
||||
BTC_TRACE_ERROR("malloc error\n");
|
||||
return;
|
||||
}
|
||||
type = BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_WIFI_LIST);
|
||||
for (int i = 0; i < apCount; ++i)
|
||||
{
|
||||
uint32_t len = strlen((const char *)list[i].ssid);
|
||||
data_len = (p - data);
|
||||
//current_len + ssid + rssi + total_len_value
|
||||
if((data_len + len + 1 + 1) > malloc_size) {
|
||||
BTC_TRACE_ERROR("%s len error", __func__);
|
||||
osi_free(data);
|
||||
return;
|
||||
}
|
||||
*p++ = len + 1; // length of ssid + rssi
|
||||
*p++ = list[i].rssi;
|
||||
memcpy(p, list[i].ssid, len);
|
||||
p = p + len;
|
||||
}
|
||||
data_len = (p - data);
|
||||
btc_blufi_send_encap(type, data, data_len);
|
||||
osi_free(data);
|
||||
}
|
||||
|
||||
static void btc_blufi_send_ack(uint8_t seq)
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t data;
|
||||
|
||||
type = BLUFI_BUILD_TYPE(BLUFI_TYPE_CTRL, BLUFI_TYPE_CTRL_SUBTYPE_ACK);
|
||||
data = seq;
|
||||
|
||||
btc_blufi_send_encap(type, &data, 1);
|
||||
}
|
||||
static void btc_blufi_send_error_info(uint8_t state)
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t *data;
|
||||
int data_len;
|
||||
uint8_t *p;
|
||||
|
||||
data_len = 1;
|
||||
p = data = osi_malloc(data_len);
|
||||
if (data == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
type = BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_ERROR_INFO);
|
||||
*p++ = state;
|
||||
if (p - data > data_len) {
|
||||
BTC_TRACE_ERROR("%s len error %d %d\n", __func__, (int)(p - data), data_len);
|
||||
}
|
||||
|
||||
btc_blufi_send_encap(type, data, data_len);
|
||||
osi_free(data);
|
||||
}
|
||||
|
||||
static void btc_blufi_send_custom_data(uint8_t *value, uint32_t value_len)
|
||||
{
|
||||
if(value == NULL || value_len == 0) {
|
||||
BTC_TRACE_ERROR("%s value or value len error", __func__);
|
||||
return;
|
||||
}
|
||||
uint8_t *data = osi_malloc(value_len);
|
||||
if (data == NULL) {
|
||||
BTC_TRACE_ERROR("%s mem malloc error", __func__);
|
||||
return;
|
||||
}
|
||||
uint8_t type = BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_CUSTOM_DATA);
|
||||
memcpy(data, value, value_len);
|
||||
btc_blufi_send_encap(type, data, value_len);
|
||||
osi_free(data);
|
||||
}
|
||||
|
||||
void btc_blufi_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
{
|
||||
esp_blufi_cb_param_t *dst = (esp_blufi_cb_param_t *) p_dest;
|
||||
esp_blufi_cb_param_t *src = (esp_blufi_cb_param_t *) p_src;
|
||||
|
||||
switch (msg->act) {
|
||||
case ESP_BLUFI_EVENT_RECV_STA_SSID:
|
||||
dst->sta_ssid.ssid = osi_malloc(src->sta_ssid.ssid_len);
|
||||
if (dst->sta_ssid.ssid == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->sta_ssid.ssid, src->sta_ssid.ssid, src->sta_ssid.ssid_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
|
||||
dst->sta_passwd.passwd = osi_malloc(src->sta_passwd.passwd_len);
|
||||
if (dst->sta_passwd.passwd == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->sta_passwd.passwd, src->sta_passwd.passwd, src->sta_passwd.passwd_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
|
||||
dst->softap_ssid.ssid = osi_malloc(src->softap_ssid.ssid_len);
|
||||
if (dst->softap_ssid.ssid == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->softap_ssid.ssid, src->softap_ssid.ssid, src->softap_ssid.ssid_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
|
||||
dst->softap_passwd.passwd = osi_malloc(src->softap_passwd.passwd_len);
|
||||
if (dst->softap_passwd.passwd == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->softap_passwd.passwd, src->softap_passwd.passwd, src->softap_passwd.passwd_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_USERNAME:
|
||||
dst->username.name = osi_malloc(src->username.name_len);
|
||||
if (dst->username.name == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->username.name, src->username.name, src->username.name_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CA_CERT:
|
||||
dst->ca.cert = osi_malloc(src->ca.cert_len);
|
||||
if (dst->ca.cert == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->ca.cert, src->ca.cert, src->ca.cert_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
|
||||
dst->client_cert.cert = osi_malloc(src->client_cert.cert_len);
|
||||
if (dst->client_cert.cert == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->client_cert.cert, src->client_cert.cert, src->client_cert.cert_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
|
||||
dst->server_cert.cert = osi_malloc(src->server_cert.cert_len);
|
||||
if (dst->server_cert.cert == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->server_cert.cert, src->server_cert.cert, src->server_cert.cert_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
|
||||
dst->client_pkey.pkey = osi_malloc(src->client_pkey.pkey_len);
|
||||
if (dst->client_pkey.pkey == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->client_pkey.pkey, src->client_pkey.pkey, src->client_pkey.pkey_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
|
||||
dst->server_pkey.pkey = osi_malloc(src->server_pkey.pkey_len);
|
||||
if (dst->server_pkey.pkey == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
}
|
||||
memcpy(dst->server_pkey.pkey, src->server_pkey.pkey, src->server_pkey.pkey_len);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
|
||||
dst->custom_data.data = osi_malloc(src->custom_data.data_len);
|
||||
if (dst->custom_data.data == NULL) {
|
||||
BTC_TRACE_ERROR("%s %d no mem\n", __func__, msg->act);
|
||||
break;
|
||||
}
|
||||
memcpy(dst->custom_data.data, src->custom_data.data, src->custom_data.data_len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_blufi_cb_deep_free(btc_msg_t *msg)
|
||||
{
|
||||
esp_blufi_cb_param_t *param = (esp_blufi_cb_param_t *)msg->arg;
|
||||
|
||||
switch (msg->act) {
|
||||
case ESP_BLUFI_EVENT_RECV_STA_SSID:
|
||||
osi_free(param->sta_ssid.ssid);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
|
||||
osi_free(param->sta_passwd.passwd);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
|
||||
osi_free(param->softap_ssid.ssid);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
|
||||
osi_free(param->softap_passwd.passwd);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_USERNAME:
|
||||
osi_free(param->username.name);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CA_CERT:
|
||||
osi_free(param->ca.cert);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
|
||||
osi_free(param->client_cert.cert);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
|
||||
osi_free(param->server_cert.cert);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
|
||||
osi_free(param->client_pkey.pkey);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
|
||||
osi_free(param->server_pkey.pkey);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
|
||||
osi_free(param->custom_data.data);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_blufi_cb_handler(btc_msg_t *msg)
|
||||
{
|
||||
esp_blufi_cb_param_t *param = (esp_blufi_cb_param_t *)msg->arg;
|
||||
|
||||
switch (msg->act) {
|
||||
case ESP_BLUFI_EVENT_INIT_FINISH: {
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_INIT_FINISH, param);
|
||||
break;
|
||||
}
|
||||
case ESP_BLUFI_EVENT_DEINIT_FINISH: {
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_DEINIT_FINISH, param);
|
||||
break;
|
||||
}
|
||||
case ESP_BLUFI_EVENT_BLE_CONNECT:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_BLE_CONNECT, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_BLE_DISCONNECT, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_SET_WIFI_OPMODE, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP, NULL);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP, NULL);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_GET_WIFI_STATUS:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_GET_WIFI_STATUS, NULL);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_GET_WIFI_LIST:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_GET_WIFI_LIST, NULL);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_DEAUTHENTICATE_STA, NULL);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_STA_BSSID:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_STA_BSSID, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_STA_SSID:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_STA_SSID, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_STA_PASSWD, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SOFTAP_SSID, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_USERNAME:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_USERNAME, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CA_CERT:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_CA_CERT, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_CLIENT_CERT, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SERVER_CERT, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_REPORT_ERROR:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_REPORT_ERROR, param);
|
||||
break;
|
||||
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_RECV_CUSTOM_DATA, param);
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_ERROR("%s UNKNOWN %d\n", __func__, msg->act);
|
||||
break;
|
||||
}
|
||||
|
||||
btc_blufi_cb_deep_free(msg);
|
||||
}
|
||||
|
||||
void btc_blufi_call_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src)
|
||||
{
|
||||
btc_blufi_args_t *dst = (btc_blufi_args_t *) p_dest;
|
||||
btc_blufi_args_t *src = (btc_blufi_args_t *) p_src;
|
||||
|
||||
switch (msg->act) {
|
||||
case BTC_BLUFI_ACT_SEND_CFG_REPORT: {
|
||||
esp_blufi_extra_info_t *src_info = src->wifi_conn_report.extra_info;
|
||||
dst->wifi_conn_report.extra_info_len = 0;
|
||||
dst->wifi_conn_report.extra_info = NULL;
|
||||
|
||||
if (src_info == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
dst->wifi_conn_report.extra_info = osi_calloc(sizeof(esp_blufi_extra_info_t));
|
||||
if (dst->wifi_conn_report.extra_info == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem line %d\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (src_info->sta_bssid_set) {
|
||||
memcpy(dst->wifi_conn_report.extra_info->sta_bssid, src_info->sta_bssid, 6);
|
||||
dst->wifi_conn_report.extra_info->sta_bssid_set = src_info->sta_bssid_set;
|
||||
dst->wifi_conn_report.extra_info_len += (6 + 2);
|
||||
}
|
||||
if (src_info->sta_ssid) {
|
||||
dst->wifi_conn_report.extra_info->sta_ssid = osi_malloc(src_info->sta_ssid_len);
|
||||
if (dst->wifi_conn_report.extra_info->sta_ssid) {
|
||||
memcpy(dst->wifi_conn_report.extra_info->sta_ssid, src_info->sta_ssid, src_info->sta_ssid_len);
|
||||
dst->wifi_conn_report.extra_info->sta_ssid_len = src_info->sta_ssid_len;
|
||||
dst->wifi_conn_report.extra_info_len += (dst->wifi_conn_report.extra_info->sta_ssid_len + 2);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s no mem line %d\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (src_info->sta_passwd) {
|
||||
dst->wifi_conn_report.extra_info->sta_passwd = osi_malloc(src_info->sta_passwd_len);
|
||||
if (dst->wifi_conn_report.extra_info->sta_passwd) {
|
||||
memcpy(dst->wifi_conn_report.extra_info->sta_passwd, src_info->sta_passwd, src_info->sta_passwd_len);
|
||||
dst->wifi_conn_report.extra_info->sta_passwd_len = src_info->sta_passwd_len;
|
||||
dst->wifi_conn_report.extra_info_len += (dst->wifi_conn_report.extra_info->sta_passwd_len + 2);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s no mem line %d\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (src_info->softap_ssid) {
|
||||
dst->wifi_conn_report.extra_info->softap_ssid = osi_malloc(src_info->softap_ssid_len);
|
||||
if (dst->wifi_conn_report.extra_info->softap_ssid) {
|
||||
memcpy(dst->wifi_conn_report.extra_info->softap_ssid, src_info->softap_ssid, src_info->softap_ssid_len);
|
||||
dst->wifi_conn_report.extra_info->softap_ssid_len = src_info->softap_ssid_len;
|
||||
dst->wifi_conn_report.extra_info_len += (dst->wifi_conn_report.extra_info->softap_ssid_len + 2);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s no mem line %d\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (src_info->softap_passwd) {
|
||||
dst->wifi_conn_report.extra_info->softap_passwd = osi_malloc(src_info->softap_passwd_len);
|
||||
if (dst->wifi_conn_report.extra_info->softap_passwd) {
|
||||
memcpy(dst->wifi_conn_report.extra_info->softap_passwd, src_info->softap_passwd, src_info->softap_passwd_len);
|
||||
dst->wifi_conn_report.extra_info->softap_passwd_len = src_info->softap_passwd_len;
|
||||
dst->wifi_conn_report.extra_info_len += (dst->wifi_conn_report.extra_info->softap_passwd_len + 2);
|
||||
} else {
|
||||
BTC_TRACE_ERROR("%s no mem line %d\n", __func__, __LINE__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (src_info->softap_authmode_set) {
|
||||
dst->wifi_conn_report.extra_info->softap_authmode_set = src_info->softap_authmode_set;
|
||||
dst->wifi_conn_report.extra_info->softap_authmode = src_info->softap_authmode;
|
||||
dst->wifi_conn_report.extra_info_len += (1 + 2);
|
||||
}
|
||||
if (src_info->softap_max_conn_num_set) {
|
||||
dst->wifi_conn_report.extra_info->softap_max_conn_num_set = src_info->softap_max_conn_num_set;
|
||||
dst->wifi_conn_report.extra_info->softap_max_conn_num = src_info->softap_max_conn_num;
|
||||
dst->wifi_conn_report.extra_info_len += (1 + 2);
|
||||
}
|
||||
if (src_info->softap_channel_set) {
|
||||
dst->wifi_conn_report.extra_info->softap_channel_set = src_info->softap_channel_set;
|
||||
dst->wifi_conn_report.extra_info->softap_channel = src_info->softap_channel;
|
||||
dst->wifi_conn_report.extra_info_len += (1 + 2);
|
||||
}
|
||||
if (src_info->sta_max_conn_retry_set) {
|
||||
dst->wifi_conn_report.extra_info->sta_max_conn_retry_set = src_info->sta_max_conn_retry_set;
|
||||
dst->wifi_conn_report.extra_info->sta_max_conn_retry = src_info->sta_max_conn_retry;
|
||||
dst->wifi_conn_report.extra_info_len += (1 + 2);
|
||||
}
|
||||
if (src_info->sta_conn_end_reason_set) {
|
||||
dst->wifi_conn_report.extra_info->sta_conn_end_reason_set = src_info->sta_conn_end_reason_set;
|
||||
dst->wifi_conn_report.extra_info->sta_conn_end_reason = src_info->sta_conn_end_reason;
|
||||
dst->wifi_conn_report.extra_info_len += (1 + 2);
|
||||
}
|
||||
if (src_info->sta_conn_rssi_set) {
|
||||
dst->wifi_conn_report.extra_info->sta_conn_rssi_set = src_info->sta_conn_rssi_set;
|
||||
dst->wifi_conn_report.extra_info->sta_conn_rssi = src_info->sta_conn_rssi;
|
||||
dst->wifi_conn_report.extra_info_len += (1 + 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_BLUFI_ACT_SEND_WIFI_LIST:{
|
||||
esp_blufi_ap_record_t *list = src->wifi_list.list;
|
||||
src->wifi_list.list = NULL;
|
||||
if (list == NULL || src->wifi_list.apCount <= 0) {
|
||||
break;
|
||||
}
|
||||
dst->wifi_list.list = (esp_blufi_ap_record_t *)osi_malloc(sizeof(esp_blufi_ap_record_t) * src->wifi_list.apCount);
|
||||
if (dst->wifi_list.list == NULL) {
|
||||
BTC_TRACE_ERROR("%s no mem line %d\n", __func__, __LINE__);
|
||||
break;
|
||||
}
|
||||
memcpy(dst->wifi_list.list, list, sizeof(esp_blufi_ap_record_t) * src->wifi_list.apCount);
|
||||
break;
|
||||
}
|
||||
case BTC_BLUFI_ACT_SEND_CUSTOM_DATA:{
|
||||
uint8_t *data = src->custom_data.data;
|
||||
if(data == NULL) {
|
||||
BTC_TRACE_ERROR("custom data is NULL\n");
|
||||
break;
|
||||
}
|
||||
dst->custom_data.data = osi_malloc(src->custom_data.data_len);
|
||||
if(dst->custom_data.data == NULL) {
|
||||
BTC_TRACE_ERROR("custom data malloc error\n");
|
||||
break;
|
||||
}
|
||||
memcpy(dst->custom_data.data, src->custom_data.data, src->custom_data.data_len);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_blufi_call_deep_free(btc_msg_t *msg)
|
||||
{
|
||||
btc_blufi_args_t *arg = (btc_blufi_args_t *)msg->arg;
|
||||
|
||||
switch (msg->act) {
|
||||
case BTC_BLUFI_ACT_SEND_CFG_REPORT: {
|
||||
esp_blufi_extra_info_t *info = (esp_blufi_extra_info_t *)arg->wifi_conn_report.extra_info;
|
||||
|
||||
if (info == NULL) {
|
||||
return;
|
||||
}
|
||||
if (info->sta_ssid) {
|
||||
osi_free(info->sta_ssid);
|
||||
}
|
||||
if (info->sta_passwd) {
|
||||
osi_free(info->sta_passwd);
|
||||
}
|
||||
if (info->softap_ssid) {
|
||||
osi_free(info->softap_ssid);
|
||||
}
|
||||
if (info->softap_passwd) {
|
||||
osi_free(info->softap_passwd);
|
||||
}
|
||||
osi_free(info);
|
||||
break;
|
||||
}
|
||||
case BTC_BLUFI_ACT_SEND_WIFI_LIST:{
|
||||
esp_blufi_ap_record_t *list = (esp_blufi_ap_record_t *)arg->wifi_list.list;
|
||||
if (list){
|
||||
osi_free(list);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BTC_BLUFI_ACT_SEND_CUSTOM_DATA:{
|
||||
uint8_t *data = arg->custom_data.data;
|
||||
if(data) {
|
||||
osi_free(data);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btc_blufi_call_handler(btc_msg_t *msg)
|
||||
{
|
||||
btc_blufi_args_t *arg = (btc_blufi_args_t *)msg->arg;
|
||||
|
||||
switch (msg->act) {
|
||||
case BTC_BLUFI_ACT_INIT:
|
||||
btc_blufi_profile_init();
|
||||
break;
|
||||
case BTC_BLUFI_ACT_DEINIT:
|
||||
btc_blufi_profile_deinit();
|
||||
break;
|
||||
case BTC_BLUFI_ACT_SEND_CFG_REPORT:
|
||||
btc_blufi_wifi_conn_report(arg->wifi_conn_report.opmode,
|
||||
arg->wifi_conn_report.sta_conn_state,
|
||||
arg->wifi_conn_report.softap_conn_num,
|
||||
arg->wifi_conn_report.extra_info,
|
||||
arg->wifi_conn_report.extra_info_len);
|
||||
break;
|
||||
case BTC_BLUFI_ACT_SEND_WIFI_LIST:{
|
||||
btc_blufi_send_wifi_list(arg->wifi_list.apCount, arg->wifi_list.list);
|
||||
break;
|
||||
}
|
||||
case BTC_BLUFI_ACT_SEND_ERR_INFO:
|
||||
btc_blufi_send_error_info(arg->blufi_err_infor.state);
|
||||
break;
|
||||
case BTC_BLUFI_ACT_SEND_CUSTOM_DATA:
|
||||
btc_blufi_send_custom_data(arg->custom_data.data, arg->custom_data.data_len);
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_ERROR("%s UNKNOWN %d\n", __func__, msg->act);
|
||||
break;
|
||||
}
|
||||
btc_blufi_call_deep_free(msg);
|
||||
}
|
||||
|
||||
void btc_blufi_set_callbacks(esp_blufi_callbacks_t *callbacks)
|
||||
{
|
||||
blufi_env.cbs = callbacks;
|
||||
}
|
||||
|
||||
uint16_t btc_blufi_get_version(void)
|
||||
{
|
||||
return BTC_BLUFI_VERSION;
|
||||
}
|
||||
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_manage.h"
|
||||
|
||||
#include "blufi_int.h"
|
||||
|
||||
//#include "esp_wifi.h"
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len)
|
||||
{
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
uint8_t *output_data = NULL;
|
||||
int output_len = 0;
|
||||
bool need_free = false;
|
||||
|
||||
switch (BLUFI_GET_TYPE(type)) {
|
||||
case BLUFI_TYPE_CTRL:
|
||||
switch (BLUFI_GET_SUBTYPE(type)) {
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_ACK:
|
||||
/* TODO: check sequence */
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_SET_SEC_MODE:
|
||||
blufi_env.sec_mode = data[0];
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_SET_WIFI_OPMODE:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_SET_WIFI_OPMODE;
|
||||
param.wifi_mode.op_mode = data[0];
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_CONN_TO_AP:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP;
|
||||
|
||||
btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_DISCONN_FROM_AP:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP;
|
||||
|
||||
btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_STATUS:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_GET_WIFI_STATUS;
|
||||
|
||||
btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_DEAUTHENTICATE_STA:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_DEAUTHENTICATE_STA;
|
||||
|
||||
btc_transfer_context(&msg, NULL, 0, NULL,NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_GET_VERSION: {
|
||||
uint8_t type = BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_REPLY_VERSION);
|
||||
uint8_t data[2];
|
||||
|
||||
data[0] = BTC_BLUFI_GREAT_VER;
|
||||
data[1] = BTC_BLUFI_SUB_VER;
|
||||
btc_blufi_send_encap(type, &data[0], sizeof(data));
|
||||
break;
|
||||
}
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_DISCONNECT_BLE:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE;
|
||||
btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_LIST:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_GET_WIFI_LIST;
|
||||
btc_transfer_context(&msg, NULL, 0, NULL, NULL);
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_ERROR("%s Unkown Ctrl pkt %02x\n", __func__, type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case BLUFI_TYPE_DATA:
|
||||
switch (BLUFI_GET_SUBTYPE(type)) {
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_NEG:
|
||||
if (blufi_env.cbs && blufi_env.cbs->negotiate_data_handler) {
|
||||
blufi_env.cbs->negotiate_data_handler(data, len, &output_data, &output_len, &need_free);
|
||||
}
|
||||
|
||||
if (output_data && output_len > 0) {
|
||||
btc_blufi_send_encap(BLUFI_BUILD_TYPE(BLUFI_TYPE_DATA, BLUFI_TYPE_DATA_SUBTYPE_NEG),
|
||||
output_data, output_len);
|
||||
}
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_STA_BSSID;
|
||||
memcpy(param.sta_bssid.bssid, &data[0], 6);
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_STA_SSID:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_STA_SSID;
|
||||
param.sta_ssid.ssid = &data[0];
|
||||
param.sta_ssid.ssid_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_STA_PASSWD;
|
||||
param.sta_passwd.passwd = &data[0];
|
||||
param.sta_passwd.passwd_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_SSID;
|
||||
param.softap_ssid.ssid = &data[0];
|
||||
param.softap_ssid.ssid_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD;
|
||||
param.softap_passwd.passwd = &data[0];
|
||||
param.softap_passwd.passwd_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM;
|
||||
param.softap_max_conn_num.max_conn_num = data[0];
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE;
|
||||
param.softap_auth_mode.auth_mode = data[0];
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL;
|
||||
param.softap_channel.channel = data[0];
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_USERNAME:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_USERNAME;
|
||||
param.username.name = &data[0];
|
||||
param.username.name_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_CA:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_CA_CERT;
|
||||
param.ca.cert = &data[0];
|
||||
param.ca.cert_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_CLIENT_CERT:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_CLIENT_CERT;
|
||||
param.client_cert.cert = &data[0];
|
||||
param.client_cert.cert_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SERVER_CERT:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SERVER_CERT;
|
||||
param.client_cert.cert = &data[0];
|
||||
param.client_cert.cert_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_CLIENT_PRIV_KEY:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY;
|
||||
param.client_pkey.pkey = &data[0];
|
||||
param.client_pkey.pkey_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_SERVER_PRIV_KEY:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY;
|
||||
param.client_pkey.pkey = &data[0];
|
||||
param.client_pkey.pkey_len = len;
|
||||
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
case BLUFI_TYPE_DATA_SUBTYPE_CUSTOM_DATA:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_RECV_CUSTOM_DATA;
|
||||
param.custom_data.data = &data[0];
|
||||
param.custom_data.data_len = len;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), btc_blufi_cb_deep_copy, btc_blufi_cb_deep_free);
|
||||
break;
|
||||
default:
|
||||
BTC_TRACE_ERROR("%s Unkown Ctrl pkt %02x\n", __func__, type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
@@ -0,0 +1,197 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BLUFI_INT_H__
|
||||
#define __BLUFI_INT_H__
|
||||
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
#define BTC_BLUFI_GREAT_VER 0x01 //Version + Subversion
|
||||
#define BTC_BLUFI_SUB_VER 0x03 //Version + Subversion
|
||||
#define BTC_BLUFI_VERSION ((BTC_BLUFI_GREAT_VER<<8)|BTC_BLUFI_SUB_VER) //Version + Subversion
|
||||
|
||||
typedef UINT8 tGATT_IF;
|
||||
/* service engine control block */
|
||||
typedef struct {
|
||||
/* Protocol reference */
|
||||
tGATT_IF gatt_if;
|
||||
UINT8 srvc_inst;
|
||||
UINT16 handle_srvc;
|
||||
UINT16 handle_char_p2e;
|
||||
UINT16 handle_char_e2p;
|
||||
UINT16 handle_descr_e2p;
|
||||
UINT16 conn_id;
|
||||
BOOLEAN is_connected;
|
||||
BD_ADDR remote_bda;
|
||||
UINT32 trans_id;
|
||||
UINT8 congest;
|
||||
UINT16 frag_size;
|
||||
#define BLUFI_PREPAIR_BUF_MAX_SIZE 1024
|
||||
uint8_t *prepare_buf;
|
||||
int prepare_len;
|
||||
/* Control reference */
|
||||
esp_blufi_callbacks_t *cbs;
|
||||
BOOLEAN enabled;
|
||||
uint8_t send_seq;
|
||||
uint8_t recv_seq;
|
||||
uint8_t sec_mode;
|
||||
uint8_t *aggr_buf;
|
||||
uint16_t total_len;
|
||||
uint16_t offset;
|
||||
} tBLUFI_ENV;
|
||||
|
||||
/* BLUFI protocol */
|
||||
struct blufi_hdr{
|
||||
uint8_t type;
|
||||
uint8_t fc;
|
||||
uint8_t seq;
|
||||
uint8_t data_len;
|
||||
uint8_t data[0];
|
||||
};
|
||||
typedef struct blufi_hdr blufi_hd_t;
|
||||
|
||||
struct blufi_frag_hdr {
|
||||
uint8_t type;
|
||||
uint8_t fc;
|
||||
uint8_t seq;
|
||||
uint8_t data_len;
|
||||
uint16_t total_len;
|
||||
uint8_t content[0];
|
||||
};
|
||||
typedef struct blufi_frag_hdr blufi_frag_hdr_t;
|
||||
|
||||
#if GATT_DYNAMIC_MEMORY == FALSE
|
||||
extern tBLUFI_ENV blufi_env;
|
||||
#else
|
||||
extern tBLUFI_ENV *blufi_env_ptr;
|
||||
#define blufi_env (*blufi_env_ptr)
|
||||
#endif
|
||||
|
||||
#define BLUFI_DATA_SEC_MODE_CHECK_MASK 0x01
|
||||
#define BLUFI_DATA_SEC_MODE_ENC_MASK 0x02
|
||||
#define BLUFI_CTRL_SEC_MODE_CHECK_MASK 0x10
|
||||
#define BLUFI_CTRL_SEC_MODE_ENC_MASK 0x20
|
||||
#define BLUFI_MAX_DATA_LEN 255
|
||||
|
||||
// packet type
|
||||
#define BLUFI_TYPE_MASK 0x03
|
||||
#define BLUFI_TYPE_SHIFT 0
|
||||
#define BLUFI_SUBTYPE_MASK 0xFC
|
||||
#define BLUFI_SUBTYPE_SHIFT 2
|
||||
|
||||
#define BLUFI_GET_TYPE(type) ((type) & BLUFI_TYPE_MASK)
|
||||
#define BLUFI_GET_SUBTYPE(type) (((type) & BLUFI_SUBTYPE_MASK) >>BLUFI_SUBTYPE_SHIFT)
|
||||
#define BLUFI_BUILD_TYPE(type, subtype) (((type) & BLUFI_TYPE_MASK) | ((subtype)<<BLUFI_SUBTYPE_SHIFT))
|
||||
|
||||
#define BLUFI_TYPE_CTRL 0x0
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_ACK 0x00
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_SET_SEC_MODE 0x01
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_SET_WIFI_OPMODE 0x02
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_CONN_TO_AP 0x03
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_DISCONN_FROM_AP 0x04
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_STATUS 0x05
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_DEAUTHENTICATE_STA 0x06
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_GET_VERSION 0x07
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_DISCONNECT_BLE 0x08
|
||||
#define BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_LIST 0x09
|
||||
|
||||
#define BLUFI_TYPE_DATA 0x1
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_NEG 0x00
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID 0x01
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_STA_SSID 0x02
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD 0x03
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID 0x04
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD 0x05
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM 0x06
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE 0x07
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL 0x08
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_USERNAME 0x09
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_CA 0x0a
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_CLIENT_CERT 0x0b
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SERVER_CERT 0x0c
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_CLIENT_PRIV_KEY 0x0d
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_SERVER_PRIV_KEY 0x0e
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_WIFI_REP 0x0f
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_REPLY_VERSION 0x10
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_WIFI_LIST 0x11
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_ERROR_INFO 0x12
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_CUSTOM_DATA 0x13
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_STA_MAX_CONN_RETRY 0x14
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_END_REASON 0x15
|
||||
#define BLUFI_TYPE_DATA_SUBTYPE_STA_CONN_RSSI 0x16
|
||||
#define BLUFI_TYPE_IS_CTRL(type) (BLUFI_GET_TYPE((type)) == BLUFI_TYPE_CTRL)
|
||||
#define BLUFI_TYPE_IS_DATA(type) (BLUFI_GET_TYPE((type)) == BLUFI_TYPE_DATA)
|
||||
|
||||
#define BLUFI_TYPE_IS_CTRL_ACK(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_ACK)
|
||||
#define BLUFI_TYPE_IS_CTRL_START_NEG(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_START_NEG)
|
||||
#define BLUFI_TYPE_IS_CTRL_STOP_NEG(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_STOP_NEG)
|
||||
#define BLUFI_TYPE_IS_CTRL_SET_WIFI_OPMODE(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_SET_WIFI_OPMODE)
|
||||
#define BLUFI_TYPE_IS_CTRL_CONN_WIFI(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_CONN_TO_AP)
|
||||
#define BLUFI_TYPE_IS_CTRL_DISCONN_WIFI(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_DISCONN_FROM_AP)
|
||||
#define BLUFI_TYPE_IS_CTRL_GET_WIFI_STATUS(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_GET_WIFI_STATUS)
|
||||
#define BLUFI_TYPE_IS_CTRL_DEAUTHENTICATE_STA(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_DEAUTHENTICATE_STA)
|
||||
#define BLUFI_TYPE_IS_CTRL_GET_VERSION(type) (BLUFI_TYPE_IS_CTRL((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_CTRL_SUBTYPE_GET_VERSION)
|
||||
|
||||
#define BLUFI_TYPE_IS_DATA_NEG(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_NEG)
|
||||
#define BLUFI_TYPE_IS_DATA_STA_BSSID(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_STA_BSSID)
|
||||
#define BLUFI_TYPE_IS_DATA_STA_SSID(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_STA_SSID)
|
||||
#define BLUFI_TYPE_IS_DATA_STA_PASSWD(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_STA_PASSWD)
|
||||
#define BLUFI_TYPE_IS_DATA_SOFTAP_SSID(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_SSID)
|
||||
#define BLUFI_TYPE_IS_DATA_SOFTAP_PASSWD(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_PASSWD)
|
||||
#define BLUFI_TYPE_IS_DATA_SOFTAP_MAX_CONN_NUM(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_MAX_CONN_NUM)
|
||||
#define BLUFI_TYPE_IS_DATA_SOFTAP_AUTH_MODE(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_AUTH_MODE)
|
||||
#define BLUFI_TYPE_IS_DATA_SOFTAP_CHANNEL(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SOFTAP_CHANNEL)
|
||||
#define BLUFI_TYPE_IS_DATA_USERNAME(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_USERNAME)
|
||||
#define BLUFI_TYPE_IS_DATA_CA(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_CA)
|
||||
#define BLUFI_TYPE_IS_DATA_CLEINT_CERT(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_CLIENT_CERT)
|
||||
#define BLUFI_TYPE_IS_DATA_SERVER_CERT(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SERVER_CERT)
|
||||
#define BLUFI_TYPE_IS_DATA_CLIENT_PRIV_KEY(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_CLIENT_PRIV_KEY)
|
||||
#define BLUFI_TYPE_IS_DATA_SERVER_PRIV_KEY(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_SERVER_PRIV_KEY)
|
||||
#define BLUFI_TYPE_IS_DATA_ERROR_INFO(type) (BLUFI_TYPE_IS_DATA((type)) && BLUFI_GET_SUBTYPE((type)) == BLUFI_TYPE_DATA_SUBTYPE_ERROR_INFO)
|
||||
|
||||
// packet frame control
|
||||
#define BLUFI_FC_ENC_MASK 0x01
|
||||
#define BLUFI_FC_CHECK_MASK 0x02
|
||||
#define BLUFI_FC_DIR_MASK 0x04
|
||||
#define BLUFI_FC_REQ_ACK_MASK 0x08
|
||||
#define BLUFI_FC_FRAG_MASK 0x10
|
||||
|
||||
#define BLUFI_FC_ENC 0x01
|
||||
#define BLUFI_FC_CHECK 0x02
|
||||
#define BLUFI_FC_DIR_P2E 0x00
|
||||
#define BLUFI_FC_DIR_E2P 0x04
|
||||
#define BLUFI_FC_REQ_ACK 0x08
|
||||
#define BLUFI_FC_FRAG 0x10
|
||||
|
||||
#define BLUFI_FC_IS_ENC(fc) ((fc) & BLUFI_FC_ENC_MASK)
|
||||
#define BLUFI_FC_IS_CHECK(fc) ((fc) & BLUFI_FC_CHECK_MASK)
|
||||
#define BLUFI_FC_IS_DIR_P2E(fc) ((fc) & BLUFI_FC_DIR_P2E_MASK)
|
||||
#define BLUFI_FC_IS_DIR_E2P(fc) (!((fc) & BLUFI_DIR_P2E_MASK))
|
||||
#define BLUFI_FC_IS_REQ_ACK(fc) ((fc) & BLUFI_FC_REQ_ACK_MASK)
|
||||
#define BLUFI_FC_IS_FRAG(fc) ((fc) & BLUFI_FC_FRAG_MASK)
|
||||
|
||||
/* default GATT MTU size over LE link
|
||||
*/
|
||||
#define GATT_DEF_BLE_MTU_SIZE 23
|
||||
/* BLUFI HEADER + TOTAL(REMAIN) LENGTH + CRC + L2CAP RESERVED */
|
||||
#define BLUFI_MTU_RESERVED_SIZE (sizeof(struct blufi_hdr) + 2 + 2 + 3)
|
||||
#define BLUFI_FRAG_DATA_DEFAULT_LEN (GATT_DEF_BLE_MTU_SIZE - BLUFI_MTU_RESERVED_SIZE)
|
||||
|
||||
//function declare
|
||||
void btc_blufi_protocol_handler(uint8_t type, uint8_t *data, int len);
|
||||
|
||||
void btc_blufi_send_encap(uint8_t type, uint8_t *data, int data_len);
|
||||
|
||||
void btc_blufi_set_callbacks(esp_blufi_callbacks_t *callbacks);
|
||||
|
||||
void btc_blufi_cb_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
void btc_blufi_cb_deep_free(btc_msg_t *msg);
|
||||
|
||||
#endif /* __BLUFI_INT_H__ */
|
||||
#endif ///BLUFI_INCLUDED == TRUE
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __ESP_BLUFI_H__
|
||||
#define __ESP_BLUFI_H__
|
||||
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "nimble/ble.h"
|
||||
#include "host/ble_gap.h"
|
||||
#include "modlog/modlog.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "esp_gap_ble_api.h"
|
||||
#endif
|
||||
|
||||
#define BLUFI_APP_UUID 0xFFFF
|
||||
#define BLUFI_DEVICE_NAME "BLUFI_DEVICE"
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
struct ble_hs_cfg;
|
||||
struct ble_gatt_register_ctxt;
|
||||
struct gatt_value {
|
||||
struct os_mbuf *buf;
|
||||
uint16_t val_handle;
|
||||
uint8_t type;
|
||||
void *ptr;
|
||||
};
|
||||
#define SERVER_MAX_VALUES 3
|
||||
#define MAX_VAL_SIZE 512
|
||||
extern struct gatt_value gatt_values[SERVER_MAX_VALUES];
|
||||
/* GATT server callback */
|
||||
void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg);
|
||||
|
||||
/* Initialise gatt server */
|
||||
int esp_blufi_gatt_svr_init(void);
|
||||
void esp_blufi_btc_init(void);
|
||||
void esp_blufi_btc_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
/**
|
||||
* @brief Close a connection a remote device.
|
||||
*
|
||||
* @param[in] gatts_if: GATT server access interface
|
||||
* @param[in] conn_id: connection ID to be closed.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : success
|
||||
* - other : failed
|
||||
*
|
||||
*/
|
||||
esp_err_t esp_blufi_close(uint8_t gatts_if, uint16_t conn_id);
|
||||
void esp_blufi_gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
|
||||
#endif
|
||||
|
||||
/* Initialise blufi profile */
|
||||
uint8_t esp_blufi_init(void);
|
||||
|
||||
/* start advertising */
|
||||
void bleprph_advertise(void);
|
||||
|
||||
/* send notifications */
|
||||
void esp_blufi_send_notify(void *arg);
|
||||
|
||||
/* Deinitialise blufi */
|
||||
void esp_blufi_deinit(void);
|
||||
/* disconnect */
|
||||
void esp_blufi_disconnect(void);
|
||||
|
||||
/* Stop advertisement */
|
||||
void esp_blufi_adv_stop(void);
|
||||
|
||||
/* Start advertisement */
|
||||
void esp_blufi_adv_start(void);
|
||||
|
||||
void esp_blufi_send_encap(void *arg);
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
/**
|
||||
* @brief Handle gap event for BluFi.
|
||||
* This function can be called inside custom use gap event handler.
|
||||
* It provide minimal event management for BluFi purpose.
|
||||
*
|
||||
* @param[in] event The type of event being signalled.
|
||||
* @param[in] arg Application-specified argument. Currently unused
|
||||
* @return int 0 in case of success.
|
||||
* Other in case of failure.
|
||||
*/
|
||||
int esp_blufi_handle_gap_events(struct ble_gap_event *event, void *arg);
|
||||
#endif
|
||||
|
||||
#endif/* _ESP_BLUFI_ */
|
||||
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "btc_blufi_prf.h"
|
||||
#include "blufi_int.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_err.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_blufi.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "console/console.h"
|
||||
|
||||
/*nimBLE Host*/
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#include "host/util/util.h"
|
||||
#include "host/ble_uuid.h"
|
||||
#include "host/ble_gatt.h"
|
||||
|
||||
#include "services/gap/ble_svc_gap.h"
|
||||
#include "services/gatt/ble_svc_gatt.h"
|
||||
|
||||
#if (BLUFI_INCLUDED == TRUE)
|
||||
|
||||
static uint8_t own_addr_type;
|
||||
|
||||
struct gatt_value gatt_values[SERVER_MAX_VALUES];
|
||||
const static char *TAG = "BLUFI_EXAMPLE";
|
||||
|
||||
enum {
|
||||
GATT_VALUE_TYPE_CHR,
|
||||
GATT_VALUE_TYPE_DSC,
|
||||
};
|
||||
|
||||
static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg);
|
||||
|
||||
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
|
||||
{
|
||||
/*** Service: Blufi */
|
||||
.type = BLE_GATT_SVC_TYPE_PRIMARY,
|
||||
.uuid = BLE_UUID16_DECLARE(BLUFI_SERVICE_UUID),
|
||||
.characteristics = (struct ble_gatt_chr_def[])
|
||||
{ {
|
||||
/*** Characteristic: P2E */
|
||||
.uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_P2E_UUID),
|
||||
.access_cb = gatt_svr_access_cb,
|
||||
.flags = BLE_GATT_CHR_F_WRITE,
|
||||
.arg = &gatt_values[0],
|
||||
.val_handle = &gatt_values[0].val_handle,
|
||||
}, {
|
||||
/*** Characteristic: E2P */
|
||||
.uuid = BLE_UUID16_DECLARE(BLUFI_CHAR_E2P_UUID),
|
||||
.access_cb = gatt_svr_access_cb,
|
||||
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_NOTIFY,
|
||||
.arg = &gatt_values[1],
|
||||
.val_handle = &gatt_values[1].val_handle,
|
||||
}, {
|
||||
0, /* No more characteristics in this service. */
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
0, /* No more services. */
|
||||
},
|
||||
};
|
||||
|
||||
void esp_blufi_gatt_svr_register_cb(struct ble_gatt_register_ctxt *ctxt, void *arg)
|
||||
{
|
||||
char buf[BLE_UUID_STR_LEN];
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_REGISTER_OP_SVC:
|
||||
ESP_LOGI(TAG, "registered service %s with handle=%d",
|
||||
ble_uuid_to_str(ctxt->svc.svc_def->uuid, buf),
|
||||
ctxt->svc.handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_CHR:
|
||||
ESP_LOGI(TAG, "registering characteristic %s with "
|
||||
"def_handle=%d val_handle=%d\n",
|
||||
ble_uuid_to_str(ctxt->chr.chr_def->uuid, buf),
|
||||
ctxt->chr.def_handle,
|
||||
ctxt->chr.val_handle);
|
||||
break;
|
||||
|
||||
case BLE_GATT_REGISTER_OP_DSC:
|
||||
ESP_LOGI(TAG, "registering descriptor %s with handle=%d",
|
||||
ble_uuid_to_str(ctxt->dsc.dsc_def->uuid, buf),
|
||||
ctxt->dsc.handle);
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t write_value(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
struct gatt_value *value = (struct gatt_value *)arg;
|
||||
uint16_t len;
|
||||
int rc;
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_WRITE_CHR) {
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_WRITE_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
} else {
|
||||
if (ctxt->dsc->att_flags & BLE_ATT_F_WRITE_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
}
|
||||
|
||||
btc_blufi_recv_handler(&ctxt->om->om_data[0], ctxt->om->om_len);
|
||||
rc = ble_hs_mbuf_to_flat(ctxt->om, value->buf->om_data,
|
||||
value->buf->om_len, &len);
|
||||
if (rc != 0) {
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
/* Maximum attribute value size is 512 bytes */
|
||||
assert(value->buf->om_len < MAX_VAL_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t read_value(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
const struct gatt_value *value = (const struct gatt_value *) arg;
|
||||
char str[BLE_UUID_STR_LEN];
|
||||
int rc;
|
||||
|
||||
memset(str, '\0', sizeof(str));
|
||||
|
||||
if (ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR) {
|
||||
if (ctxt->chr->flags & BLE_GATT_CHR_F_READ_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
|
||||
ble_uuid_to_str(ctxt->chr->uuid, str);
|
||||
} else {
|
||||
if (ctxt->dsc->att_flags & BLE_ATT_F_READ_AUTHOR) {
|
||||
return BLE_ATT_ERR_INSUFFICIENT_AUTHOR;
|
||||
}
|
||||
|
||||
ble_uuid_to_str(ctxt->dsc->uuid, str);
|
||||
}
|
||||
|
||||
rc = os_mbuf_append(ctxt->om, value->buf->om_data, value->buf->om_len);
|
||||
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
|
||||
}
|
||||
|
||||
static int gatt_svr_access_cb(uint16_t conn_handle, uint16_t attr_handle,
|
||||
struct ble_gatt_access_ctxt *ctxt,
|
||||
void *arg)
|
||||
{
|
||||
switch (ctxt->op) {
|
||||
case BLE_GATT_ACCESS_OP_READ_CHR:
|
||||
return read_value(conn_handle, attr_handle,
|
||||
ctxt, arg);
|
||||
case BLE_GATT_ACCESS_OP_WRITE_CHR:
|
||||
return write_value(conn_handle, attr_handle,
|
||||
ctxt, arg);
|
||||
default:
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
/* Unknown characteristic; the nimble stack should not have called this
|
||||
* function.
|
||||
*/
|
||||
assert(0);
|
||||
return BLE_ATT_ERR_UNLIKELY;
|
||||
}
|
||||
|
||||
static void init_gatt_values(void)
|
||||
{
|
||||
int i = 0;
|
||||
const struct ble_gatt_svc_def *svc;
|
||||
const struct ble_gatt_chr_def *chr;
|
||||
const struct ble_gatt_dsc_def *dsc;
|
||||
|
||||
for (svc = gatt_svr_svcs; svc && svc->uuid; svc++) {
|
||||
for (chr = svc->characteristics; chr && chr->uuid; chr++) {
|
||||
assert(i < SERVER_MAX_VALUES);
|
||||
gatt_values[i].type = GATT_VALUE_TYPE_CHR;
|
||||
gatt_values[i].ptr = (void *)chr;
|
||||
gatt_values[i].buf = os_msys_get(0, 0);
|
||||
os_mbuf_extend(gatt_values[i].buf, 1);
|
||||
++i;
|
||||
|
||||
for (dsc = chr->descriptors; dsc && dsc->uuid; dsc++) {
|
||||
assert(i < SERVER_MAX_VALUES);
|
||||
gatt_values[i].type = GATT_VALUE_TYPE_DSC;
|
||||
gatt_values[i].ptr = (void *)dsc;
|
||||
gatt_values[i].buf = os_msys_get(0, 0);
|
||||
os_mbuf_extend(gatt_values[i].buf, 1);
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int esp_blufi_gatt_svr_init(void)
|
||||
{
|
||||
int rc;
|
||||
ble_svc_gap_init();
|
||||
ble_svc_gatt_init();
|
||||
|
||||
rc = ble_gatts_count_cfg(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ble_gatts_add_svcs(gatt_svr_svcs);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
init_gatt_values();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
esp_blufi_gap_event(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
int rc;
|
||||
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
/* A new connection was established or a connection attempt failed. */
|
||||
ESP_LOGI(TAG, "connection %s; status=%d",
|
||||
event->connect.status == 0 ? "established" : "failed",
|
||||
event->connect.status);
|
||||
if (event->connect.status == 0) {
|
||||
|
||||
blufi_env.is_connected = true;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
memcpy(param.connect.remote_bda, desc.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
|
||||
|
||||
param.connect.conn_id = event->connect.conn_handle;
|
||||
/* save connection handle */
|
||||
blufi_env.conn_id = event->connect.conn_handle;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
}
|
||||
if (event->connect.status != 0) {
|
||||
/* Connection failed; resume advertising. */
|
||||
esp_blufi_adv_start();
|
||||
}
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_DISCONNECT:
|
||||
ESP_LOGI(TAG, "disconnect; reason=%d", event->disconnect.reason);
|
||||
memcpy(blufi_env.remote_bda, event->disconnect.conn.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
|
||||
blufi_env.is_connected = false;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.sec_mode = 0x0;
|
||||
blufi_env.offset = 0;
|
||||
|
||||
if (blufi_env.aggr_buf != NULL) {
|
||||
osi_free(blufi_env.aggr_buf);
|
||||
blufi_env.aggr_buf = NULL;
|
||||
}
|
||||
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
|
||||
memcpy(param.disconnect.remote_bda, event->disconnect.conn.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_CONN_UPDATE:
|
||||
/* The central has updated the connection parameters. */
|
||||
ESP_LOGI(TAG, "connection updated; status=%d",
|
||||
event->conn_update.status);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_ADV_COMPLETE:
|
||||
ESP_LOGI(TAG, "advertise complete; reason=%d",
|
||||
event->adv_complete.reason);
|
||||
esp_blufi_adv_start();
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_SUBSCRIBE:
|
||||
ESP_LOGI(TAG, "subscribe event; conn_handle=%d attr_handle=%d "
|
||||
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
|
||||
event->subscribe.conn_handle,
|
||||
event->subscribe.attr_handle,
|
||||
event->subscribe.reason,
|
||||
event->subscribe.prev_notify,
|
||||
event->subscribe.cur_notify,
|
||||
event->subscribe.prev_indicate,
|
||||
event->subscribe.cur_indicate);
|
||||
return 0;
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
ESP_LOGI(TAG, "mtu update event; conn_handle=%d cid=%d mtu=%d",
|
||||
event->mtu.conn_handle,
|
||||
event->mtu.channel_id,
|
||||
event->mtu.value);
|
||||
blufi_env.frag_size = (event->mtu.value < BLUFI_MAX_DATA_LEN ? event->mtu.value : BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
|
||||
return 0;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void esp_blufi_adv_start(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ble_hs_util_ensure_addr(0);
|
||||
assert(rc == 0);
|
||||
|
||||
/* Figure out address to use while advertising (no privacy for now) */
|
||||
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
||||
if (rc != 0) {
|
||||
ESP_LOGI(TAG, "error determining address type; rc=%d ", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Printing ADDR */
|
||||
uint8_t addr_val[6] = {0};
|
||||
rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
|
||||
|
||||
/* Begin advertising. */
|
||||
struct ble_gap_adv_params adv_params;
|
||||
struct ble_hs_adv_fields fields;
|
||||
const char *name;
|
||||
|
||||
/**
|
||||
* Set the advertisement data included in our advertisements:
|
||||
* o Flags (indicates advertisement type and other general info).
|
||||
* o Advertising tx power.
|
||||
* o Device name.
|
||||
* o 16-bit service UUIDs (alert notifications).
|
||||
*/
|
||||
|
||||
memset(&fields, 0, sizeof fields);
|
||||
|
||||
/* Advertise two flags:
|
||||
* o Discoverability in forthcoming advertisement (general)
|
||||
* o BLE-only (BR/EDR unsupported).
|
||||
*/
|
||||
fields.flags = BLE_HS_ADV_F_DISC_GEN |
|
||||
BLE_HS_ADV_F_BREDR_UNSUP;
|
||||
|
||||
/* Indicate that the TX power level field should be included; have the
|
||||
* stack fill this value automatically. This is done by assigning the
|
||||
* special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
|
||||
*/
|
||||
fields.tx_pwr_lvl_is_present = 1;
|
||||
fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
|
||||
|
||||
name = ble_svc_gap_device_name();
|
||||
fields.name = (uint8_t *)name;
|
||||
fields.name_len = strlen(name);
|
||||
fields.name_is_complete = 1;
|
||||
|
||||
fields.uuids16 = (ble_uuid16_t[]) {
|
||||
BLE_UUID16_INIT(BLUFI_APP_UUID)
|
||||
};
|
||||
fields.num_uuids16 = 1;
|
||||
fields.uuids16_is_complete = 1;
|
||||
rc = ble_gap_adv_set_fields(&fields);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "error setting advertisement data; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Begin advertising. */
|
||||
memset(&adv_params, 0, sizeof adv_params);
|
||||
adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
|
||||
adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
|
||||
rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
|
||||
&adv_params, esp_blufi_gap_event, NULL);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "error enabling advertisement; rc=%d", rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t esp_blufi_init(void)
|
||||
{
|
||||
blufi_env.enabled = true;
|
||||
esp_blufi_cb_param_t param;
|
||||
param.init_finish.state = ESP_BLUFI_INIT_OK;
|
||||
btc_blufi_cb_to_app(ESP_BLUFI_EVENT_INIT_FINISH, ¶m);
|
||||
return ESP_BLUFI_ERROR;
|
||||
}
|
||||
|
||||
void esp_blufi_deinit(void)
|
||||
{
|
||||
blufi_env.enabled = false;
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_DEINIT_FINISH;
|
||||
param.deinit_finish.state = ESP_BLUFI_DEINIT_OK;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
}
|
||||
|
||||
void esp_blufi_send_notify(void *arg)
|
||||
{
|
||||
struct pkt_info *pkts = (struct pkt_info *) arg;
|
||||
struct os_mbuf *om;
|
||||
om = ble_hs_mbuf_from_flat(pkts->pkt, pkts->pkt_len);
|
||||
if (om == NULL) {
|
||||
ESP_LOGE(TAG, "Error in allocating memory");
|
||||
return;
|
||||
}
|
||||
int rc = 0;
|
||||
rc = ble_gatts_notify_custom(blufi_env.conn_id, gatt_values[1].val_handle, om);
|
||||
if (rc != 0) {
|
||||
ESP_LOGE(TAG, "Error in sending notification");
|
||||
}
|
||||
}
|
||||
|
||||
void esp_blufi_disconnect(void)
|
||||
{
|
||||
ble_gap_terminate(blufi_env.conn_id, BLE_ERR_REM_USER_CONN_TERM);
|
||||
}
|
||||
|
||||
void esp_blufi_adv_stop(void) {}
|
||||
|
||||
void esp_blufi_send_encap(void *arg)
|
||||
{
|
||||
struct blufi_hdr *hdr = (struct blufi_hdr *)arg;
|
||||
if (blufi_env.is_connected == false) {
|
||||
BTC_TRACE_WARNING("%s ble connection is broken\n", __func__);
|
||||
return;
|
||||
}
|
||||
btc_blufi_send_notify((uint8_t *)hdr,
|
||||
((hdr->fc & BLUFI_FC_CHECK) ?
|
||||
hdr->data_len + sizeof(struct blufi_hdr) + 2 :
|
||||
hdr->data_len + sizeof(struct blufi_hdr)));
|
||||
}
|
||||
|
||||
void esp_blufi_btc_init(void)
|
||||
{
|
||||
int rc;
|
||||
rc = btc_init();
|
||||
assert(rc == 0);
|
||||
}
|
||||
|
||||
void esp_blufi_btc_deinit(void)
|
||||
{
|
||||
btc_deinit();
|
||||
}
|
||||
|
||||
int esp_blufi_handle_gap_events(struct ble_gap_event *event, void *arg)
|
||||
{
|
||||
struct ble_gap_conn_desc desc;
|
||||
int rc;
|
||||
|
||||
if (event != NULL) {
|
||||
switch (event->type) {
|
||||
case BLE_GAP_EVENT_CONNECT:
|
||||
if (event->connect.status == 0) {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
blufi_env.is_connected = true;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.conn_id = event->connect.conn_handle;
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_CONNECT;
|
||||
|
||||
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
|
||||
assert(rc == 0);
|
||||
memcpy(param.connect.remote_bda, desc.peer_id_addr.val, ESP_BLUFI_BD_ADDR_LEN);
|
||||
|
||||
param.connect.conn_id = event->connect.conn_handle;
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
}
|
||||
return 0;
|
||||
case BLE_GAP_EVENT_DISCONNECT: {
|
||||
btc_msg_t msg;
|
||||
esp_blufi_cb_param_t param;
|
||||
|
||||
blufi_env.is_connected = false;
|
||||
blufi_env.recv_seq = blufi_env.send_seq = 0;
|
||||
blufi_env.sec_mode = 0x0;
|
||||
blufi_env.offset = 0;
|
||||
|
||||
memcpy(blufi_env.remote_bda,
|
||||
event->disconnect.conn.peer_id_addr.val,
|
||||
ESP_BLUFI_BD_ADDR_LEN);
|
||||
|
||||
if (blufi_env.aggr_buf != NULL) {
|
||||
osi_free(blufi_env.aggr_buf);
|
||||
blufi_env.aggr_buf = NULL;
|
||||
}
|
||||
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_BLUFI;
|
||||
msg.act = ESP_BLUFI_EVENT_BLE_DISCONNECT;
|
||||
memcpy(param.disconnect.remote_bda,
|
||||
event->disconnect.conn.peer_id_addr.val,
|
||||
ESP_BLUFI_BD_ADDR_LEN);
|
||||
btc_transfer_context(&msg, ¶m, sizeof(esp_blufi_cb_param_t), NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case BLE_GAP_EVENT_MTU:
|
||||
blufi_env.frag_size = (event->mtu.value < BLUFI_MAX_DATA_LEN ? event->mtu.value :
|
||||
BLUFI_MAX_DATA_LEN) - BLUFI_MTU_RESERVED_SIZE;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BTC_BLUFI_PRF_H__
|
||||
#define __BTC_BLUFI_PRF_H__
|
||||
|
||||
#include "blufi_int.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "esp_blufi_api.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "stack/gatt_api.h"
|
||||
#define ESP_BLUFI_ERROR GATT_ERROR
|
||||
#define ESP_BLUFI_SUCCESS GATT_SUCCESS
|
||||
#else
|
||||
#define ESP_BLUFI_ERROR 0x85
|
||||
#define ESP_BLUFI_SUCCESS 0x00
|
||||
#endif
|
||||
|
||||
#define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||
#define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
|
||||
|
||||
#define GATT_UUID_CHAR_CLIENT_CONFIG 0x2902 /* Client Characteristic Configuration */
|
||||
//define the blufi serivce uuid
|
||||
#define BLUFI_SERVICE_UUID 0xFFFF
|
||||
//define the blufi Char uuid (PHONE to ESP32)
|
||||
#define BLUFI_CHAR_P2E_UUID 0xFF01
|
||||
//define the blufi Char uuid (ESP32 to PHONE)
|
||||
#define BLUFI_CHAR_E2P_UUID 0xFF02
|
||||
//define the blufi Descriptor uuid (ESP32 to PHONE)
|
||||
#define BLUFI_DESCR_E2P_UUID GATT_UUID_CHAR_CLIENT_CONFIG
|
||||
//define the blufi APP ID
|
||||
#define BLUFI_APP_UUID 0xFFFF
|
||||
|
||||
#define BLUFI_HDL_NUM 6
|
||||
|
||||
struct pkt_info{
|
||||
uint8_t *pkt;
|
||||
int pkt_len;
|
||||
};
|
||||
|
||||
static const tBT_UUID blufi_srvc_uuid = {LEN_UUID_16, {BLUFI_SERVICE_UUID}};
|
||||
static const tBT_UUID blufi_char_uuid_p2e = {LEN_UUID_16, {BLUFI_CHAR_P2E_UUID}};
|
||||
static const tBT_UUID blufi_char_uuid_e2p = {LEN_UUID_16, {BLUFI_CHAR_E2P_UUID}};
|
||||
static const tBT_UUID blufi_descr_uuid_e2p = {LEN_UUID_16, {BLUFI_DESCR_E2P_UUID}};
|
||||
static const tBT_UUID blufi_app_uuid = {LEN_UUID_16, {BLUFI_APP_UUID}};
|
||||
|
||||
typedef enum {
|
||||
BTC_BLUFI_ACT_INIT = 0,
|
||||
BTC_BLUFI_ACT_DEINIT,
|
||||
BTC_BLUFI_ACT_SEND_CFG_REPORT,
|
||||
BTC_BLUFI_ACT_SEND_WIFI_LIST,
|
||||
BTC_BLUFI_ACT_SEND_ERR_INFO,
|
||||
BTC_BLUFI_ACT_SEND_CUSTOM_DATA,
|
||||
} btc_blufi_act_t;
|
||||
|
||||
typedef union {
|
||||
struct blufi_cfg_report {
|
||||
wifi_mode_t opmode;
|
||||
esp_blufi_sta_conn_state_t sta_conn_state;
|
||||
uint8_t softap_conn_num;
|
||||
esp_blufi_extra_info_t *extra_info;
|
||||
int extra_info_len;
|
||||
} wifi_conn_report;
|
||||
/*
|
||||
BTC_BLUFI_ACT_SEND_WIFI_LIST
|
||||
*/
|
||||
struct blufi_wifi_list {
|
||||
uint16_t apCount;
|
||||
esp_blufi_ap_record_t *list;
|
||||
} wifi_list;
|
||||
/*
|
||||
BTC_BLUFI_ACT_SEND_ERR_INFO
|
||||
*/
|
||||
struct blufi_error_infor {
|
||||
esp_blufi_error_state_t state;
|
||||
} blufi_err_infor;
|
||||
/*
|
||||
BTC_BLUFI_ACT_SEND_CUSTOM_DATA
|
||||
*/
|
||||
struct blufi_custom_data {
|
||||
uint8_t *data;
|
||||
uint32_t data_len;
|
||||
} custom_data;
|
||||
} btc_blufi_args_t;
|
||||
|
||||
void btc_blufi_cb_to_app(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);
|
||||
void btc_blufi_cb_handler(btc_msg_t *msg);
|
||||
void btc_blufi_call_handler(btc_msg_t *msg);
|
||||
void btc_blufi_set_callbacks(esp_blufi_callbacks_t *callbacks);
|
||||
|
||||
void btc_blufi_recv_handler(uint8_t *data, int len);
|
||||
void btc_blufi_send_notify(uint8_t *pkt, int pkt_len);
|
||||
void btc_blufi_call_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
void btc_blufi_call_deep_free(btc_msg_t *msg);
|
||||
|
||||
uint16_t btc_blufi_get_version(void);
|
||||
|
||||
#endif /* __BTC_BLUFI_PRF_H__ */
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _BT_COMMON_H_
|
||||
#define _BT_COMMON_H_
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include "bt_user_config.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE false
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE true
|
||||
#endif
|
||||
|
||||
|
||||
#if (UC_BT_BLUFI_ENABLE)
|
||||
#define BLUFI_INCLUDED TRUE
|
||||
#else
|
||||
#define BLUFI_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include "esp_bt_defs.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gatt_defs.h"
|
||||
#define ESP_BLE_HOST_STATUS_ENABLED ESP_BLUEDROID_STATUS_ENABLED
|
||||
#define ESP_BLE_HOST_STATUS_CHECK(status) ESP_BLUEDROID_STATUS_CHECK(status)
|
||||
#else
|
||||
#define ESP_BLE_HOST_STATUS_ENABLED 0
|
||||
#define ESP_BLE_HOST_STATUS_CHECK(status) do {} while (0)
|
||||
#endif
|
||||
|
||||
#ifndef BT_QUEUE_CONGEST_SIZE
|
||||
#define BT_QUEUE_CONGEST_SIZE 40
|
||||
#endif
|
||||
|
||||
#define BTC_INITIAL_TRACE_LEVEL UC_BT_LOG_BTC_TRACE_LEVEL
|
||||
#define OSI_INITIAL_TRACE_LEVEL UC_BT_LOG_OSI_TRACE_LEVEL
|
||||
#define BLUFI_INITIAL_TRACE_LEVEL UC_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
|
||||
#if UC_BT_BLE_DYNAMIC_ENV_MEMORY
|
||||
#define BT_BLE_DYNAMIC_ENV_MEMORY TRUE
|
||||
#define BTC_DYNAMIC_MEMORY TRUE
|
||||
#else
|
||||
#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE
|
||||
#define BTC_DYNAMIC_MEMORY FALSE
|
||||
#endif
|
||||
|
||||
#if UC_BT_BLUEDROID_MEM_DEBUG
|
||||
#define HEAP_MEMORY_DEBUG TRUE
|
||||
#else
|
||||
#define HEAP_MEMORY_DEBUG FALSE
|
||||
#endif
|
||||
|
||||
#ifndef BT_BLE_DYNAMIC_ENV_MEMORY
|
||||
#define BT_BLE_DYNAMIC_ENV_MEMORY FALSE
|
||||
#endif
|
||||
|
||||
/* OS Configuration from User config (eg: sdkconfig) */
|
||||
#define TASK_PINNED_TO_CORE UC_TASK_PINNED_TO_CORE
|
||||
#define BT_TASK_MAX_PRIORITIES configMAX_PRIORITIES
|
||||
#define BT_BTC_TASK_STACK_SIZE UC_BTC_TASK_STACK_SIZE
|
||||
|
||||
/* Define trace levels */
|
||||
#define BT_TRACE_LEVEL_NONE UC_TRACE_LEVEL_NONE /* No trace messages to be generated */
|
||||
#define BT_TRACE_LEVEL_ERROR UC_TRACE_LEVEL_ERROR /* Error condition trace messages */
|
||||
#define BT_TRACE_LEVEL_WARNING UC_TRACE_LEVEL_WARNING /* Warning condition trace messages */
|
||||
#define BT_TRACE_LEVEL_API UC_TRACE_LEVEL_API /* API traces */
|
||||
#define BT_TRACE_LEVEL_EVENT UC_TRACE_LEVEL_EVENT /* Debug messages for events */
|
||||
#define BT_TRACE_LEVEL_DEBUG UC_TRACE_LEVEL_DEBUG /* Full debug messages */
|
||||
#define BT_TRACE_LEVEL_VERBOSE UC_TRACE_LEVEL_VERBOSE /* Verbose debug messages */
|
||||
|
||||
#define MAX_TRACE_LEVEL UC_TRACE_LEVEL_VERBOSE
|
||||
|
||||
#ifndef LOG_LOCAL_LEVEL
|
||||
#ifndef BOOTLOADER_BUILD
|
||||
#define LOG_LOCAL_LEVEL UC_LOG_DEFAULT_LEVEL
|
||||
#else
|
||||
#define LOG_LOCAL_LEVEL UC_BOOTLOADER_LOG_LEVEL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Mapping between ESP_LOG_LEVEL and BT_TRACE_LEVEL
|
||||
#if (LOG_LOCAL_LEVEL >= 4)
|
||||
#define LOG_LOCAL_LEVEL_MAPPING (LOG_LOCAL_LEVEL+1)
|
||||
#else
|
||||
#define LOG_LOCAL_LEVEL_MAPPING LOG_LOCAL_LEVEL
|
||||
#endif
|
||||
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
#define BT_LOG_LEVEL_CHECK(LAYER, LEVEL) (MAX(LAYER##_INITIAL_TRACE_LEVEL, LOG_LOCAL_LEVEL_MAPPING) >= BT_TRACE_LEVEL_##LEVEL)
|
||||
|
||||
#define BT_PRINT_E(tag, format, ...) {esp_log_write(ESP_LOG_ERROR, tag, LOG_FORMAT(E, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
#define BT_PRINT_W(tag, format, ...) {esp_log_write(ESP_LOG_WARN, tag, LOG_FORMAT(W, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
#define BT_PRINT_I(tag, format, ...) {esp_log_write(ESP_LOG_INFO, tag, LOG_FORMAT(I, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
#define BT_PRINT_D(tag, format, ...) {esp_log_write(ESP_LOG_DEBUG, tag, LOG_FORMAT(D, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
#define BT_PRINT_V(tag, format, ...) {esp_log_write(ESP_LOG_VERBOSE, tag, LOG_FORMAT(V, format), esp_log_timestamp(), tag, ##__VA_ARGS__); }
|
||||
|
||||
|
||||
#if !UC_BT_STACK_NO_LOG
|
||||
/* define traces for BTC */
|
||||
#define BTC_TRACE_ERROR(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BTC, ERROR)) BT_PRINT_E("BT_BTC", fmt, ## args);}
|
||||
#define BTC_TRACE_WARNING(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BTC, WARNING)) BT_PRINT_W("BT_BTC", fmt, ## args);}
|
||||
#define BTC_TRACE_API(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(BTC,API)) BT_PRINT_I("BT_BTC", fmt, ## args);}
|
||||
#define BTC_TRACE_EVENT(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(BTC,EVENT)) BT_PRINT_D("BT_BTC", fmt, ## args);}
|
||||
#define BTC_TRACE_DEBUG(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(BTC,DEBUG)) BT_PRINT_D("BT_BTC", fmt, ## args);}
|
||||
#define BTC_TRACE_VERBOSE(fmt, args...) {if (BTC_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(BTC,VERBOSE)) BT_PRINT_V("BT_BTC", fmt, ## args);}
|
||||
|
||||
/* define traces for OSI */
|
||||
#define OSI_TRACE_ERROR(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(OSI, ERROR)) BT_PRINT_E("BT_OSI", fmt, ## args);}
|
||||
#define OSI_TRACE_WARNING(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(OSI, WARNING)) BT_PRINT_W("BT_OSI", fmt, ## args);}
|
||||
#define OSI_TRACE_API(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(OSI,API)) BT_PRINT_I("BT_OSI", fmt, ## args);}
|
||||
#define OSI_TRACE_EVENT(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(OSI,EVENT)) BT_PRINT_D("BT_OSI", fmt, ## args);}
|
||||
#define OSI_TRACE_DEBUG(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(OSI,DEBUG)) BT_PRINT_D("BT_OSI", fmt, ## args);}
|
||||
#define OSI_TRACE_VERBOSE(fmt, args...) {if (OSI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(OSI,VERBOSE)) BT_PRINT_V("BT_OSI", fmt, ## args);}
|
||||
|
||||
/* define traces for BLUFI */
|
||||
#define BLUFI_TRACE_ERROR(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_ERROR && BT_LOG_LEVEL_CHECK(BLUFI, ERROR)) BT_PRINT_E("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_WARNING(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_WARNING && BT_LOG_LEVEL_CHECK(BLUFI, WARNING)) BT_PRINT_W("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_API(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_API && BT_LOG_LEVEL_CHECK(BLUFI,API)) BT_PRINT_I("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_EVENT(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_EVENT && BT_LOG_LEVEL_CHECK(BLUFI,EVENT)) BT_PRINT_D("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_DEBUG(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_DEBUG && BT_LOG_LEVEL_CHECK(BLUFI,DEBUG)) BT_PRINT_D("BT_BLUFI", fmt, ## args);}
|
||||
#define BLUFI_TRACE_VERBOSE(fmt, args...) {if (BLUFI_INITIAL_TRACE_LEVEL >= BT_TRACE_LEVEL_VERBOSE && BT_LOG_LEVEL_CHECK(BLUFI,VERBOSE)) BT_PRINT_V("BT_BLUFI", fmt, ## args);}
|
||||
|
||||
#else
|
||||
|
||||
/* define traces for BTC */
|
||||
#define BTC_TRACE_ERROR(fmt, args...)
|
||||
#define BTC_TRACE_WARNING(fmt, args...)
|
||||
#define BTC_TRACE_API(fmt, args...)
|
||||
#define BTC_TRACE_EVENT(fmt, args...)
|
||||
#define BTC_TRACE_DEBUG(fmt, args...)
|
||||
#define BTC_TRACE_VERBOSE(fmt, args...)
|
||||
|
||||
/* define traces for OSI */
|
||||
#define OSI_TRACE_ERROR(fmt, args...)
|
||||
#define OSI_TRACE_WARNING(fmt, args...)
|
||||
#define OSI_TRACE_API(fmt, args...)
|
||||
#define OSI_TRACE_EVENT(fmt, args...)
|
||||
#define OSI_TRACE_DEBUG(fmt, args...)
|
||||
#define OSI_TRACE_VERBOSE(fmt, args...)
|
||||
|
||||
/* define traces for BLUFI */
|
||||
#define BLUFI_TRACE_ERROR(fmt, args...)
|
||||
#define BLUFI_TRACE_WARNING(fmt, args...)
|
||||
#define BLUFI_TRACE_API(fmt, args...)
|
||||
#define BLUFI_TRACE_EVENT(fmt, args...)
|
||||
#define BLUFI_TRACE_DEBUG(fmt, args...)
|
||||
#define BLUFI_TRACE_VERBOSE(fmt, args...)
|
||||
|
||||
#endif
|
||||
|
||||
/** Bluetooth Error Status */
|
||||
/** We need to build on this */
|
||||
|
||||
/* relate to ESP_BT_STATUS_xxx in esp_bt_defs.h */
|
||||
typedef enum {
|
||||
BT_STATUS_SUCCESS = 0,
|
||||
BT_STATUS_FAIL,
|
||||
BT_STATUS_NOT_READY,
|
||||
BT_STATUS_NOMEM,
|
||||
BT_STATUS_BUSY,
|
||||
BT_STATUS_DONE, /* request already completed */
|
||||
BT_STATUS_UNSUPPORTED,
|
||||
BT_STATUS_PARM_INVALID,
|
||||
BT_STATUS_UNHANDLED,
|
||||
BT_STATUS_AUTH_FAILURE,
|
||||
BT_STATUS_RMT_DEV_DOWN,
|
||||
BT_STATUS_AUTH_REJECTED,
|
||||
BT_STATUS_INVALID_STATIC_RAND_ADDR,
|
||||
BT_STATUS_PENDING,
|
||||
BT_STATUS_UNACCEPT_CONN_INTERVAL,
|
||||
BT_STATUS_PARAM_OUT_OF_RANGE,
|
||||
BT_STATUS_TIMEOUT,
|
||||
BT_STATUS_MEMORY_FULL,
|
||||
BT_STATUS_EIR_TOO_LARGE,
|
||||
} bt_status_t;
|
||||
|
||||
typedef uint8_t UINT8;
|
||||
typedef uint16_t UINT16;
|
||||
typedef uint32_t UINT32;
|
||||
typedef uint64_t UINT64;
|
||||
typedef bool BOOLEAN;
|
||||
/* Maximum UUID size - 16 bytes, and structure to hold any type of UUID. */
|
||||
#define MAX_UUID_SIZE 16
|
||||
|
||||
typedef struct {
|
||||
#define LEN_UUID_16 2
|
||||
#define LEN_UUID_32 4
|
||||
#define LEN_UUID_128 16
|
||||
|
||||
UINT16 len;
|
||||
|
||||
union {
|
||||
UINT16 uuid16;
|
||||
UINT32 uuid32;
|
||||
UINT8 uuid128[MAX_UUID_SIZE];
|
||||
} uu;
|
||||
|
||||
} tBT_UUID;
|
||||
|
||||
/* Common Bluetooth field definitions */
|
||||
#define BD_ADDR_LEN 6 /* Device address length */
|
||||
typedef UINT8 BD_ADDR[BD_ADDR_LEN]; /* Device address */
|
||||
|
||||
#endif /* _BT_COMMON_H_ */
|
||||
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __BT_USER_CONFIG_H__
|
||||
#define __BT_USER_CONFIG_H__
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define UC_TRACE_LEVEL_NONE 0 /* No trace messages to be generated */
|
||||
#define UC_TRACE_LEVEL_ERROR 1 /* Error condition trace messages */
|
||||
#define UC_TRACE_LEVEL_WARNING 2 /* Warning condition trace messages */
|
||||
#define UC_TRACE_LEVEL_API 3 /* API traces */
|
||||
#define UC_TRACE_LEVEL_EVENT 4 /* Debug messages for events */
|
||||
#define UC_TRACE_LEVEL_DEBUG 5 /* Full debug messages */
|
||||
#define UC_TRACE_LEVEL_VERBOSE 6 /* Verbose debug messages */
|
||||
|
||||
//DYNAMIC ENV ALLOCATOR
|
||||
#ifdef CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY
|
||||
#define UC_BT_BLE_DYNAMIC_ENV_MEMORY CONFIG_BT_BLE_DYNAMIC_ENV_MEMORY
|
||||
#else
|
||||
#define UC_BT_BLE_DYNAMIC_ENV_MEMORY FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_STACK_NO_LOG
|
||||
#define UC_BT_STACK_NO_LOG CONFIG_BT_STACK_NO_LOG
|
||||
#else
|
||||
#define UC_BT_STACK_NO_LOG FALSE
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_CONTROLLER_ENABLED
|
||||
#define UC_BT_CONTROLLER_INCLUDED TRUE
|
||||
#else
|
||||
#define UC_BT_CONTROLLER_INCLUDED FALSE
|
||||
#endif
|
||||
|
||||
/**********************************************************
|
||||
* Thread/Task reference
|
||||
**********************************************************/
|
||||
#ifdef CONFIG_BT_BLUEDROID_PINNED_TO_CORE
|
||||
#define UC_TASK_PINNED_TO_CORE (CONFIG_BT_BLUEDROID_PINNED_TO_CORE < portNUM_PROCESSORS ? CONFIG_BT_BLUEDROID_PINNED_TO_CORE : tskNO_AFFINITY)
|
||||
#else
|
||||
#define UC_TASK_PINNED_TO_CORE (0)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_BTC_TASK_STACK_SIZE
|
||||
#define UC_BTC_TASK_STACK_SIZE CONFIG_BT_BTC_TASK_STACK_SIZE
|
||||
#else
|
||||
#define UC_BTC_TASK_STACK_SIZE 4096
|
||||
#endif
|
||||
|
||||
/**********************************************************
|
||||
* Trace reference
|
||||
**********************************************************/
|
||||
|
||||
#ifdef CONFIG_LOG_DEFAULT_LEVEL
|
||||
#define UC_LOG_DEFAULT_LEVEL CONFIG_LOG_DEFAULT_LEVEL
|
||||
#else
|
||||
#define UC_LOG_DEFAULT_LEVEL 3
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BOOTLOADER_LOG_LEVEL
|
||||
#define UC_BOOTLOADER_LOG_LEVEL CONFIG_BOOTLOADER_LOG_LEVEL
|
||||
#else
|
||||
#define UC_BOOTLOADER_LOG_LEVEL 3
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_LOG_BTC_TRACE_LEVEL
|
||||
#define UC_BT_LOG_BTC_TRACE_LEVEL CONFIG_BT_LOG_BTC_TRACE_LEVEL
|
||||
#else
|
||||
#define UC_BT_LOG_BTC_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_LOG_OSI_TRACE_LEVEL
|
||||
#define UC_BT_LOG_OSI_TRACE_LEVEL CONFIG_BT_LOG_OSI_TRACE_LEVEL
|
||||
#else
|
||||
#define UC_BT_LOG_OSI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
#define UC_BT_LOG_BLUFI_TRACE_LEVEL CONFIG_BT_LOG_BLUFI_TRACE_LEVEL
|
||||
#else
|
||||
#define UC_BT_LOG_BLUFI_TRACE_LEVEL UC_TRACE_LEVEL_WARNING
|
||||
#endif
|
||||
|
||||
//BLUFI
|
||||
#if defined(CONFIG_BT_BLE_BLUFI_ENABLE) || defined(CONFIG_BT_NIMBLE_BLUFI_ENABLE)
|
||||
#define UC_BT_BLUFI_ENABLE TRUE
|
||||
#else
|
||||
#define UC_BT_BLUFI_ENABLE FALSE
|
||||
#endif
|
||||
|
||||
//MEMORY DEBUG
|
||||
#ifdef CONFIG_BT_BLUEDROID_MEM_DEBUG
|
||||
#define UC_BT_BLUEDROID_MEM_DEBUG TRUE
|
||||
#else
|
||||
#define UC_BT_BLUEDROID_MEM_DEBUG FALSE
|
||||
#endif
|
||||
|
||||
#endif /* __BT_USER_CONFIG_H__ */
|
||||
@@ -0,0 +1,331 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "osi/alarm.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/list.h"
|
||||
#include "esp_timer.h"
|
||||
#include "btc/btc_task.h"
|
||||
#include "btc/btc_alarm.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "bt_common.h"
|
||||
|
||||
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,
|
||||
ALARM_STATE_OPEN,
|
||||
};
|
||||
|
||||
static osi_mutex_t alarm_mutex;
|
||||
static int alarm_state;
|
||||
|
||||
#if (BT_BLE_DYNAMIC_ENV_MEMORY == FALSE)
|
||||
static struct alarm_t alarm_cbs[ALARM_CBS_NUM];
|
||||
#else
|
||||
static struct alarm_t *alarm_cbs;
|
||||
#endif
|
||||
|
||||
static osi_alarm_err_t alarm_free(osi_alarm_t *alarm);
|
||||
static osi_alarm_err_t alarm_set(osi_alarm_t *alarm, period_ms_t timeout, bool is_periodic);
|
||||
|
||||
int osi_alarm_create_mux(void)
|
||||
{
|
||||
if (alarm_state != ALARM_STATE_IDLE) {
|
||||
OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state);
|
||||
return -1;
|
||||
}
|
||||
osi_mutex_new(&alarm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int osi_alarm_delete_mux(void)
|
||||
{
|
||||
if (alarm_state != ALARM_STATE_IDLE) {
|
||||
OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state);
|
||||
return -1;
|
||||
}
|
||||
osi_mutex_free(&alarm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void osi_alarm_init(void)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_IDLE) {
|
||||
OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state);
|
||||
goto end;
|
||||
}
|
||||
#if (BT_BLE_DYNAMIC_ENV_MEMORY == TRUE)
|
||||
if ((alarm_cbs = (osi_alarm_t *)osi_malloc(sizeof(osi_alarm_t) * ALARM_CBS_NUM)) == NULL) {
|
||||
OSI_TRACE_ERROR("%s, malloc failed\n", __func__);
|
||||
goto end;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset(alarm_cbs, 0x00, sizeof(osi_alarm_t) * ALARM_CBS_NUM);
|
||||
alarm_state = ALARM_STATE_OPEN;
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
}
|
||||
|
||||
void osi_alarm_deinit(void)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state);
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ALARM_CBS_NUM; i++) {
|
||||
if (alarm_cbs[i].alarm_hdl != NULL) {
|
||||
alarm_free(&alarm_cbs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#if (BT_BLE_DYNAMIC_ENV_MEMORY == TRUE)
|
||||
osi_free(alarm_cbs);
|
||||
alarm_cbs = NULL;
|
||||
#endif
|
||||
|
||||
alarm_state = ALARM_STATE_IDLE;
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
}
|
||||
|
||||
static struct alarm_t *alarm_cbs_lookfor_available(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ALARM_CBS_NUM; i++) {
|
||||
if (alarm_cbs[i].alarm_hdl == NULL) { //available
|
||||
OSI_TRACE_DEBUG("%s %d %p\n", __func__, i, &alarm_cbs[i]);
|
||||
return &alarm_cbs[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void alarm_cb_handler(struct alarm_t *alarm)
|
||||
{
|
||||
OSI_TRACE_DEBUG("TimerID %p\n", alarm);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
OSI_TRACE_WARNING("%s, invalid state %d\n", __func__, alarm_state);
|
||||
return;
|
||||
}
|
||||
btc_msg_t msg = {0};
|
||||
btc_alarm_args_t arg;
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_ALARM;
|
||||
arg.cb = alarm->cb;
|
||||
arg.cb_data = alarm->cb_data;
|
||||
btc_transfer_context(&msg, &arg, sizeof(btc_alarm_args_t), NULL, NULL);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
struct alarm_t *timer_id = NULL;
|
||||
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
OSI_TRACE_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
timer_id = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
timer_id = alarm_cbs_lookfor_available();
|
||||
|
||||
if (!timer_id) {
|
||||
OSI_TRACE_ERROR("%s alarm_cbs exhausted\n", __func__);
|
||||
timer_id = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
esp_timer_create_args_t tca = {0};
|
||||
tca.callback = (esp_timer_cb_t)alarm_cb_handler;
|
||||
tca.arg = timer_id;
|
||||
tca.dispatch_method = ESP_TIMER_TASK;
|
||||
tca.name = alarm_name;
|
||||
|
||||
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) {
|
||||
OSI_TRACE_ERROR("%s failed to create timer, err 0x%x\n", __func__, stat);
|
||||
timer_id = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return timer_id;
|
||||
}
|
||||
|
||||
static osi_alarm_err_t alarm_free(osi_alarm_t *alarm)
|
||||
{
|
||||
if (!alarm || alarm->alarm_hdl == NULL) {
|
||||
OSI_TRACE_ERROR("%s null\n", __func__);
|
||||
return OSI_ALARM_ERR_INVALID_ARG;
|
||||
}
|
||||
esp_timer_stop(alarm->alarm_hdl);
|
||||
esp_err_t stat = esp_timer_delete(alarm->alarm_hdl);
|
||||
if (stat != ESP_OK) {
|
||||
OSI_TRACE_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 OSI_ALARM_ERR_PASS;
|
||||
}
|
||||
|
||||
void osi_alarm_free(osi_alarm_t *alarm)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
OSI_TRACE_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
goto end;
|
||||
}
|
||||
alarm_free(alarm);
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
static osi_alarm_err_t alarm_set(osi_alarm_t *alarm, period_ms_t timeout, bool is_periodic)
|
||||
{
|
||||
assert(alarm_mutex != NULL);
|
||||
|
||||
osi_alarm_err_t ret = OSI_ALARM_ERR_PASS;
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
OSI_TRACE_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
ret = OSI_ALARM_ERR_INVALID_STATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!alarm || alarm->alarm_hdl == NULL) {
|
||||
OSI_TRACE_ERROR("%s null\n", __func__);
|
||||
ret = OSI_ALARM_ERR_INVALID_ARG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int64_t timeout_us = 1000 * (int64_t)timeout;
|
||||
esp_err_t stat;
|
||||
if (is_periodic) {
|
||||
stat = esp_timer_start_periodic(alarm->alarm_hdl, (uint64_t)timeout_us);
|
||||
} else {
|
||||
stat = esp_timer_start_once(alarm->alarm_hdl, (uint64_t)timeout_us);
|
||||
}
|
||||
if (stat != ESP_OK) {
|
||||
OSI_TRACE_ERROR("%s failed to start timer, err 0x%x\n", __func__, stat);
|
||||
ret = OSI_ALARM_ERR_FAIL;
|
||||
goto end;
|
||||
}
|
||||
alarm->deadline_us = is_periodic ? 0 : (timeout_us + esp_timer_get_time());
|
||||
|
||||
end:
|
||||
osi_mutex_unlock(&alarm_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
osi_alarm_err_t osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout)
|
||||
{
|
||||
return alarm_set(alarm, timeout, FALSE);
|
||||
}
|
||||
|
||||
osi_alarm_err_t osi_alarm_set_periodic(osi_alarm_t *alarm, period_ms_t period)
|
||||
{
|
||||
return alarm_set(alarm, period, TRUE);
|
||||
}
|
||||
|
||||
osi_alarm_err_t osi_alarm_cancel(osi_alarm_t *alarm)
|
||||
{
|
||||
int ret = OSI_ALARM_ERR_PASS;
|
||||
osi_mutex_lock(&alarm_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (alarm_state != ALARM_STATE_OPEN) {
|
||||
OSI_TRACE_ERROR("%s, invalid state %d\n", __func__, alarm_state);
|
||||
ret = OSI_ALARM_ERR_INVALID_STATE;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!alarm || alarm->alarm_hdl == NULL) {
|
||||
OSI_TRACE_ERROR("%s null\n", __func__);
|
||||
ret = OSI_ALARM_ERR_INVALID_ARG;
|
||||
goto end;
|
||||
}
|
||||
|
||||
esp_err_t stat = esp_timer_stop(alarm->alarm_hdl);
|
||||
if (stat != ESP_OK) {
|
||||
OSI_TRACE_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;
|
||||
}
|
||||
|
||||
period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm)
|
||||
{
|
||||
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);
|
||||
|
||||
return (dt_us > 0) ? (period_ms_t)(dt_us / 1000) : 0;
|
||||
}
|
||||
|
||||
uint32_t osi_time_get_os_boottime_ms(void)
|
||||
{
|
||||
return (uint32_t)(esp_timer_get_time() / 1000);
|
||||
}
|
||||
|
||||
bool osi_alarm_is_active(osi_alarm_t *alarm)
|
||||
{
|
||||
assert(alarm != NULL);
|
||||
|
||||
if (alarm->alarm_hdl != NULL) {
|
||||
return esp_timer_is_active(alarm->alarm_hdl);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bt_common.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
extern void *pvPortZalloc(size_t size);
|
||||
extern void vPortFree(void *pv);
|
||||
|
||||
|
||||
#if HEAP_MEMORY_DEBUG
|
||||
|
||||
#define OSI_MEM_DBG_INFO_MAX 1024*3
|
||||
typedef struct {
|
||||
void *p;
|
||||
int size;
|
||||
const char *func;
|
||||
int line;
|
||||
} osi_mem_dbg_info_t;
|
||||
|
||||
static uint32_t mem_dbg_count = 0;
|
||||
static osi_mem_dbg_info_t mem_dbg_info[OSI_MEM_DBG_INFO_MAX];
|
||||
static uint32_t mem_dbg_current_size = 0;
|
||||
static uint32_t mem_dbg_max_size = 0;
|
||||
|
||||
#define OSI_MEM_DBG_MAX_SECTION_NUM 5
|
||||
typedef struct {
|
||||
bool used;
|
||||
uint32_t max_size;
|
||||
} osi_mem_dbg_max_size_section_t;
|
||||
static osi_mem_dbg_max_size_section_t mem_dbg_max_size_section[OSI_MEM_DBG_MAX_SECTION_NUM];
|
||||
|
||||
void osi_mem_dbg_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OSI_MEM_DBG_INFO_MAX; i++) {
|
||||
mem_dbg_info[i].p = NULL;
|
||||
mem_dbg_info[i].size = 0;
|
||||
mem_dbg_info[i].func = NULL;
|
||||
mem_dbg_info[i].line = 0;
|
||||
}
|
||||
mem_dbg_count = 0;
|
||||
mem_dbg_current_size = 0;
|
||||
mem_dbg_max_size = 0;
|
||||
|
||||
for (i = 0; i < OSI_MEM_DBG_MAX_SECTION_NUM; i++){
|
||||
mem_dbg_max_size_section[i].used = false;
|
||||
mem_dbg_max_size_section[i].max_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void osi_mem_dbg_record(void *p, int size, const char *func, int line)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!p || size == 0) {
|
||||
OSI_TRACE_ERROR("%s invalid !!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < OSI_MEM_DBG_INFO_MAX; i++) {
|
||||
if (mem_dbg_info[i].p == NULL) {
|
||||
mem_dbg_info[i].p = p;
|
||||
mem_dbg_info[i].size = size;
|
||||
mem_dbg_info[i].func = func;
|
||||
mem_dbg_info[i].line = line;
|
||||
mem_dbg_count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= OSI_MEM_DBG_INFO_MAX) {
|
||||
OSI_TRACE_ERROR("%s full %s %d !!\n", __func__, func, line);
|
||||
}
|
||||
|
||||
mem_dbg_current_size += size;
|
||||
if(mem_dbg_max_size < mem_dbg_current_size) {
|
||||
mem_dbg_max_size = mem_dbg_current_size;
|
||||
}
|
||||
|
||||
for (i = 0; i < OSI_MEM_DBG_MAX_SECTION_NUM; i++){
|
||||
if (mem_dbg_max_size_section[i].used) {
|
||||
if(mem_dbg_max_size_section[i].max_size < mem_dbg_current_size) {
|
||||
mem_dbg_max_size_section[i].max_size = mem_dbg_current_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void osi_mem_dbg_clean(void *p, const char *func, int line)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!p) {
|
||||
OSI_TRACE_ERROR("%s invalid\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < OSI_MEM_DBG_INFO_MAX; i++) {
|
||||
if (mem_dbg_info[i].p == p) {
|
||||
mem_dbg_current_size -= mem_dbg_info[i].size;
|
||||
mem_dbg_info[i].p = NULL;
|
||||
mem_dbg_info[i].size = 0;
|
||||
mem_dbg_info[i].func = NULL;
|
||||
mem_dbg_info[i].line = 0;
|
||||
mem_dbg_count--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= OSI_MEM_DBG_INFO_MAX) {
|
||||
OSI_TRACE_ERROR("%s full %s %d !!\n", __func__, func, line);
|
||||
}
|
||||
}
|
||||
|
||||
void osi_mem_dbg_show(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < OSI_MEM_DBG_INFO_MAX; i++) {
|
||||
if (mem_dbg_info[i].p || mem_dbg_info[i].size != 0 ) {
|
||||
OSI_TRACE_ERROR("--> p %p, s %d, f %s, l %d\n", mem_dbg_info[i].p, mem_dbg_info[i].size, mem_dbg_info[i].func, mem_dbg_info[i].line);
|
||||
}
|
||||
}
|
||||
OSI_TRACE_ERROR("--> count %d\n", mem_dbg_count);
|
||||
OSI_TRACE_ERROR("--> size %dB\n--> max size %dB\n", mem_dbg_current_size, mem_dbg_max_size);
|
||||
}
|
||||
|
||||
uint32_t osi_mem_dbg_get_max_size(void)
|
||||
{
|
||||
return mem_dbg_max_size;
|
||||
}
|
||||
|
||||
uint32_t osi_mem_dbg_get_current_size(void)
|
||||
{
|
||||
return mem_dbg_current_size;
|
||||
}
|
||||
|
||||
void osi_men_dbg_set_section_start(uint8_t index)
|
||||
{
|
||||
if (index >= OSI_MEM_DBG_MAX_SECTION_NUM) {
|
||||
OSI_TRACE_ERROR("Then range of index should be between 0 and %d, current index is %d.\n",
|
||||
OSI_MEM_DBG_MAX_SECTION_NUM - 1, index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mem_dbg_max_size_section[index].used) {
|
||||
OSI_TRACE_WARNING("This index(%d) has been started, restart it.\n", index);
|
||||
}
|
||||
|
||||
mem_dbg_max_size_section[index].used = true;
|
||||
mem_dbg_max_size_section[index].max_size = mem_dbg_current_size;
|
||||
}
|
||||
|
||||
void osi_men_dbg_set_section_end(uint8_t index)
|
||||
{
|
||||
if (index >= OSI_MEM_DBG_MAX_SECTION_NUM) {
|
||||
OSI_TRACE_ERROR("Then range of index should be between 0 and %d, current index is %d.\n",
|
||||
OSI_MEM_DBG_MAX_SECTION_NUM - 1, index);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mem_dbg_max_size_section[index].used) {
|
||||
OSI_TRACE_ERROR("This index(%d) has not been started.\n", index);
|
||||
return;
|
||||
}
|
||||
|
||||
mem_dbg_max_size_section[index].used = false;
|
||||
}
|
||||
|
||||
uint32_t osi_mem_dbg_get_max_size_section(uint8_t index)
|
||||
{
|
||||
if (index >= OSI_MEM_DBG_MAX_SECTION_NUM){
|
||||
OSI_TRACE_ERROR("Then range of index should be between 0 and %d, current index is %d.\n",
|
||||
OSI_MEM_DBG_MAX_SECTION_NUM - 1, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return mem_dbg_max_size_section[index].max_size;
|
||||
}
|
||||
#endif
|
||||
|
||||
char *osi_strdup(const char *str)
|
||||
{
|
||||
size_t size = strlen(str) + 1; // + 1 for the null terminator
|
||||
char *new_string = (char *)osi_calloc(size);
|
||||
|
||||
if (!new_string) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(new_string, str, size);
|
||||
return new_string;
|
||||
}
|
||||
|
||||
void *osi_malloc_func(size_t size)
|
||||
{
|
||||
#if HEAP_MEMORY_DEBUG
|
||||
void *p;
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
p = heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
|
||||
#else
|
||||
p = malloc(size);
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__);
|
||||
return p;
|
||||
#else
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
return heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
|
||||
#else
|
||||
return malloc(size);
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */
|
||||
#endif /* #if HEAP_MEMORY_DEBUG */
|
||||
}
|
||||
|
||||
void *osi_calloc_func(size_t size)
|
||||
{
|
||||
#if HEAP_MEMORY_DEBUG
|
||||
void *p;
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
p = heap_caps_calloc_prefer(1, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
|
||||
#else
|
||||
p = calloc(1, size);
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__);
|
||||
return p;
|
||||
#else
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
return heap_caps_calloc_prefer(1, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL);
|
||||
#else
|
||||
return calloc(1, size);
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */
|
||||
#endif /* #if HEAP_MEMORY_DEBUG */
|
||||
}
|
||||
|
||||
void osi_free_func(void *ptr)
|
||||
{
|
||||
#if HEAP_MEMORY_DEBUG
|
||||
osi_mem_dbg_clean(ptr, __func__, __LINE__);
|
||||
#endif
|
||||
free(ptr);
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
#include <stdint.h>
|
||||
#include "bt_common.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/buffer.h"
|
||||
|
||||
struct buffer_t {
|
||||
buffer_t *root;
|
||||
size_t refcount;
|
||||
size_t length;
|
||||
uint8_t data[];
|
||||
};
|
||||
|
||||
buffer_t *buffer_new(size_t size)
|
||||
{
|
||||
assert(size > 0);
|
||||
|
||||
buffer_t *buffer = osi_malloc(sizeof(buffer_t) + size);
|
||||
if (!buffer) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate buffer of %zu bytes.", __func__, size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buffer->root = buffer;
|
||||
buffer->refcount = 1;
|
||||
buffer->length = size;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
buffer_t *buffer_new_ref(const buffer_t *buf)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
return buffer_new_slice(buf, buf->length);
|
||||
}
|
||||
|
||||
buffer_t *buffer_new_slice(const buffer_t *buf, size_t slice_size)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
assert(slice_size > 0);
|
||||
assert(slice_size <= buf->length);
|
||||
|
||||
buffer_t *ret = osi_calloc(sizeof(buffer_t));
|
||||
if (!ret) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate new buffer for slice of length %zu.", __func__, slice_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->root = buf->root;
|
||||
ret->refcount = SIZE_MAX;
|
||||
ret->length = slice_size;
|
||||
|
||||
++buf->root->refcount;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void buffer_free(buffer_t *buffer)
|
||||
{
|
||||
if (!buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer->root != buffer) {
|
||||
// We're a leaf node. Delete the root node if we're the last referent.
|
||||
if (--buffer->root->refcount == 0) {
|
||||
osi_free(buffer->root);
|
||||
}
|
||||
osi_free(buffer);
|
||||
} else if (--buffer->refcount == 0) {
|
||||
// We're a root node. Roots are only deleted when their refcount goes to 0.
|
||||
osi_free(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void *buffer_ptr(const buffer_t *buf)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
return buf->root->data + buf->root->length - buf->length;
|
||||
}
|
||||
|
||||
size_t buffer_length(const buffer_t *buf)
|
||||
{
|
||||
assert(buf != NULL);
|
||||
return buf->length;
|
||||
}
|
||||
@@ -0,0 +1,740 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define LOG_TAG "bt_osi_config"
|
||||
#include "esp_system.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bt_common.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/config.h"
|
||||
#include "osi/list.h"
|
||||
|
||||
#define CONFIG_FILE_MAX_SIZE (1536)//1.5k
|
||||
#define CONFIG_FILE_DEFAULE_LENGTH (2048)
|
||||
#define CONFIG_KEY "bt_cfg_key"
|
||||
typedef struct {
|
||||
char *key;
|
||||
char *value;
|
||||
} entry_t;
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
list_t *entries;
|
||||
} section_t;
|
||||
|
||||
struct config_t {
|
||||
list_t *sections;
|
||||
};
|
||||
|
||||
// Empty definition; this type is aliased to list_node_t.
|
||||
struct config_section_iter_t {};
|
||||
|
||||
static void config_parse(nvs_handle_t fp, config_t *config);
|
||||
|
||||
static section_t *section_new(const char *name);
|
||||
static void section_free(void *ptr);
|
||||
static section_t *section_find(const config_t *config, const char *section);
|
||||
|
||||
static entry_t *entry_new(const char *key, const char *value);
|
||||
static void entry_free(void *ptr);
|
||||
static entry_t *entry_find(const config_t *config, const char *section, const char *key);
|
||||
|
||||
config_t *config_new_empty(void)
|
||||
{
|
||||
config_t *config = osi_calloc(sizeof(config_t));
|
||||
if (!config) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate memory for config_t.\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
config->sections = list_new(section_free);
|
||||
if (!config->sections) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate list for sections.\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return config;
|
||||
|
||||
error:;
|
||||
config_free(config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config_t *config_new(const char *filename)
|
||||
{
|
||||
assert(filename != NULL);
|
||||
|
||||
config_t *config = config_new_empty();
|
||||
if (!config) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t err;
|
||||
nvs_handle_t fp;
|
||||
err = nvs_open(filename, NVS_READWRITE, &fp);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NVS_NOT_INITIALIZED) {
|
||||
OSI_TRACE_ERROR("%s: NVS not initialized. "
|
||||
"Call nvs_flash_init before initializing bluetooth.", __func__);
|
||||
} else {
|
||||
OSI_TRACE_ERROR("%s unable to open NVS namespace '%s'\n", __func__, filename);
|
||||
}
|
||||
config_free(config);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
config_parse(fp, config);
|
||||
nvs_close(fp);
|
||||
return config;
|
||||
}
|
||||
|
||||
void config_free(config_t *config)
|
||||
{
|
||||
if (!config) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_free(config->sections);
|
||||
osi_free(config);
|
||||
}
|
||||
|
||||
bool config_has_section(const config_t *config, const char *section)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
|
||||
return (section_find(config, section) != NULL);
|
||||
}
|
||||
|
||||
bool config_has_key(const config_t *config, const char *section, const char *key)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
return (entry_find(config, section, key) != NULL);
|
||||
}
|
||||
|
||||
bool config_has_key_in_section(config_t *config, const char *key, char *key_value)
|
||||
{
|
||||
OSI_TRACE_DEBUG("key = %s, value = %s", key, key_value);
|
||||
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
|
||||
const section_t *section = (const section_t *)list_node(node);
|
||||
|
||||
for (const list_node_t *node = list_begin(section->entries); node != list_end(section->entries); node = list_next(node)) {
|
||||
entry_t *entry = list_node(node);
|
||||
OSI_TRACE_DEBUG("entry->key = %s, entry->value = %s", entry->key, entry->value);
|
||||
if (!strcmp(entry->key, key) && !strcmp(entry->value, key_value)) {
|
||||
OSI_TRACE_DEBUG("%s, the irk aready in the flash.", __func__);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int config_get_int(const config_t *config, const char *section, const char *key, int def_value)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
entry_t *entry = entry_find(config, section, key);
|
||||
if (!entry) {
|
||||
return def_value;
|
||||
}
|
||||
|
||||
char *endptr;
|
||||
int ret = strtol(entry->value, &endptr, 0);
|
||||
return (*endptr == '\0') ? ret : def_value;
|
||||
}
|
||||
|
||||
bool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
entry_t *entry = entry_find(config, section, key);
|
||||
if (!entry) {
|
||||
return def_value;
|
||||
}
|
||||
|
||||
if (!strcmp(entry->value, "true")) {
|
||||
return true;
|
||||
}
|
||||
if (!strcmp(entry->value, "false")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return def_value;
|
||||
}
|
||||
|
||||
const char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
entry_t *entry = entry_find(config, section, key);
|
||||
if (!entry) {
|
||||
return def_value;
|
||||
}
|
||||
|
||||
return entry->value;
|
||||
}
|
||||
|
||||
void config_set_int(config_t *config, const char *section, const char *key, int value)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
char value_str[32] = { 0 };
|
||||
sprintf(value_str, "%d", value);
|
||||
config_set_string(config, section, key, value_str, false);
|
||||
}
|
||||
|
||||
void config_set_bool(config_t *config, const char *section, const char *key, bool value)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
|
||||
config_set_string(config, section, key, value ? "true" : "false", false);
|
||||
}
|
||||
|
||||
void config_set_string(config_t *config, const char *section, const char *key, const char *value, bool insert_back)
|
||||
{
|
||||
section_t *sec = section_find(config, section);
|
||||
if (!sec) {
|
||||
sec = section_new(section);
|
||||
if (insert_back) {
|
||||
list_append(config->sections, sec);
|
||||
} else {
|
||||
list_prepend(config->sections, sec);
|
||||
}
|
||||
}
|
||||
|
||||
for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
|
||||
entry_t *entry = list_node(node);
|
||||
if (!strcmp(entry->key, key)) {
|
||||
osi_free(entry->value);
|
||||
entry->value = osi_strdup(value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
entry_t *entry = entry_new(key, value);
|
||||
list_append(sec->entries, entry);
|
||||
}
|
||||
|
||||
bool config_remove_section(config_t *config, const char *section)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
|
||||
section_t *sec = section_find(config, section);
|
||||
if (!sec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return list_remove(config->sections, sec);
|
||||
}
|
||||
|
||||
bool config_update_newest_section(config_t *config, const char *section)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
|
||||
list_node_t *first_node = list_begin(config->sections);
|
||||
if (first_node == NULL) {
|
||||
return false;
|
||||
}
|
||||
section_t *first_sec = list_node(first_node);
|
||||
if (strcmp(first_sec->name, section) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
|
||||
section_t *sec = list_node(node);
|
||||
if (strcmp(sec->name, section) == 0) {
|
||||
list_delete(config->sections, sec);
|
||||
list_prepend(config->sections, sec);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool config_remove_key(config_t *config, const char *section, const char *key)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(section != NULL);
|
||||
assert(key != NULL);
|
||||
bool ret;
|
||||
|
||||
section_t *sec = section_find(config, section);
|
||||
entry_t *entry = entry_find(config, section, key);
|
||||
if (!sec || !entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = list_remove(sec->entries, entry);
|
||||
if (list_length(sec->entries) == 0) {
|
||||
OSI_TRACE_DEBUG("%s remove section name:%s",__func__, section);
|
||||
ret &= config_remove_section(config, section);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const config_section_node_t *config_section_begin(const config_t *config)
|
||||
{
|
||||
assert(config != NULL);
|
||||
return (const config_section_node_t *)list_begin(config->sections);
|
||||
}
|
||||
|
||||
const config_section_node_t *config_section_end(const config_t *config)
|
||||
{
|
||||
assert(config != NULL);
|
||||
return (const config_section_node_t *)list_end(config->sections);
|
||||
}
|
||||
|
||||
const config_section_node_t *config_section_next(const config_section_node_t *node)
|
||||
{
|
||||
assert(node != NULL);
|
||||
return (const config_section_node_t *)list_next((const list_node_t *)node);
|
||||
}
|
||||
|
||||
const char *config_section_name(const config_section_node_t *node)
|
||||
{
|
||||
assert(node != NULL);
|
||||
const list_node_t *lnode = (const list_node_t *)node;
|
||||
const section_t *section = (const section_t *)list_node(lnode);
|
||||
return section->name;
|
||||
}
|
||||
|
||||
static int get_config_size(const config_t *config)
|
||||
{
|
||||
assert(config != NULL);
|
||||
|
||||
int w_len = 0, total_size = 0;
|
||||
|
||||
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
|
||||
const section_t *section = (const section_t *)list_node(node);
|
||||
w_len = strlen(section->name) + strlen("[]\n");// format "[section->name]\n"
|
||||
total_size += w_len;
|
||||
|
||||
for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) {
|
||||
const entry_t *entry = (const entry_t *)list_node(enode);
|
||||
w_len = strlen(entry->key) + strlen(entry->value) + strlen(" = \n");// format "entry->key = entry->value\n"
|
||||
total_size += w_len;
|
||||
}
|
||||
|
||||
// Only add a separating newline if there are more sections.
|
||||
if (list_next(node) != list_end(config->sections)) {
|
||||
total_size ++; //'\n'
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
total_size ++; //'\0'
|
||||
return total_size;
|
||||
}
|
||||
|
||||
static int get_config_size_from_flash(nvs_handle_t fp)
|
||||
{
|
||||
assert(fp != 0);
|
||||
|
||||
esp_err_t err;
|
||||
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
|
||||
char *keyname = osi_calloc(keyname_bufsz);
|
||||
if (!keyname){
|
||||
OSI_TRACE_ERROR("%s, malloc error\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
size_t length = CONFIG_FILE_DEFAULE_LENGTH;
|
||||
size_t total_length = 0;
|
||||
uint16_t i = 0;
|
||||
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
|
||||
err = nvs_get_blob(fp, keyname, NULL, &length);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
osi_free(keyname);
|
||||
return 0;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
OSI_TRACE_ERROR("%s, error %d\n", __func__, err);
|
||||
osi_free(keyname);
|
||||
return 0;
|
||||
}
|
||||
total_length += length;
|
||||
while (length == CONFIG_FILE_MAX_SIZE) {
|
||||
length = CONFIG_FILE_DEFAULE_LENGTH;
|
||||
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, ++i);
|
||||
err = nvs_get_blob(fp, keyname, NULL, &length);
|
||||
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
OSI_TRACE_ERROR("%s, error %d\n", __func__, err);
|
||||
osi_free(keyname);
|
||||
return 0;
|
||||
}
|
||||
total_length += length;
|
||||
}
|
||||
osi_free(keyname);
|
||||
return total_length;
|
||||
}
|
||||
|
||||
bool config_save(const config_t *config, const char *filename)
|
||||
{
|
||||
assert(config != NULL);
|
||||
assert(filename != NULL);
|
||||
assert(*filename != '\0');
|
||||
|
||||
esp_err_t err;
|
||||
int err_code = 0;
|
||||
nvs_handle_t fp;
|
||||
char *line = osi_calloc(1024);
|
||||
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
|
||||
char *keyname = osi_calloc(keyname_bufsz);
|
||||
int config_size = get_config_size(config);
|
||||
char *buf = osi_calloc(config_size);
|
||||
if (!line || !buf || !keyname) {
|
||||
err_code |= 0x01;
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = nvs_open(filename, NVS_READWRITE, &fp);
|
||||
if (err != ESP_OK) {
|
||||
if (err == ESP_ERR_NVS_NOT_INITIALIZED) {
|
||||
OSI_TRACE_ERROR("%s: NVS not initialized. "
|
||||
"Call nvs_flash_init before initializing bluetooth.", __func__);
|
||||
}
|
||||
err_code |= 0x02;
|
||||
goto error;
|
||||
}
|
||||
|
||||
int w_cnt, w_cnt_total = 0;
|
||||
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
|
||||
const section_t *section = (const section_t *)list_node(node);
|
||||
w_cnt = snprintf(line, 1024, "[%s]\n", section->name);
|
||||
if(w_cnt < 0) {
|
||||
OSI_TRACE_ERROR("snprintf error w_cnt %d.",w_cnt);
|
||||
err_code |= 0x10;
|
||||
goto error;
|
||||
}
|
||||
if(w_cnt_total + w_cnt > config_size) {
|
||||
OSI_TRACE_ERROR("%s, memcpy size (w_cnt + w_cnt_total = %d) is larger than buffer size (config_size = %d).", __func__, (w_cnt + w_cnt_total), config_size);
|
||||
err_code |= 0x20;
|
||||
goto error;
|
||||
}
|
||||
OSI_TRACE_DEBUG("section name: %s, w_cnt + w_cnt_total = %d\n", section->name, w_cnt + w_cnt_total);
|
||||
memcpy(buf + w_cnt_total, line, w_cnt);
|
||||
w_cnt_total += w_cnt;
|
||||
|
||||
for (const list_node_t *enode = list_begin(section->entries); enode != list_end(section->entries); enode = list_next(enode)) {
|
||||
const entry_t *entry = (const entry_t *)list_node(enode);
|
||||
OSI_TRACE_DEBUG("(key, val): (%s, %s)\n", entry->key, entry->value);
|
||||
w_cnt = snprintf(line, 1024, "%s = %s\n", entry->key, entry->value);
|
||||
if(w_cnt < 0) {
|
||||
OSI_TRACE_ERROR("snprintf error w_cnt %d.",w_cnt);
|
||||
err_code |= 0x10;
|
||||
goto error;
|
||||
}
|
||||
if(w_cnt_total + w_cnt > config_size) {
|
||||
OSI_TRACE_ERROR("%s, memcpy size (w_cnt + w_cnt_total = %d) is larger than buffer size.(config_size = %d)", __func__, (w_cnt + w_cnt_total), config_size);
|
||||
err_code |= 0x20;
|
||||
goto error;
|
||||
}
|
||||
OSI_TRACE_DEBUG("%s, w_cnt + w_cnt_total = %d", __func__, w_cnt + w_cnt_total);
|
||||
memcpy(buf + w_cnt_total, line, w_cnt);
|
||||
w_cnt_total += w_cnt;
|
||||
}
|
||||
|
||||
// Only add a separating newline if there are more sections.
|
||||
if (list_next(node) != list_end(config->sections)) {
|
||||
buf[w_cnt_total] = '\n';
|
||||
w_cnt_total += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[w_cnt_total] = '\0';
|
||||
if (w_cnt_total < CONFIG_FILE_MAX_SIZE) {
|
||||
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
|
||||
err = nvs_set_blob(fp, keyname, buf, w_cnt_total);
|
||||
if (err != ESP_OK) {
|
||||
nvs_close(fp);
|
||||
err_code |= 0x04;
|
||||
goto error;
|
||||
}
|
||||
}else {
|
||||
int count = (w_cnt_total / CONFIG_FILE_MAX_SIZE);
|
||||
assert(count <= 0xFF);
|
||||
for (uint8_t i = 0; i <= count; i++)
|
||||
{
|
||||
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, i);
|
||||
if (i == count) {
|
||||
err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, w_cnt_total - i*CONFIG_FILE_MAX_SIZE);
|
||||
OSI_TRACE_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, w_cnt_total - i*CONFIG_FILE_MAX_SIZE);
|
||||
}else {
|
||||
err = nvs_set_blob(fp, keyname, buf + i*CONFIG_FILE_MAX_SIZE, CONFIG_FILE_MAX_SIZE);
|
||||
OSI_TRACE_DEBUG("save keyname = %s, i = %d, %d\n", keyname, i, CONFIG_FILE_MAX_SIZE);
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
nvs_close(fp);
|
||||
err_code |= 0x04;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = nvs_commit(fp);
|
||||
if (err != ESP_OK) {
|
||||
nvs_close(fp);
|
||||
err_code |= 0x08;
|
||||
goto error;
|
||||
}
|
||||
|
||||
nvs_close(fp);
|
||||
osi_free(line);
|
||||
osi_free(buf);
|
||||
osi_free(keyname);
|
||||
return true;
|
||||
|
||||
error:
|
||||
if (buf) {
|
||||
osi_free(buf);
|
||||
}
|
||||
if (line) {
|
||||
osi_free(line);
|
||||
}
|
||||
if (keyname) {
|
||||
osi_free(keyname);
|
||||
}
|
||||
if (err_code) {
|
||||
OSI_TRACE_ERROR("%s, err_code: 0x%x\n", __func__, err_code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *trim(char *str)
|
||||
{
|
||||
while (isspace((unsigned char)(*str))) {
|
||||
++str;
|
||||
}
|
||||
|
||||
if (!*str) {
|
||||
return str;
|
||||
}
|
||||
|
||||
char *end_str = str + strlen(str) - 1;
|
||||
while (end_str > str && isspace((unsigned char)(*end_str))) {
|
||||
--end_str;
|
||||
}
|
||||
|
||||
end_str[1] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
static void config_parse(nvs_handle_t fp, config_t *config)
|
||||
{
|
||||
assert(fp != 0);
|
||||
assert(config != NULL);
|
||||
|
||||
esp_err_t err;
|
||||
int line_num = 0;
|
||||
int err_code = 0;
|
||||
uint16_t i = 0;
|
||||
size_t length = CONFIG_FILE_DEFAULE_LENGTH;
|
||||
size_t total_length = 0;
|
||||
char *line = osi_calloc(1024);
|
||||
char *section = osi_calloc(1024);
|
||||
const size_t keyname_bufsz = sizeof(CONFIG_KEY) + 5 + 1; // including log10(sizeof(i))
|
||||
char *keyname = osi_calloc(keyname_bufsz);
|
||||
int buf_size = get_config_size_from_flash(fp);
|
||||
char *buf = NULL;
|
||||
|
||||
if(buf_size == 0) { //First use nvs
|
||||
goto error;
|
||||
}
|
||||
buf = osi_calloc(buf_size);
|
||||
if (!line || !section || !buf || !keyname) {
|
||||
err_code |= 0x01;
|
||||
goto error;
|
||||
}
|
||||
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, 0);
|
||||
err = nvs_get_blob(fp, keyname, buf, &length);
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
goto error;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
err_code |= 0x02;
|
||||
goto error;
|
||||
}
|
||||
total_length += length;
|
||||
while (length == CONFIG_FILE_MAX_SIZE) {
|
||||
length = CONFIG_FILE_DEFAULE_LENGTH;
|
||||
snprintf(keyname, keyname_bufsz, "%s%d", CONFIG_KEY, ++i);
|
||||
err = nvs_get_blob(fp, keyname, buf + CONFIG_FILE_MAX_SIZE * i, &length);
|
||||
|
||||
if (err == ESP_ERR_NVS_NOT_FOUND) {
|
||||
break;
|
||||
}
|
||||
if (err != ESP_OK) {
|
||||
err_code |= 0x02;
|
||||
goto error;
|
||||
}
|
||||
total_length += length;
|
||||
}
|
||||
char *p_line_end;
|
||||
char *p_line_bgn = buf;
|
||||
strcpy(section, CONFIG_DEFAULT_SECTION);
|
||||
|
||||
while ( (p_line_bgn < buf + total_length - 1) && (p_line_end = strchr(p_line_bgn, '\n'))) {
|
||||
|
||||
// get one line
|
||||
int line_len = p_line_end - p_line_bgn;
|
||||
if (line_len > 1023) {
|
||||
OSI_TRACE_WARNING("%s exceed max line length on line %d.\n", __func__, line_num);
|
||||
break;
|
||||
}
|
||||
memcpy(line, p_line_bgn, line_len);
|
||||
line[line_len] = '\0';
|
||||
p_line_bgn = p_line_end + 1;
|
||||
char *line_ptr = trim(line);
|
||||
++line_num;
|
||||
|
||||
// Skip blank and comment lines.
|
||||
if (*line_ptr == '\0' || *line_ptr == '#') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*line_ptr == '[') {
|
||||
size_t len = strlen(line_ptr);
|
||||
if (line_ptr[len - 1] != ']') {
|
||||
OSI_TRACE_WARNING("%s unterminated section name on line %d.\n", __func__, line_num);
|
||||
continue;
|
||||
}
|
||||
strncpy(section, line_ptr + 1, len - 2);
|
||||
section[len - 2] = '\0';
|
||||
} else {
|
||||
char *split = strchr(line_ptr, '=');
|
||||
if (!split) {
|
||||
OSI_TRACE_DEBUG("%s no key/value separator found on line %d.\n", __func__, line_num);
|
||||
continue;
|
||||
}
|
||||
*split = '\0';
|
||||
config_set_string(config, section, trim(line_ptr), trim(split + 1), true);
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
if (buf) {
|
||||
osi_free(buf);
|
||||
}
|
||||
if (line) {
|
||||
osi_free(line);
|
||||
}
|
||||
if (section) {
|
||||
osi_free(section);
|
||||
}
|
||||
if (keyname) {
|
||||
osi_free(keyname);
|
||||
}
|
||||
if (err_code) {
|
||||
OSI_TRACE_ERROR("%s returned with err code: %d\n", __func__, err_code);
|
||||
}
|
||||
}
|
||||
|
||||
static section_t *section_new(const char *name)
|
||||
{
|
||||
section_t *section = osi_calloc(sizeof(section_t));
|
||||
if (!section) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
section->name = osi_strdup(name);
|
||||
section->entries = list_new(entry_free);
|
||||
return section;
|
||||
}
|
||||
|
||||
static void section_free(void *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
section_t *section = ptr;
|
||||
osi_free(section->name);
|
||||
list_free(section->entries);
|
||||
osi_free(section);
|
||||
}
|
||||
|
||||
static section_t *section_find(const config_t *config, const char *section)
|
||||
{
|
||||
for (const list_node_t *node = list_begin(config->sections); node != list_end(config->sections); node = list_next(node)) {
|
||||
section_t *sec = list_node(node);
|
||||
if (!strcmp(sec->name, section)) {
|
||||
return sec;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static entry_t *entry_new(const char *key, const char *value)
|
||||
{
|
||||
entry_t *entry = osi_calloc(sizeof(entry_t));
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
entry->key = osi_strdup(key);
|
||||
entry->value = osi_strdup(value);
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void entry_free(void *ptr)
|
||||
{
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
entry_t *entry = ptr;
|
||||
osi_free(entry->key);
|
||||
osi_free(entry->value);
|
||||
osi_free(entry);
|
||||
}
|
||||
|
||||
static entry_t *entry_find(const config_t *config, const char *section, const char *key)
|
||||
{
|
||||
section_t *sec = section_find(config, section);
|
||||
if (!sec) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (const list_node_t *node = list_begin(sec->entries); node != list_end(sec->entries); node = list_next(node)) {
|
||||
entry_t *entry = list_node(node);
|
||||
if (!strcmp(entry->key, key)) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/pkt_queue.h"
|
||||
#include "osi/fixed_pkt_queue.h"
|
||||
#include "osi/osi.h"
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
typedef struct fixed_pkt_queue_t {
|
||||
struct pkt_queue *pkt_list;
|
||||
osi_sem_t enqueue_sem;
|
||||
osi_sem_t dequeue_sem;
|
||||
size_t capacity;
|
||||
fixed_pkt_queue_cb dequeue_ready;
|
||||
} fixed_pkt_queue_t;
|
||||
|
||||
fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity)
|
||||
{
|
||||
fixed_pkt_queue_t *ret = osi_calloc(sizeof(fixed_pkt_queue_t));
|
||||
if (!ret) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret->capacity = capacity;
|
||||
ret->pkt_list = pkt_queue_create();
|
||||
if (!ret->pkt_list) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
osi_sem_new(&ret->enqueue_sem, capacity, capacity);
|
||||
if (!ret->enqueue_sem) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
osi_sem_new(&ret->dequeue_sem, capacity, 0);
|
||||
if (!ret->dequeue_sem) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error:
|
||||
fixed_pkt_queue_free(ret, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fixed_pkt_queue_unregister_dequeue(queue);
|
||||
|
||||
pkt_queue_destroy(queue->pkt_list, (pkt_queue_free_cb)free_cb);
|
||||
queue->pkt_list = NULL;
|
||||
|
||||
if (queue->enqueue_sem) {
|
||||
osi_sem_free(&queue->enqueue_sem);
|
||||
}
|
||||
if (queue->dequeue_sem) {
|
||||
osi_sem_free(&queue->dequeue_sem);
|
||||
}
|
||||
osi_free(queue);
|
||||
}
|
||||
|
||||
bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return pkt_queue_is_empty(queue->pkt_list);
|
||||
}
|
||||
|
||||
size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return pkt_queue_length(queue->pkt_list);
|
||||
}
|
||||
|
||||
size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
return queue->capacity;
|
||||
}
|
||||
|
||||
bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
assert(queue != NULL);
|
||||
assert(linked_pkt != NULL);
|
||||
|
||||
if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = pkt_queue_enqueue(queue->pkt_list, linked_pkt);
|
||||
|
||||
assert(ret == true);
|
||||
osi_sem_give(&queue->dequeue_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout)
|
||||
{
|
||||
pkt_linked_item_t *ret = NULL;
|
||||
|
||||
assert(queue != NULL);
|
||||
|
||||
if (osi_sem_take(&queue->dequeue_sem, timeout) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
ret = pkt_queue_dequeue(queue->pkt_list);
|
||||
|
||||
osi_sem_give(&queue->enqueue_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pkt_queue_try_peek_first(queue->pkt_list);
|
||||
}
|
||||
|
||||
void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
assert(ready_cb != NULL);
|
||||
|
||||
queue->dequeue_ready = ready_cb;
|
||||
}
|
||||
|
||||
void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
queue->dequeue_ready = NULL;
|
||||
}
|
||||
|
||||
void fixed_pkt_queue_process(fixed_pkt_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
if (queue->dequeue_ready) {
|
||||
queue->dequeue_ready(queue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/fixed_queue.h"
|
||||
#include "osi/list.h"
|
||||
#include "osi/osi.h"
|
||||
#include "osi/mutex.h"
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
typedef struct fixed_queue_t {
|
||||
|
||||
list_t *list;
|
||||
osi_sem_t enqueue_sem;
|
||||
osi_sem_t dequeue_sem;
|
||||
osi_mutex_t lock;
|
||||
size_t capacity;
|
||||
|
||||
fixed_queue_cb dequeue_ready;
|
||||
} fixed_queue_t;
|
||||
|
||||
|
||||
fixed_queue_t *fixed_queue_new(size_t capacity)
|
||||
{
|
||||
fixed_queue_t *ret = osi_calloc(sizeof(fixed_queue_t));
|
||||
if (!ret) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
osi_mutex_new(&ret->lock);
|
||||
ret->capacity = capacity;
|
||||
|
||||
ret->list = list_new(NULL);
|
||||
if (!ret->list) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
osi_sem_new(&ret->enqueue_sem, capacity, capacity);
|
||||
if (!ret->enqueue_sem) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
osi_sem_new(&ret->dequeue_sem, capacity, 0);
|
||||
if (!ret->dequeue_sem) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
error:;
|
||||
fixed_queue_free(ret, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb)
|
||||
{
|
||||
const list_node_t *node;
|
||||
|
||||
if (queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
fixed_queue_unregister_dequeue(queue);
|
||||
|
||||
if (free_cb) {
|
||||
for (node = list_begin(queue->list); node != list_end(queue->list); node = list_next(node)) {
|
||||
free_cb(list_node(node));
|
||||
}
|
||||
}
|
||||
|
||||
list_free(queue->list);
|
||||
osi_sem_free(&queue->enqueue_sem);
|
||||
osi_sem_free(&queue->dequeue_sem);
|
||||
osi_mutex_free(&queue->lock);
|
||||
osi_free(queue);
|
||||
}
|
||||
|
||||
bool fixed_queue_is_empty(fixed_queue_t *queue)
|
||||
{
|
||||
bool is_empty = false;
|
||||
|
||||
if (queue == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
is_empty = list_is_empty(queue->list);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return is_empty;
|
||||
}
|
||||
|
||||
size_t fixed_queue_length(fixed_queue_t *queue)
|
||||
{
|
||||
size_t length;
|
||||
|
||||
if (queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
length = list_length(queue->list);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return length;
|
||||
}
|
||||
size_t fixed_queue_capacity(fixed_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
return queue->capacity;
|
||||
}
|
||||
|
||||
bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout)
|
||||
{
|
||||
bool status=false; //Flag whether enqueued success
|
||||
|
||||
assert(queue != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
if (osi_sem_take(&queue->enqueue_sem, timeout) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
status = list_append(queue->list, data); //Check whether enqueued success
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
if(status == true )
|
||||
osi_sem_give(&queue->dequeue_sem);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout)
|
||||
{
|
||||
void *ret = NULL;
|
||||
|
||||
assert(queue != NULL);
|
||||
|
||||
if (osi_sem_take(&queue->dequeue_sem, timeout) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
ret = list_front(queue->list);
|
||||
list_remove(queue->list, ret);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
osi_sem_give(&queue->enqueue_sem);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *fixed_queue_try_peek_first(fixed_queue_t *queue)
|
||||
{
|
||||
void *ret = NULL;
|
||||
|
||||
if (queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
ret = list_is_empty(queue->list) ? NULL : list_front(queue->list);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *fixed_queue_try_peek_last(fixed_queue_t *queue)
|
||||
{
|
||||
void *ret = NULL;
|
||||
|
||||
if (queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
ret = list_is_empty(queue->list) ? NULL : list_back(queue->list);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *fixed_queue_try_remove_from_queue(fixed_queue_t *queue, void *data)
|
||||
{
|
||||
bool removed = false;
|
||||
|
||||
if (queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
if (list_contains(queue->list, data) &&
|
||||
osi_sem_take(&queue->dequeue_sem, 0) == 0) {
|
||||
removed = list_remove(queue->list, data);
|
||||
assert(removed);
|
||||
}
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
if (removed) {
|
||||
osi_sem_give(&queue->enqueue_sem);
|
||||
return data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_t *fixed_queue_get_list(fixed_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
// NOTE: This function is not thread safe, and there is no point for
|
||||
// calling osi_mutex_lock() / osi_mutex_unlock()
|
||||
return queue->list;
|
||||
}
|
||||
|
||||
void fixed_queue_register_dequeue(fixed_queue_t *queue, fixed_queue_cb ready_cb)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
assert(ready_cb != NULL);
|
||||
|
||||
queue->dequeue_ready = ready_cb;
|
||||
}
|
||||
|
||||
void fixed_queue_unregister_dequeue(fixed_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
queue->dequeue_ready = NULL;
|
||||
}
|
||||
|
||||
void fixed_queue_process(fixed_queue_t *queue)
|
||||
{
|
||||
assert(queue != NULL);
|
||||
|
||||
if (queue->dequeue_ready) {
|
||||
queue->dequeue_ready(queue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "bt_common.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/future.h"
|
||||
#include "osi/osi.h"
|
||||
|
||||
void future_free(future_t *future);
|
||||
|
||||
future_t *future_new(void)
|
||||
{
|
||||
future_t *ret = osi_calloc(sizeof(future_t));
|
||||
if (!ret) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate memory for return value.", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (osi_sem_new(&ret->semaphore, 1, 0) != 0) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate memory for the semaphore.", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret->ready_can_be_called = true;
|
||||
return ret;
|
||||
error:;
|
||||
future_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
future_t *future_new_immediate(void *value)
|
||||
{
|
||||
future_t *ret = osi_calloc(sizeof(future_t));
|
||||
if (!ret) {
|
||||
OSI_TRACE_ERROR("%s unable to allocate memory for return value.", __func__);
|
||||
goto error;
|
||||
}
|
||||
|
||||
ret->result = value;
|
||||
ret->ready_can_be_called = false;
|
||||
return ret;
|
||||
error:;
|
||||
future_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void future_ready(future_t *future, void *value)
|
||||
{
|
||||
assert(future != NULL);
|
||||
assert(future->ready_can_be_called);
|
||||
|
||||
future->ready_can_be_called = false;
|
||||
future->result = value;
|
||||
osi_sem_give(&future->semaphore);
|
||||
}
|
||||
|
||||
void *future_await(future_t *future)
|
||||
{
|
||||
assert(future != NULL);
|
||||
|
||||
// If the future is immediate, it will not have a semaphore
|
||||
if (future->semaphore) {
|
||||
osi_sem_take(&future->semaphore, OSI_SEM_MAX_TIMEOUT);
|
||||
}
|
||||
|
||||
void *result = future->result;
|
||||
future_free(future);
|
||||
return result;
|
||||
}
|
||||
|
||||
void future_free(future_t *future)
|
||||
{
|
||||
if (!future) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (future->semaphore) {
|
||||
osi_sem_free(&future->semaphore);
|
||||
}
|
||||
|
||||
osi_free(future);
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osi/hash_functions.h"
|
||||
|
||||
hash_index_t hash_function_naive(const void *key)
|
||||
{
|
||||
return (hash_index_t)key;
|
||||
}
|
||||
|
||||
hash_index_t hash_function_integer(const void *key)
|
||||
{
|
||||
return ((hash_index_t)key) * 2654435761;
|
||||
}
|
||||
|
||||
hash_index_t hash_function_pointer(const void *key)
|
||||
{
|
||||
return ((hash_index_t)key) * 2654435761;
|
||||
}
|
||||
|
||||
hash_index_t hash_function_string(const void *key)
|
||||
{
|
||||
hash_index_t hash = 5381;
|
||||
const char *name = (const char *)key;
|
||||
size_t string_len = strlen(name);
|
||||
for (size_t i = 0; i < string_len; ++i) {
|
||||
hash = ((hash << 5) + hash ) + name[i];
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
void hash_function_blob(const unsigned char *s, unsigned int len, hash_key_t h)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
while (len--) {
|
||||
j = sizeof(hash_key_t)-1;
|
||||
|
||||
while (j) {
|
||||
h[j] = ((h[j] << 7) | (h[j-1] >> 1)) + h[j];
|
||||
--j;
|
||||
}
|
||||
|
||||
h[0] = (h[0] << 7) + h[0] + *s++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "bt_common.h"
|
||||
#include "osi/list.h"
|
||||
#include "osi/hash_map.h"
|
||||
#include "osi/allocator.h"
|
||||
|
||||
struct hash_map_t;
|
||||
|
||||
typedef struct hash_map_bucket_t {
|
||||
list_t *list;
|
||||
} hash_map_bucket_t;
|
||||
|
||||
typedef struct hash_map_t {
|
||||
hash_map_bucket_t *bucket;
|
||||
size_t num_bucket;
|
||||
size_t hash_size;
|
||||
hash_index_fn hash_fn;
|
||||
key_free_fn key_fn;
|
||||
data_free_fn data_fn;
|
||||
key_equality_fn keys_are_equal;
|
||||
} hash_map_t;
|
||||
|
||||
// Hidden constructor for list, only to be used by us.
|
||||
list_t *list_new_internal(list_free_cb callback);
|
||||
|
||||
static void bucket_free_(void *data);
|
||||
static bool default_key_equality(const void *x, const void *y);
|
||||
static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list,
|
||||
const void *key);
|
||||
|
||||
// Hidden constructor, only to be used by the allocation tracker. Behaves the same as
|
||||
// |hash_map_new|, except you get to specify the allocator.
|
||||
hash_map_t *hash_map_new_internal(
|
||||
size_t num_bucket,
|
||||
hash_index_fn hash_fn,
|
||||
key_free_fn key_fn,
|
||||
data_free_fn data_fn,
|
||||
key_equality_fn equality_fn)
|
||||
{
|
||||
assert(hash_fn != NULL);
|
||||
assert(num_bucket > 0);
|
||||
hash_map_t *hash_map = osi_calloc(sizeof(hash_map_t));
|
||||
if (hash_map == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hash_map->hash_fn = hash_fn;
|
||||
hash_map->key_fn = key_fn;
|
||||
hash_map->data_fn = data_fn;
|
||||
hash_map->keys_are_equal = equality_fn ? equality_fn : default_key_equality;
|
||||
|
||||
hash_map->num_bucket = num_bucket;
|
||||
hash_map->bucket = osi_calloc(sizeof(hash_map_bucket_t) * num_bucket);
|
||||
if (hash_map->bucket == NULL) {
|
||||
osi_free(hash_map);
|
||||
return NULL;
|
||||
}
|
||||
return hash_map;
|
||||
}
|
||||
|
||||
hash_map_t *hash_map_new(
|
||||
size_t num_bucket,
|
||||
hash_index_fn hash_fn,
|
||||
key_free_fn key_fn,
|
||||
data_free_fn data_fn,
|
||||
key_equality_fn equality_fn)
|
||||
{
|
||||
return hash_map_new_internal(num_bucket, hash_fn, key_fn, data_fn, equality_fn);
|
||||
}
|
||||
|
||||
void hash_map_free(hash_map_t *hash_map)
|
||||
{
|
||||
if (hash_map == NULL) {
|
||||
return;
|
||||
}
|
||||
hash_map_clear(hash_map);
|
||||
osi_free(hash_map->bucket);
|
||||
osi_free(hash_map);
|
||||
}
|
||||
|
||||
/*
|
||||
bool hash_map_is_empty(const hash_map_t *hash_map) {
|
||||
assert(hash_map != NULL);
|
||||
return (hash_map->hash_size == 0);
|
||||
}
|
||||
|
||||
size_t hash_map_size(const hash_map_t *hash_map) {
|
||||
assert(hash_map != NULL);
|
||||
return hash_map->hash_size;
|
||||
}
|
||||
|
||||
size_t hash_map_num_buckets(const hash_map_t *hash_map) {
|
||||
assert(hash_map != NULL);
|
||||
return hash_map->num_bucket;
|
||||
}
|
||||
*/
|
||||
|
||||
bool hash_map_has_key(const hash_map_t *hash_map, const void *key)
|
||||
{
|
||||
assert(hash_map != NULL);
|
||||
|
||||
hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
|
||||
list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
|
||||
|
||||
hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
|
||||
return (hash_map_entry != NULL);
|
||||
}
|
||||
|
||||
bool hash_map_set(hash_map_t *hash_map, const void *key, void *data)
|
||||
{
|
||||
assert(hash_map != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
|
||||
|
||||
if (hash_map->bucket[hash_key].list == NULL) {
|
||||
hash_map->bucket[hash_key].list = list_new_internal(bucket_free_);
|
||||
if (hash_map->bucket[hash_key].list == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
|
||||
|
||||
hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
|
||||
|
||||
if (hash_map_entry) {
|
||||
// Calls hash_map callback to delete the hash_map_entry.
|
||||
bool rc = list_remove(hash_bucket_list, hash_map_entry);
|
||||
assert(rc == true);
|
||||
(void)rc;
|
||||
} else {
|
||||
hash_map->hash_size++;
|
||||
}
|
||||
hash_map_entry = osi_calloc(sizeof(hash_map_entry_t));
|
||||
if (hash_map_entry == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hash_map_entry->key = key;
|
||||
hash_map_entry->data = data;
|
||||
hash_map_entry->hash_map = hash_map;
|
||||
|
||||
return list_append(hash_bucket_list, hash_map_entry);
|
||||
}
|
||||
|
||||
bool hash_map_erase(hash_map_t *hash_map, const void *key)
|
||||
{
|
||||
assert(hash_map != NULL);
|
||||
|
||||
hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
|
||||
list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
|
||||
|
||||
hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
|
||||
if (hash_map_entry == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
hash_map->hash_size--;
|
||||
bool remove = list_remove(hash_bucket_list, hash_map_entry);
|
||||
if(list_is_empty(hash_map->bucket[hash_key].list)) {
|
||||
list_free(hash_map->bucket[hash_key].list);
|
||||
hash_map->bucket[hash_key].list = NULL;
|
||||
}
|
||||
|
||||
return remove;
|
||||
}
|
||||
|
||||
void *hash_map_get(const hash_map_t *hash_map, const void *key)
|
||||
{
|
||||
assert(hash_map != NULL);
|
||||
|
||||
hash_index_t hash_key = hash_map->hash_fn(key) % hash_map->num_bucket;
|
||||
list_t *hash_bucket_list = hash_map->bucket[hash_key].list;
|
||||
|
||||
hash_map_entry_t *hash_map_entry = find_bucket_entry_(hash_bucket_list, key);
|
||||
if (hash_map_entry != NULL) {
|
||||
return hash_map_entry->data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hash_map_clear(hash_map_t *hash_map)
|
||||
{
|
||||
assert(hash_map != NULL);
|
||||
|
||||
for (hash_index_t i = 0; i < hash_map->num_bucket; i++) {
|
||||
if (hash_map->bucket[i].list == NULL) {
|
||||
continue;
|
||||
}
|
||||
list_free(hash_map->bucket[i].list);
|
||||
hash_map->bucket[i].list = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void hash_map_foreach(hash_map_t *hash_map, hash_map_iter_cb callback, void *context)
|
||||
{
|
||||
assert(hash_map != NULL);
|
||||
assert(callback != NULL);
|
||||
|
||||
for (hash_index_t i = 0; i < hash_map->num_bucket; ++i) {
|
||||
if (hash_map->bucket[i].list == NULL) {
|
||||
continue;
|
||||
}
|
||||
for (const list_node_t *iter = list_begin(hash_map->bucket[i].list);
|
||||
iter != list_end(hash_map->bucket[i].list);
|
||||
iter = list_next(iter)) {
|
||||
hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter);
|
||||
if (!callback(hash_map_entry, context)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bucket_free_(void *data)
|
||||
{
|
||||
assert(data != NULL);
|
||||
hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)data;
|
||||
const hash_map_t *hash_map = hash_map_entry->hash_map;
|
||||
|
||||
if (hash_map->key_fn) {
|
||||
hash_map->key_fn((void *)hash_map_entry->key);
|
||||
}
|
||||
if (hash_map->data_fn) {
|
||||
hash_map->data_fn(hash_map_entry->data);
|
||||
}
|
||||
osi_free(hash_map_entry);
|
||||
}
|
||||
|
||||
static hash_map_entry_t *find_bucket_entry_(list_t *hash_bucket_list,
|
||||
const void *key)
|
||||
{
|
||||
|
||||
if (hash_bucket_list == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (const list_node_t *iter = list_begin(hash_bucket_list);
|
||||
iter != list_end(hash_bucket_list);
|
||||
iter = list_next(iter)) {
|
||||
hash_map_entry_t *hash_map_entry = (hash_map_entry_t *)list_node(iter);
|
||||
if (hash_map_entry->hash_map->keys_are_equal(hash_map_entry->key, key)) {
|
||||
return hash_map_entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static bool default_key_equality(const void *x, const void *y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _ALARM_H_
|
||||
#define _ALARM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "esp_timer.h"
|
||||
|
||||
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 50
|
||||
#define ALARM_ID_BASE 1000
|
||||
|
||||
int osi_alarm_create_mux(void);
|
||||
int osi_alarm_delete_mux(void);
|
||||
void osi_alarm_init(void);
|
||||
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(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|.
|
||||
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.
|
||||
osi_alarm_err_t osi_alarm_set(osi_alarm_t *alarm, period_ms_t timeout);
|
||||
|
||||
// Sets an periodic alarm to fire |cb| each given |period|.
|
||||
osi_alarm_err_t osi_alarm_set_periodic(osi_alarm_t *alarm, period_ms_t period);
|
||||
|
||||
// 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.
|
||||
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.
|
||||
// only for oneshot alarm, not for periodic alarm
|
||||
// TODO: Remove this function once PM timers can be re-factored
|
||||
period_ms_t osi_alarm_get_remaining_ms(const osi_alarm_t *alarm);
|
||||
|
||||
// Alarm-related state cleanup
|
||||
//void alarm_cleanup(void);
|
||||
|
||||
uint32_t osi_time_get_os_boottime_ms(void);
|
||||
|
||||
// This function returns whether the given |alarm| is active or not.
|
||||
// Return true if active, false otherwise.
|
||||
bool osi_alarm_is_active(osi_alarm_t *alarm);
|
||||
|
||||
#endif /*_ALARM_H_*/
|
||||
@@ -0,0 +1,145 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _ALLOCATOR_H_
|
||||
#define _ALLOCATOR_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
char *osi_strdup(const char *str);
|
||||
|
||||
void *osi_malloc_func(size_t size);
|
||||
void *osi_calloc_func(size_t size);
|
||||
void osi_free_func(void *ptr);
|
||||
|
||||
#if HEAP_MEMORY_DEBUG
|
||||
|
||||
void osi_mem_dbg_init(void);
|
||||
void osi_mem_dbg_record(void *p, int size, const char *func, int line);
|
||||
void osi_mem_dbg_clean(void *p, const char *func, int line);
|
||||
void osi_mem_dbg_show(void);
|
||||
uint32_t osi_mem_dbg_get_max_size(void);
|
||||
uint32_t osi_mem_dbg_get_current_size(void);
|
||||
void osi_men_dbg_set_section_start(uint8_t index);
|
||||
void osi_men_dbg_set_section_end(uint8_t index);
|
||||
uint32_t osi_mem_dbg_get_max_size_section(uint8_t index);
|
||||
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
#define osi_malloc(size) \
|
||||
({ \
|
||||
void *p; \
|
||||
p = heap_caps_malloc_prefer(size, 2, \
|
||||
MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, \
|
||||
MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); \
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__); \
|
||||
(void *)p; \
|
||||
})
|
||||
|
||||
#define osi_calloc(size) \
|
||||
({ \
|
||||
void *p; \
|
||||
p = heap_caps_calloc_prefer(1, size, 2, \
|
||||
MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, \
|
||||
MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); \
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__); \
|
||||
(void *)p; \
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#define osi_malloc(size) \
|
||||
({ \
|
||||
void *p; \
|
||||
p = malloc((size)); \
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__); \
|
||||
(void *)p; \
|
||||
})
|
||||
|
||||
#define osi_calloc(size) \
|
||||
({ \
|
||||
void *p; \
|
||||
p = calloc(1, (size)); \
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__); \
|
||||
(void *)p; \
|
||||
})
|
||||
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */
|
||||
|
||||
|
||||
#if 0
|
||||
#define osi_malloc(size) \
|
||||
do { \
|
||||
void *p; \
|
||||
\
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST \
|
||||
p = heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); \
|
||||
#else \
|
||||
p = malloc((size)); \
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ \
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__); \
|
||||
(void *)p; \
|
||||
}while(0)
|
||||
|
||||
#define osi_calloc(size) \
|
||||
do { \
|
||||
void *p; \
|
||||
\
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST \
|
||||
p = heap_caps_calloc_prefer(1, size, 2, \
|
||||
MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, \
|
||||
MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL); \
|
||||
#else \
|
||||
p = calloc(1, (size)); \
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */ \
|
||||
osi_mem_dbg_record(p, size, __func__, __LINE__); \
|
||||
(void *)p; \
|
||||
} while(0)
|
||||
#endif
|
||||
|
||||
#define osi_free(ptr) \
|
||||
do { \
|
||||
void *tmp_point = (void *)(ptr); \
|
||||
osi_mem_dbg_clean(tmp_point, __func__, __LINE__); \
|
||||
free(tmp_point); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#if HEAP_ALLOCATION_FROM_SPIRAM_FIRST
|
||||
#define osi_malloc(size) heap_caps_malloc_prefer(size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL)
|
||||
#define osi_calloc(size) heap_caps_calloc_prefer(1, size, 2, MALLOC_CAP_DEFAULT|MALLOC_CAP_SPIRAM, MALLOC_CAP_DEFAULT|MALLOC_CAP_INTERNAL)
|
||||
#else
|
||||
#define osi_malloc(size) malloc((size))
|
||||
#define osi_calloc(size) calloc(1, (size))
|
||||
#endif /* #if HEAP_ALLOCATION_FROM_SPIRAM_FIRST */
|
||||
#define osi_free(p) free((p))
|
||||
|
||||
#endif /* HEAP_MEMORY_DEBUG */
|
||||
|
||||
#define FREE_AND_RESET(a) \
|
||||
do { \
|
||||
if (a) { \
|
||||
osi_free(a); \
|
||||
a = NULL; \
|
||||
} \
|
||||
}while (0)
|
||||
|
||||
|
||||
#endif /* _ALLOCATOR_H_ */
|
||||
@@ -0,0 +1,59 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _BUFFER_H_
|
||||
#define _BUFFER_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct buffer_t buffer_t;
|
||||
|
||||
// Returns a new buffer of |size| bytes. Returns NULL if a buffer could not be
|
||||
// allocated. |size| must be non-zero. The caller must release this buffer with
|
||||
// |buffer_free|.
|
||||
buffer_t *buffer_new(size_t size);
|
||||
|
||||
// Creates a new reference to the buffer |buf|. A reference is indistinguishable
|
||||
// from the original: writes to the original will be reflected in the reference
|
||||
// and vice versa. In other words, this function creates an alias to |buf|. The
|
||||
// caller must release the returned buffer with |buffer_free|. Note that releasing
|
||||
// the returned buffer does not release |buf|. |buf| must not be NULL.
|
||||
buffer_t *buffer_new_ref(const buffer_t *buf);
|
||||
|
||||
// Creates a new reference to the last |slice_size| bytes of |buf|. See
|
||||
// |buffer_new_ref| for a description of references. |slice_size| must be
|
||||
// greater than 0 and may be at most |buffer_length|
|
||||
// (0 < slice_size <= buffer_length). |buf| must not be NULL.
|
||||
buffer_t *buffer_new_slice(const buffer_t *buf, size_t slice_size);
|
||||
|
||||
// Frees a buffer object. |buf| may be NULL.
|
||||
void buffer_free(buffer_t *buf);
|
||||
|
||||
// Returns a pointer to a writeable memory region for |buf|. All references
|
||||
// and slices that share overlapping bytes will also be written to when
|
||||
// writing to the returned pointer. The caller may safely write up to
|
||||
// |buffer_length| consecutive bytes starting at the address returned by
|
||||
// this function. |buf| must not be NULL.
|
||||
void *buffer_ptr(const buffer_t *buf);
|
||||
|
||||
// Returns the length of the writeable memory region referred to by |buf|.
|
||||
// |buf| must not be NULL.
|
||||
size_t buffer_length(const buffer_t *buf);
|
||||
|
||||
#endif /*_BUFFER_H_*/
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_H__
|
||||
#define __CONFIG_H__
|
||||
|
||||
// This module implements a configuration parser. Clients can query the
|
||||
// contents of a configuration file through the interface provided here.
|
||||
// The current implementation is read-only; mutations are only kept in
|
||||
// memory. This parser supports the INI file format.
|
||||
|
||||
// Implementation notes:
|
||||
// - Key/value pairs that are not within a section are assumed to be under
|
||||
// the |CONFIG_DEFAULT_SECTION| section.
|
||||
// - Multiple sections with the same name will be merged as if they were in
|
||||
// a single section.
|
||||
// - Empty sections with no key/value pairs will be treated as if they do
|
||||
// not exist. In other words, |config_has_section| will return false for
|
||||
// empty sections.
|
||||
// - Duplicate keys in a section will overwrite previous values.
|
||||
// - All strings are case sensitive.
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
// The default section name to use if a key/value pair is not defined within
|
||||
// a section.
|
||||
#define CONFIG_DEFAULT_SECTION "Global"
|
||||
|
||||
typedef struct config_t config_t;
|
||||
typedef struct config_section_node_t config_section_node_t;
|
||||
|
||||
// Creates a new config object with no entries (i.e. not backed by a file).
|
||||
// This function returns a config object or NULL on error. Clients must call
|
||||
// |config_free| on the returned handle when it is no longer required.
|
||||
config_t *config_new_empty(void);
|
||||
|
||||
// Loads the specified file and returns a handle to the config file. If there
|
||||
// was a problem loading the file or allocating memory, this function returns
|
||||
// NULL. Clients must call |config_free| on the returned handle when it is no
|
||||
// longer required. |filename| must not be NULL and must point to a readable
|
||||
// file on the filesystem.
|
||||
config_t *config_new(const char *filename);
|
||||
|
||||
// Frees resources associated with the config file. No further operations may
|
||||
// be performed on the |config| object after calling this function. |config|
|
||||
// may be NULL.
|
||||
void config_free(config_t *config);
|
||||
|
||||
// Returns true if the config file contains a section named |section|. If
|
||||
// the section has no key/value pairs in it, this function will return false.
|
||||
// |config| and |section| must not be NULL.
|
||||
bool config_has_section(const config_t *config, const char *section);
|
||||
|
||||
// Returns true if the config file has a key named |key| under |section|.
|
||||
// Returns false otherwise. |config|, |section|, and |key| must not be NULL.
|
||||
bool config_has_key(const config_t *config, const char *section, const char *key);
|
||||
|
||||
// Returns true if the config file has a key named |key| and the key_value.
|
||||
// Returns false otherwise. |config|, |key|, and |key_value| must not be NULL.
|
||||
bool config_has_key_in_section(config_t *config, const char *key, char *key_value);
|
||||
|
||||
// Returns the integral value for a given |key| in |section|. If |section|
|
||||
// or |key| do not exist, or the value cannot be fully converted to an integer,
|
||||
// this function returns |def_value|. |config|, |section|, and |key| must not
|
||||
// be NULL.
|
||||
int config_get_int(const config_t *config, const char *section, const char *key, int def_value);
|
||||
|
||||
// Returns the boolean value for a given |key| in |section|. If |section|
|
||||
// or |key| do not exist, or the value cannot be converted to a boolean, this
|
||||
// function returns |def_value|. |config|, |section|, and |key| must not be NULL.
|
||||
bool config_get_bool(const config_t *config, const char *section, const char *key, bool def_value);
|
||||
|
||||
// Returns the string value for a given |key| in |section|. If |section| or
|
||||
// |key| do not exist, this function returns |def_value|. The returned string
|
||||
// is owned by the config module and must not be freed. |config|, |section|,
|
||||
// and |key| must not be NULL. |def_value| may be NULL.
|
||||
const char *config_get_string(const config_t *config, const char *section, const char *key, const char *def_value);
|
||||
|
||||
// Sets an integral value for the |key| in |section|. If |key| or |section| do
|
||||
// not already exist, this function creates them. |config|, |section|, and |key|
|
||||
// must not be NULL.
|
||||
void config_set_int(config_t *config, const char *section, const char *key, int value);
|
||||
|
||||
// Sets a boolean value for the |key| in |section|. If |key| or |section| do
|
||||
// not already exist, this function creates them. |config|, |section|, and |key|
|
||||
// must not be NULL.
|
||||
void config_set_bool(config_t *config, const char *section, const char *key, bool value);
|
||||
|
||||
// Sets a string value for the |key| in |section|. If |key| or |section| do
|
||||
// not already exist, this function creates them. |config|, |section|, |key|, and
|
||||
// |value| must not be NULL.
|
||||
void config_set_string(config_t *config, const char *section, const char *key, const char *value, bool insert_back);
|
||||
|
||||
// Removes |section| from the |config| (and, as a result, all keys in the section).
|
||||
// Returns true if |section| was found and removed from |config|, false otherwise.
|
||||
// Neither |config| nor |section| may be NULL.
|
||||
bool config_remove_section(config_t *config, const char *section);
|
||||
|
||||
// Updates |section| to be the first section in |config|. Return true if |section| is in
|
||||
// |config| and updated successfully, false otherwise.
|
||||
// Neither |config| nor |section| may be NULL.
|
||||
bool config_update_newest_section(config_t *config, const char *section);
|
||||
|
||||
// Removes one specific |key| residing in |section| of the |config|. Returns true
|
||||
// if the section and key were found and the key was removed, false otherwise.
|
||||
// None of |config|, |section|, or |key| may be NULL.
|
||||
bool config_remove_key(config_t *config, const char *section, const char *key);
|
||||
|
||||
// Returns an iterator to the first section in the config file. If there are no
|
||||
// sections, the iterator will equal the return value of |config_section_end|.
|
||||
// The returned pointer must be treated as an opaque handle and must not be freed.
|
||||
// The iterator is invalidated on any config mutating operation. |config| may not
|
||||
// be NULL.
|
||||
const config_section_node_t *config_section_begin(const config_t *config);
|
||||
|
||||
// Returns an iterator to one past the last section in the config file. It does not
|
||||
// represent a valid section, but can be used to determine if all sections have been
|
||||
// iterated over. The returned pointer must be treated as an opaque handle and must
|
||||
// not be freed and must not be iterated on (must not call |config_section_next| on
|
||||
// it). |config| may not be NULL.
|
||||
const config_section_node_t *config_section_end(const config_t *config);
|
||||
|
||||
// Moves |iter| to the next section. If there are no more sections, |iter| will
|
||||
// equal the value of |config_section_end|. |iter| may not be NULL and must be
|
||||
// a pointer returned by either |config_section_begin| or |config_section_next|.
|
||||
const config_section_node_t *config_section_next(const config_section_node_t *iter);
|
||||
|
||||
// Returns the name of the section referred to by |iter|. The returned pointer is
|
||||
// owned by the config module and must not be freed by the caller. The pointer will
|
||||
// remain valid until |config_free| is called. |iter| may not be NULL and must not
|
||||
// equal the value returned by |config_section_end|.
|
||||
const char *config_section_name(const config_section_node_t *iter);
|
||||
|
||||
// Saves |config| to a file given by |filename|. Note that this could be a destructive
|
||||
// operation: if |filename| already exists, it will be overwritten. The config
|
||||
// module does not preserve comments or formatting so if a config file was opened
|
||||
// with |config_new| and subsequently overwritten with |config_save|, all comments
|
||||
// and special formatting in the original file will be lost. Neither |config| nor
|
||||
// |filename| may be NULL.
|
||||
bool config_save(const config_t *config, const char *filename);
|
||||
|
||||
#endif /* #ifndef __CONFIG_H__ */
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _FIXED_PKT_QUEUE_H_
|
||||
#define _FIXED_PKT_QUEUE_H_
|
||||
|
||||
|
||||
#include "osi/pkt_queue.h"
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef FIXED_PKT_QUEUE_SIZE_MAX
|
||||
#define FIXED_PKT_QUEUE_SIZE_MAX 254
|
||||
#endif
|
||||
|
||||
#define FIXED_PKT_QUEUE_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT
|
||||
|
||||
struct fixed_pkt_queue_t;
|
||||
|
||||
typedef struct fixed_pkt_queue_t fixed_pkt_queue_t;
|
||||
|
||||
typedef void (*fixed_pkt_queue_free_cb)(pkt_linked_item_t *data);
|
||||
typedef void (*fixed_pkt_queue_cb)(fixed_pkt_queue_t *queue);
|
||||
|
||||
// Creates a new fixed queue with the given |capacity|. If more elements than
|
||||
// |capacity| are added to the queue, the caller is blocked until space is
|
||||
// made available in the queue. Returns NULL on failure. The caller must free
|
||||
// the returned queue with |fixed_pkt_queue_free|.
|
||||
fixed_pkt_queue_t *fixed_pkt_queue_new(size_t capacity);
|
||||
|
||||
// Freeing a queue that is currently in use (i.e. has waiters
|
||||
// blocked on it) results in undefined behaviour.
|
||||
void fixed_pkt_queue_free(fixed_pkt_queue_t *queue, fixed_pkt_queue_free_cb free_cb);
|
||||
|
||||
// Returns a value indicating whether the given |queue| is empty. If |queue|
|
||||
// is NULL, the return value is true.
|
||||
bool fixed_pkt_queue_is_empty(fixed_pkt_queue_t *queue);
|
||||
|
||||
// Returns the length of the |queue|. If |queue| is NULL, the return value
|
||||
// is 0.
|
||||
size_t fixed_pkt_queue_length(fixed_pkt_queue_t *queue);
|
||||
|
||||
// Returns the maximum number of elements this queue may hold. |queue| may
|
||||
// not be NULL.
|
||||
size_t fixed_pkt_queue_capacity(fixed_pkt_queue_t *queue);
|
||||
|
||||
// Enqueues the given |data| into the |queue|. The caller will be blocked or immediately return or wait for timeout according to the parameter timeout.
|
||||
// If enqueue failed, it will return false, otherwise return true
|
||||
bool fixed_pkt_queue_enqueue(fixed_pkt_queue_t *queue, pkt_linked_item_t *linked_pkt, uint32_t timeout);
|
||||
|
||||
// Dequeues the next element from |queue|. If the queue is currently empty,
|
||||
// this function will block the caller until an item is enqueued or immediately return or wait for timeout according to the parameter timeout.
|
||||
// If dequeue failed, it will return NULL, otherwise return a point.
|
||||
pkt_linked_item_t *fixed_pkt_queue_dequeue(fixed_pkt_queue_t *queue, uint32_t timeout);
|
||||
|
||||
// Returns the first element from |queue|, if present, without dequeuing it.
|
||||
// This function will never block the caller. Returns NULL if there are no
|
||||
// elements in the queue or |queue| is NULL.
|
||||
pkt_linked_item_t *fixed_pkt_queue_try_peek_first(fixed_pkt_queue_t *queue);
|
||||
|
||||
// Registers |queue| with |reactor| for dequeue operations. When there is an element
|
||||
// in the queue, ready_cb will be called. The |context| parameter is passed, untouched,
|
||||
// to the callback routine. Neither |queue|, nor |reactor|, nor |read_cb| may be NULL.
|
||||
// |context| may be NULL.
|
||||
void fixed_pkt_queue_register_dequeue(fixed_pkt_queue_t *queue, fixed_pkt_queue_cb ready_cb);
|
||||
|
||||
// Unregisters the dequeue ready callback for |queue| from whichever reactor
|
||||
// it is registered with, if any. This function is idempotent.
|
||||
void fixed_pkt_queue_unregister_dequeue(fixed_pkt_queue_t *queue);
|
||||
|
||||
void fixed_pkt_queue_process(fixed_pkt_queue_t *queue);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,125 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _FIXED_QUEUE_H_
|
||||
#define _FIXED_QUEUE_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "osi/list.h"
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
#ifndef QUEUE_SIZE_MAX
|
||||
#define QUEUE_SIZE_MAX 254
|
||||
#endif
|
||||
|
||||
#define FIXED_QUEUE_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT
|
||||
|
||||
struct fixed_queue_t;
|
||||
|
||||
typedef struct fixed_queue_t fixed_queue_t;
|
||||
//typedef struct reactor_t reactor_t;
|
||||
|
||||
typedef void (*fixed_queue_free_cb)(void *data);
|
||||
typedef void (*fixed_queue_cb)(fixed_queue_t *queue);
|
||||
|
||||
// Creates a new fixed queue with the given |capacity|. If more elements than
|
||||
// |capacity| are added to the queue, the caller is blocked until space is
|
||||
// made available in the queue. Returns NULL on failure. The caller must free
|
||||
// the returned queue with |fixed_queue_free|.
|
||||
fixed_queue_t *fixed_queue_new(size_t capacity);
|
||||
|
||||
// Freeing a queue that is currently in use (i.e. has waiters
|
||||
// blocked on it) results in undefined behaviour.
|
||||
void fixed_queue_free(fixed_queue_t *queue, fixed_queue_free_cb free_cb);
|
||||
|
||||
// Returns a value indicating whether the given |queue| is empty. If |queue|
|
||||
// is NULL, the return value is true.
|
||||
bool fixed_queue_is_empty(fixed_queue_t *queue);
|
||||
|
||||
// Returns the length of the |queue|. If |queue| is NULL, the return value
|
||||
// is 0.
|
||||
size_t fixed_queue_length(fixed_queue_t *queue);
|
||||
|
||||
// Returns the maximum number of elements this queue may hold. |queue| may
|
||||
// not be NULL.
|
||||
size_t fixed_queue_capacity(fixed_queue_t *queue);
|
||||
|
||||
// Enqueues the given |data| into the |queue|. The caller will be blocked or immediately return or wait for timeout according to the parameter timeout.
|
||||
// If enqueue failed, it will return false, otherwise return true
|
||||
bool fixed_queue_enqueue(fixed_queue_t *queue, void *data, uint32_t timeout);
|
||||
|
||||
// Dequeues the next element from |queue|. If the queue is currently empty,
|
||||
// this function will block the caller until an item is enqueued or immediately return or wait for timeout according to the parameter timeout.
|
||||
// If dequeue failed, it will return NULL, otherwise return a point.
|
||||
void *fixed_queue_dequeue(fixed_queue_t *queue, uint32_t timeout);
|
||||
|
||||
// Returns the first element from |queue|, if present, without dequeuing it.
|
||||
// This function will never block the caller. Returns NULL if there are no
|
||||
// elements in the queue or |queue| is NULL.
|
||||
void *fixed_queue_try_peek_first(fixed_queue_t *queue);
|
||||
|
||||
// Returns the last element from |queue|, if present, without dequeuing it.
|
||||
// This function will never block the caller. Returns NULL if there are no
|
||||
// elements in the queue or |queue| is NULL.
|
||||
void *fixed_queue_try_peek_last(fixed_queue_t *queue);
|
||||
|
||||
// Tries to remove a |data| element from the middle of the |queue|. This
|
||||
// function will never block the caller. If the queue is empty or NULL, this
|
||||
// function returns NULL immediately. |data| may not be NULL. If the |data|
|
||||
// element is found in the queue, a pointer to the removed data is returned,
|
||||
// otherwise NULL.
|
||||
void *fixed_queue_try_remove_from_queue(fixed_queue_t *queue, void *data);
|
||||
|
||||
// Returns the iterateable list with all entries in the |queue|. This function
|
||||
// will never block the caller. |queue| may not be NULL.
|
||||
//
|
||||
// NOTE: The return result of this function is not thread safe: the list could
|
||||
// be modified by another thread, and the result would be unpredictable.
|
||||
// TODO: The usage of this function should be refactored, and the function
|
||||
// itself should be removed.
|
||||
list_t *fixed_queue_get_list(fixed_queue_t *queue);
|
||||
|
||||
// This function returns a valid file descriptor. Callers may perform one
|
||||
// operation on the fd: select(2). If |select| indicates that the file
|
||||
// descriptor is readable, the caller may call |fixed_queue_enqueue| without
|
||||
// blocking. The caller must not close the returned file descriptor. |queue|
|
||||
// may not be NULL.
|
||||
//int fixed_queue_get_enqueue_fd(const fixed_queue_t *queue);
|
||||
|
||||
// This function returns a valid file descriptor. Callers may perform one
|
||||
// operation on the fd: select(2). If |select| indicates that the file
|
||||
// descriptor is readable, the caller may call |fixed_queue_dequeue| without
|
||||
// blocking. The caller must not close the returned file descriptor. |queue|
|
||||
// may not be NULL.
|
||||
//int fixed_queue_get_dequeue_fd(const fixed_queue_t *queue);
|
||||
|
||||
// Registers |queue| with |reactor| for dequeue operations. When there is an element
|
||||
// in the queue, ready_cb will be called. The |context| parameter is passed, untouched,
|
||||
// to the callback routine. Neither |queue|, nor |reactor|, nor |read_cb| may be NULL.
|
||||
// |context| may be NULL.
|
||||
void fixed_queue_register_dequeue(fixed_queue_t *queue, fixed_queue_cb ready_cb);
|
||||
|
||||
// Unregisters the dequeue ready callback for |queue| from whichever reactor
|
||||
// it is registered with, if any. This function is idempotent.
|
||||
void fixed_queue_unregister_dequeue(fixed_queue_t *queue);
|
||||
|
||||
void fixed_queue_process(fixed_queue_t *queue);
|
||||
|
||||
list_t *fixed_queue_get_list(fixed_queue_t *queue);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __FUTURE_H__
|
||||
#define __FUTURE_H__
|
||||
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
struct future {
|
||||
bool ready_can_be_called;
|
||||
osi_sem_t semaphore; // NULL semaphore means immediate future
|
||||
void *result;
|
||||
};
|
||||
typedef struct future future_t;
|
||||
|
||||
#define FUTURE_SUCCESS ((void *)1)
|
||||
#define FUTURE_FAIL ((void *)0)
|
||||
|
||||
// Constructs a new future_t object. Returns NULL on failure.
|
||||
future_t *future_new(void);
|
||||
|
||||
// Constructs a new future_t object with an immediate |value|. No waiting will
|
||||
// occur in the call to |future_await| because the value is already present.
|
||||
// Returns NULL on failure.
|
||||
future_t *future_new_immediate(void *value);
|
||||
|
||||
// Signals that the |future| is ready, passing |value| back to the context
|
||||
// waiting for the result. Must only be called once for every future.
|
||||
// |future| may not be NULL.
|
||||
void future_ready(future_t *future, void *value);
|
||||
|
||||
// Waits for the |future| to be ready. Returns the value set in |future_ready|.
|
||||
// Frees the future before return. |future| may not be NULL.
|
||||
void *future_await(future_t *async_result);
|
||||
|
||||
//Free the future if this "future" is not used
|
||||
void future_free(future_t *future);
|
||||
#endif /* __FUTURE_H__ */
|
||||
@@ -0,0 +1,37 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _HASH_FUNCTIONS_H_
|
||||
#define _HASH_FUNCTIONS_H_
|
||||
|
||||
#include "osi/hash_map.h"
|
||||
|
||||
typedef unsigned char hash_key_t[4];
|
||||
|
||||
hash_index_t hash_function_naive(const void *key);
|
||||
|
||||
hash_index_t hash_function_integer(const void *key);
|
||||
|
||||
// Hashes a pointer based only on its address value
|
||||
hash_index_t hash_function_pointer(const void *key);
|
||||
|
||||
hash_index_t hash_function_string(const void *key);
|
||||
|
||||
void hash_function_blob(const unsigned char *s, unsigned int len, hash_key_t h);
|
||||
|
||||
#endif /* _HASH_FUNCTIONS_H_ */
|
||||
@@ -0,0 +1,110 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef _HASH_MAP_H_
|
||||
#define _HASH_MAP_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct hash_map_t;
|
||||
typedef struct hash_map_t hash_map_t;
|
||||
|
||||
typedef struct hash_map_entry_t {
|
||||
const void *key;
|
||||
void *data;
|
||||
const hash_map_t *hash_map;
|
||||
} hash_map_entry_t;
|
||||
|
||||
typedef size_t hash_index_t;
|
||||
|
||||
// Takes a key structure and returns a hash value.
|
||||
typedef hash_index_t (*hash_index_fn)(const void *key);
|
||||
typedef bool (*hash_map_iter_cb)(hash_map_entry_t *hash_entry, void *context);
|
||||
|
||||
typedef bool (*key_equality_fn)(const void *x, const void *y);
|
||||
|
||||
typedef void (*key_free_fn)(void *data);
|
||||
typedef void (*data_free_fn)(void *data);
|
||||
|
||||
// Returns a new, empty hash_map. Returns NULL if not enough memory could be allocated
|
||||
// for the hash_map structure. The returned hash_map must be freed with |hash_map_free|.
|
||||
// The |num_bucket| specifies the number of hashable buckets for the map and must not
|
||||
// be zero. The |hash_fn| specifies a hash function to be used and must not be NULL.
|
||||
// The |key_fn| and |data_fn| are called whenever a hash_map element is removed from
|
||||
// the hash_map. They can be used to release resources held by the hash_map element,
|
||||
// e.g. memory or file descriptor. |key_fn| and |data_fn| may be NULL if no cleanup
|
||||
// is necessary on element removal. |equality_fn| is used to check for key equality.
|
||||
// If |equality_fn| is NULL, default pointer equality is used.
|
||||
hash_map_t *hash_map_new(
|
||||
size_t size,
|
||||
hash_index_fn hash_fn,
|
||||
key_free_fn key_fn,
|
||||
data_free_fn data_fn,
|
||||
key_equality_fn equality_fn);
|
||||
|
||||
// Frees the hash_map. This function accepts NULL as an argument, in which case it
|
||||
// behaves like a no-op.
|
||||
void hash_map_free(hash_map_t *hash_map);
|
||||
|
||||
// Returns true if the hash_map is empty (has no elements), false otherwise.
|
||||
// Note that a NULL |hash_map| is not the same as an empty |hash_map|. This function
|
||||
// does not accept a NULL |hash_map|.
|
||||
//bool hash_map_is_empty(const hash_map_t *hash_map);
|
||||
|
||||
// Returns the number of elements in the hash map. This function does not accept a
|
||||
// NULL |hash_map|.
|
||||
//size_t hash_map_size(const hash_map_t *hash_map);
|
||||
|
||||
// Returns the number of buckets in the hash map. This function does not accept a
|
||||
// NULL |hash_map|.
|
||||
//size_t hash_map_num_buckets(const hash_map_t *hash_map);
|
||||
|
||||
// Returns true if the hash_map has a valid entry for the presented key.
|
||||
// This function does not accept a NULL |hash_map|.
|
||||
bool hash_map_has_key(const hash_map_t *hash_map, const void *key);
|
||||
|
||||
// Returns the element indexed by |key| in the hash_map without removing it. |hash_map|
|
||||
// may not be NULL. Returns NULL if no entry indexed by |key|.
|
||||
void *hash_map_get(const hash_map_t *hash_map, const void *key);
|
||||
|
||||
// Sets the value |data| indexed by |key| into the |hash_map|. Neither |data| nor
|
||||
// |hash_map| may be NULL. This function does not make copies of |data| nor |key|
|
||||
// so the pointers must remain valid at least until the element is removed from the
|
||||
// hash_map or the hash_map is freed. Returns true if |data| could be set, false
|
||||
// otherwise (e.g. out of memory).
|
||||
bool hash_map_set(hash_map_t *hash_map, const void *key, void *data);
|
||||
|
||||
// Removes data indexed by |key| from the hash_map. |hash_map| may not be NULL.
|
||||
// If |key_fn| or |data_fn| functions were specified in |hash_map_new|, they
|
||||
// will be called back with |key| or |data| respectively. This function returns true
|
||||
// if |key| was found in the hash_map and removed, false otherwise.
|
||||
bool hash_map_erase(hash_map_t *hash_map, const void *key);
|
||||
|
||||
// Removes all elements in the hash_map. Calling this function will return the hash_map
|
||||
// to the same state it was in after |hash_map_new|. |hash_map| may not be NULL.
|
||||
void hash_map_clear(hash_map_t *hash_map);
|
||||
|
||||
// Iterates through the entire |hash_map| and calls |callback| for each data
|
||||
// element and passes through the |context| argument. If the hash_map is
|
||||
// empty, |callback| will never be called. It is not safe to mutate the
|
||||
// hash_map inside the callback. Neither |hash_map| nor |callback| may be NULL.
|
||||
// If |callback| returns false, the iteration loop will immediately exit.
|
||||
void hash_map_foreach(hash_map_t *hash_map, hash_map_iter_cb callback, void *context);
|
||||
|
||||
#endif /* _HASH_MAP_H_ */
|
||||
@@ -0,0 +1,121 @@
|
||||
#ifndef _LIST_H_
|
||||
#define _LIST_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
struct list_node_t;
|
||||
typedef struct list_node_t list_node_t;
|
||||
|
||||
struct list_t;
|
||||
typedef struct list_t list_t;
|
||||
|
||||
typedef void (*list_free_cb)(void *data);
|
||||
typedef bool (*list_iter_cb)(void *data, void *context);
|
||||
|
||||
// Returns a new, empty list. Returns NULL if not enough memory could be allocated
|
||||
// for the list structure. The returned list must be freed with |list_free|. The
|
||||
// |callback| specifies a function to be called whenever a list element is removed
|
||||
// from the list. It can be used to release resources held by the list element, e.g.
|
||||
// memory or file descriptor. |callback| may be NULL if no cleanup is necessary on
|
||||
// element removal.
|
||||
list_t *list_new(list_free_cb callback);
|
||||
|
||||
|
||||
list_node_t *list_free_node(list_t *list, list_node_t *node);
|
||||
|
||||
// similar with list_free_node, this function doesn't free the node data
|
||||
list_node_t *list_delete_node(list_t *list, list_node_t *node);
|
||||
|
||||
// Frees the list. This function accepts NULL as an argument, in which case it
|
||||
// behaves like a no-op.
|
||||
void list_free(list_t *list);
|
||||
|
||||
// Returns true if |list| is empty (has no elements), false otherwise.
|
||||
// |list| may not be NULL.
|
||||
bool list_is_empty(const list_t *list);
|
||||
|
||||
// Returns true if the list contains |data|, false otherwise.
|
||||
// |list| may not be NULL.
|
||||
bool list_contains(const list_t *list, const void *data);
|
||||
|
||||
// Returns list_node which contains |data|, NULL otherwise.
|
||||
// |list| may not be NULL.
|
||||
list_node_t *list_get_node(const list_t *list, const void *data);
|
||||
|
||||
// Returns the length of the |list|. |list| may not be NULL.
|
||||
size_t list_length(const list_t *list);
|
||||
|
||||
// Returns the first element in the list without removing it. |list| may not
|
||||
// be NULL or empty.
|
||||
void *list_front(const list_t *list);
|
||||
|
||||
// Returns the last element in the list without removing it. |list| may not
|
||||
// be NULL or empty.
|
||||
void *list_back(const list_t *list);
|
||||
list_node_t *list_back_node(const list_t *list);
|
||||
|
||||
// Inserts |data| after |prev_node| in |list|. |data|, |list|, and |prev_node|
|
||||
// may not be NULL. This function does not make a copy of |data| so the pointer
|
||||
// must remain valid at least until the element is removed from the list or the
|
||||
// list is freed. Returns true if |data| could be inserted, false otherwise
|
||||
// (e.g. out of memory).
|
||||
bool list_insert_after(list_t *list, list_node_t *prev_node, void *data);
|
||||
|
||||
// Inserts |data| at the beginning of |list|. Neither |data| nor |list| may be NULL.
|
||||
// This function does not make a copy of |data| so the pointer must remain valid
|
||||
// at least until the element is removed from the list or the list is freed.
|
||||
// Returns true if |data| could be inserted, false otherwise (e.g. out of memory).
|
||||
bool list_prepend(list_t *list, void *data);
|
||||
|
||||
// Inserts |data| at the end of |list|. Neither |data| nor |list| may be NULL.
|
||||
// This function does not make a copy of |data| so the pointer must remain valid
|
||||
// at least until the element is removed from the list or the list is freed.
|
||||
// Returns true if |data| could be inserted, false otherwise (e.g. out of memory).
|
||||
bool list_append(list_t *list, void *data);
|
||||
|
||||
// Removes |data| from the list. Neither |list| nor |data| may be NULL. If |data|
|
||||
// is inserted multiple times in the list, this function will only remove the first
|
||||
// instance. If a free function was specified in |list_new|, it will be called back
|
||||
// with |data|. This function returns true if |data| was found in the list and removed,
|
||||
// false otherwise.
|
||||
//list_node_t list_remove_node(list_t *list, list_node_t *prev_node, list_node_t *node);
|
||||
//list_node_t list_insert_node(list_t *list, list_node_t *prev_node, list_node_t *node);
|
||||
|
||||
bool list_remove(list_t *list, void *data);
|
||||
|
||||
// similar with list_remove, but do not free the node data
|
||||
bool list_delete(list_t *list, void *data);
|
||||
|
||||
// Removes all elements in the list. Calling this function will return the list to the
|
||||
// same state it was in after |list_new|. |list| may not be NULL.
|
||||
void list_clear(list_t *list);
|
||||
|
||||
// Iterates through the entire |list| and calls |callback| for each data element.
|
||||
// If the list is empty, |callback| will never be called. It is safe to mutate the
|
||||
// list inside the callback. If an element is added before the node being visited,
|
||||
// there will be no callback for the newly-inserted node. Neither |list| nor
|
||||
// |callback| may be NULL.
|
||||
list_node_t *list_foreach(const list_t *list, list_iter_cb callback, void *context);
|
||||
|
||||
// Returns an iterator to the first element in |list|. |list| may not be NULL.
|
||||
// The returned iterator is valid as long as it does not equal the value returned
|
||||
// by |list_end|.
|
||||
list_node_t *list_begin(const list_t *list);
|
||||
|
||||
// Returns an iterator that points past the end of the list. In other words,
|
||||
// this function returns the value of an invalid iterator for the given list.
|
||||
// When an iterator has the same value as what's returned by this function, you
|
||||
// may no longer call |list_next| with the iterator. |list| may not be NULL.
|
||||
list_node_t *list_end(const list_t *list);
|
||||
|
||||
// Given a valid iterator |node|, this function returns the next value for the
|
||||
// iterator. If the returned value equals the value returned by |list_end|, the
|
||||
// iterator has reached the end of the list and may no longer be used for any
|
||||
// purpose.
|
||||
list_node_t *list_next(const list_node_t *node);
|
||||
|
||||
// Returns the value stored at the location pointed to by the iterator |node|.
|
||||
// |node| must not equal the value returned by |list_end|.
|
||||
void *list_node(const list_node_t *node);
|
||||
|
||||
#endif /* _LIST_H_ */
|
||||
@@ -0,0 +1,52 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __MUTEX_H__
|
||||
#define __MUTEX_H__
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
#define OSI_MUTEX_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT
|
||||
|
||||
#define osi_mutex_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
|
||||
#define osi_mutex_set_invalid( x ) ( ( *x ) = NULL )
|
||||
|
||||
typedef SemaphoreHandle_t osi_mutex_t;
|
||||
|
||||
int osi_mutex_new(osi_mutex_t *mutex);
|
||||
|
||||
int osi_mutex_lock(osi_mutex_t *mutex, uint32_t timeout);
|
||||
|
||||
void osi_mutex_unlock(osi_mutex_t *mutex);
|
||||
|
||||
void osi_mutex_free(osi_mutex_t *mutex);
|
||||
|
||||
/* Just for a global mutex */
|
||||
int osi_mutex_global_init(void);
|
||||
|
||||
void osi_mutex_global_deinit(void);
|
||||
|
||||
void osi_mutex_global_lock(void);
|
||||
|
||||
void osi_mutex_global_unlock(void);
|
||||
|
||||
#endif /* __MUTEX_H__ */
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef _OSI_H_
|
||||
#define _OSI_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define UNUSED_ATTR __attribute__((unused))
|
||||
|
||||
#define CONCAT(a, b) a##b
|
||||
#define COMPILE_ASSERT(x)
|
||||
|
||||
int osi_init(void);
|
||||
void osi_deinit(void);
|
||||
|
||||
#endif /*_OSI_H_*/
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef _PKT_LIST_H_
|
||||
#define _PKT_LIST_H_
|
||||
|
||||
#include "sys/queue.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct pkt_queue;
|
||||
|
||||
typedef struct pkt_linked_item {
|
||||
STAILQ_ENTRY(pkt_linked_item) next;
|
||||
uint8_t data[];
|
||||
} pkt_linked_item_t;
|
||||
|
||||
#define BT_PKT_LINKED_HDR_SIZE (sizeof (pkt_linked_item_t))
|
||||
|
||||
typedef void (*pkt_queue_free_cb)(pkt_linked_item_t *item);
|
||||
|
||||
/*
|
||||
* brief: create a pkt_queue instance. pkt_queue is a wrapper class of a FIFO implemented by single linked list.
|
||||
* The enqueue and dequeue operations of the FIFO are protected against race conditions of multiple tasks
|
||||
* return: NULL if not enough memory, otherwise a valid pointer
|
||||
*/
|
||||
struct pkt_queue *pkt_queue_create(void);
|
||||
|
||||
/*
|
||||
* brief: enqueue one item to the FIFO
|
||||
* param queue: pkt_queue instance created using pkt_queue_create
|
||||
* param item: the item to be enqueued to the FIFO
|
||||
* return: true if enqueued successfully, false when the arguments passed in are invalid
|
||||
*/
|
||||
bool pkt_queue_enqueue(struct pkt_queue *queue, pkt_linked_item_t *item);
|
||||
|
||||
/*
|
||||
* brief: dequeue one item for the FIFO
|
||||
* param queue: pkt_queue instance created using pkt_queue_create
|
||||
* return: pointer of type pkt_linked_item_t dequeued, NULL if the queue is empty or upon exception
|
||||
*/
|
||||
pkt_linked_item_t *pkt_queue_dequeue(struct pkt_queue *queue);
|
||||
|
||||
/*
|
||||
* brief: get the pointer of the first item from the FIFO but not get it dequeued
|
||||
* param queue: pkt_queue instance created using pkt_queue_create
|
||||
* return: pointer of the first item in the FIFO, NULL if the FIFO is empty
|
||||
*/
|
||||
pkt_linked_item_t *pkt_queue_try_peek_first(struct pkt_queue *queue);
|
||||
|
||||
/*
|
||||
* brief: retrieve the number of items existing in the FIFO
|
||||
* param queue: pkt_queue instance created using pkt_queue_create
|
||||
* return: total number of items in the FIFO
|
||||
*/
|
||||
size_t pkt_queue_length(const struct pkt_queue *queue);
|
||||
|
||||
/*
|
||||
* brief: retrieve the status whether the FIFO is empty
|
||||
* param queue: pkt_queue instance created using pkt_queue_create
|
||||
* return: false if the FIFO is not empty, otherwise true
|
||||
*/
|
||||
bool pkt_queue_is_empty(const struct pkt_queue *queue);
|
||||
|
||||
/*
|
||||
* brief: delete the item in the FIFO one by one
|
||||
* param free_cb: destructor function for each item in the FIFO, if set to NULL, will use osi_free_func by default
|
||||
*/
|
||||
void pkt_queue_flush(struct pkt_queue *queue, pkt_queue_free_cb free_cb);
|
||||
|
||||
/*
|
||||
* brief: delete the items in the FIFO and then destroy the pkt_queue instance.
|
||||
* param free_cb: destructor function for each item in the FIFO, if set to NULL, will use osi_free_func by default
|
||||
*/
|
||||
void pkt_queue_destroy(struct pkt_queue *queue, pkt_queue_free_cb free_cb);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#ifndef __SEMAPHORE_H__
|
||||
#define __SEMAPHORE_H__
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#define OSI_SEM_MAX_TIMEOUT 0xffffffffUL
|
||||
|
||||
typedef SemaphoreHandle_t osi_sem_t;
|
||||
|
||||
#define osi_sem_valid( x ) ( ( ( *x ) == NULL) ? pdFALSE : pdTRUE )
|
||||
#define osi_sem_set_invalid( x ) ( ( *x ) = NULL )
|
||||
|
||||
int osi_sem_new(osi_sem_t *sem, uint32_t max_count, uint32_t init_count);
|
||||
|
||||
void osi_sem_free(osi_sem_t *sem);
|
||||
|
||||
int osi_sem_take(osi_sem_t *sem, uint32_t timeout);
|
||||
|
||||
void osi_sem_give(osi_sem_t *sem);
|
||||
|
||||
|
||||
#endif /* __SEMAPHORE_H__ */
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef __THREAD_H__
|
||||
#define __THREAD_H__
|
||||
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "osi/semaphore.h"
|
||||
#include "esp_task.h"
|
||||
#include "bt_common.h"
|
||||
|
||||
#define OSI_THREAD_MAX_TIMEOUT OSI_SEM_MAX_TIMEOUT
|
||||
|
||||
struct osi_thread;
|
||||
struct osi_event;
|
||||
|
||||
typedef struct osi_thread osi_thread_t;
|
||||
|
||||
typedef void (*osi_thread_func_t)(void *context);
|
||||
|
||||
typedef enum {
|
||||
OSI_THREAD_CORE_0 = 0,
|
||||
OSI_THREAD_CORE_1,
|
||||
OSI_THREAD_CORE_AFFINITY,
|
||||
} osi_thread_core_t;
|
||||
|
||||
/*
|
||||
* brief: Create a thread or task
|
||||
* param name: thread name
|
||||
* param stack_size: thread stack size
|
||||
* param priority: thread priority
|
||||
* param core: the CPU core which this thread run, OSI_THREAD_CORE_AFFINITY means unspecific CPU core
|
||||
* param work_queue_num: speicify queue number, the queue[0] has highest priority, and the priority is decrease by index
|
||||
* return : if create successfully, return thread handler; otherwise return NULL.
|
||||
*/
|
||||
osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[]);
|
||||
|
||||
/*
|
||||
* brief: Destroy a thread or task
|
||||
* param thread: point of thread handler
|
||||
*/
|
||||
void osi_thread_free(osi_thread_t *thread);
|
||||
|
||||
/*
|
||||
* brief: Post an msg to a thread and told the thread call the function
|
||||
* param thread: point of thread handler
|
||||
* param func: callback function that called by target thread
|
||||
* param context: argument of callback function
|
||||
* param queue_idx: the queue which the msg send to
|
||||
* param timeout: post timeout, OSI_THREAD_MAX_TIMEOUT means blocking forever, 0 means never blocking, others means block millisecond
|
||||
* return : if post successfully, return true, otherwise return false
|
||||
*/
|
||||
bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, uint32_t timeout);
|
||||
|
||||
/*
|
||||
* brief: Set the priority of thread
|
||||
* param thread: point of thread handler
|
||||
* param priority: priority
|
||||
* return : if set successfully, return true, otherwise return false
|
||||
*/
|
||||
bool osi_thread_set_priority(osi_thread_t *thread, int priority);
|
||||
|
||||
/* brief: Get thread name
|
||||
* param thread: point of thread handler
|
||||
* return: constant point of thread name
|
||||
*/
|
||||
const char *osi_thread_name(osi_thread_t *thread);
|
||||
|
||||
/* brief: Get the size of the specified queue
|
||||
* param thread: point of thread handler
|
||||
* param wq_idx: the queue index of the thread
|
||||
* return: queue size
|
||||
*/
|
||||
int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx);
|
||||
|
||||
/*
|
||||
* brief: Create an osi_event struct and register the handler function and its argument
|
||||
* An osi_event is a kind of work that can be posted to the workqueue of osi_thread to process,
|
||||
* but the work can have at most one instance the thread workqueue before it is processed. This
|
||||
* allows the "single post, multiple data processing" jobs.
|
||||
* param func: the handler to process the job
|
||||
* param context: the argument to be passed to the handler function when the job is being processed
|
||||
* return: NULL if no memory, otherwise a valid struct pointer
|
||||
*/
|
||||
struct osi_event *osi_event_create(osi_thread_func_t func, void *context);
|
||||
|
||||
/*
|
||||
* brief: Bind an osi_event to a specific work queue for an osi_thread.
|
||||
* After binding is completed, a function call of API osi_thread_post_event will send a work
|
||||
* to the workqueue of the thread, with specified queue index.
|
||||
* param func: event: the pointer to osi_event that is created using osi_event_create
|
||||
* param thread: the pointer to osi_thread that is created using osi_thread_create
|
||||
* param queue_idx: the index of the workqueue of the specified osi_thread, with range starting from 0 to work_queue_num - 1
|
||||
* return: true if osi_event binds to the thread's workqueue successfully, otherwise false
|
||||
*/
|
||||
bool osi_event_bind(struct osi_event* event, osi_thread_t *thread, int queue_idx);
|
||||
|
||||
/*
|
||||
* brief: Destroy the osi_event struct created by osi_event_create and free the allocated memory
|
||||
* param event: the pointer to osi_event
|
||||
*/
|
||||
void osi_event_delete(struct osi_event* event);
|
||||
|
||||
/*
|
||||
* brief: try sending a work to the binded thread's workqueue, so that it can be handled by the worker thread
|
||||
* param event: pointer to osi_event, created by osi_event_create
|
||||
* param timeout: post timeout, OSI_THREAD_MAX_TIMEOUT means blocking forever, 0 means never blocking, others means block millisecond
|
||||
* return: true if the message is enqueued to the thread workqueue, otherwise failed
|
||||
* note: if the return value of function is false, it is the case that the workqueue of the thread is full, and users
|
||||
* are expected to post the event sometime later to get the work handled.
|
||||
*/
|
||||
bool osi_thread_post_event(struct osi_event *event, uint32_t timeout);
|
||||
|
||||
#endif /* __THREAD_H__ */
|
||||
@@ -0,0 +1,312 @@
|
||||
|
||||
#include "bt_common.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/list.h"
|
||||
#include "osi/osi.h"
|
||||
|
||||
struct list_node_t {
|
||||
struct list_node_t *next;
|
||||
void *data;
|
||||
};
|
||||
|
||||
typedef struct list_t {
|
||||
list_node_t *head;
|
||||
list_node_t *tail;
|
||||
size_t length;
|
||||
list_free_cb free_cb;
|
||||
} list_t;
|
||||
|
||||
//static list_node_t *list_free_node_(list_t *list, list_node_t *node);
|
||||
|
||||
// Hidden constructor, only to be used by the hash map for the allocation tracker.
|
||||
// Behaves the same as |list_new|, except you get to specify the allocator.
|
||||
list_t *list_new_internal(list_free_cb callback)
|
||||
{
|
||||
list_t *list = (list_t *) osi_calloc(sizeof(list_t));
|
||||
if (!list) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->head = list->tail = NULL;
|
||||
list->length = 0;
|
||||
list->free_cb = callback;
|
||||
return list;
|
||||
}
|
||||
|
||||
list_t *list_new(list_free_cb callback)
|
||||
{
|
||||
return list_new_internal(callback);
|
||||
}
|
||||
|
||||
void list_free(list_t *list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
list_clear(list);
|
||||
osi_free(list);
|
||||
}
|
||||
|
||||
bool list_is_empty(const list_t *list)
|
||||
{
|
||||
assert(list != NULL);
|
||||
return (list->length == 0);
|
||||
}
|
||||
|
||||
bool list_contains(const list_t *list, const void *data)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
for (const list_node_t *node = list_begin(list); node != list_end(list); node = list_next(node)) {
|
||||
if (list_node(node) == data) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
list_node_t *list_get_node(const list_t *list, const void *data)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(data != NULL);
|
||||
list_node_t *p_node_ret = NULL;
|
||||
for (list_node_t *node = list_begin(list); node != list_end(list); node = list_next(node)) {
|
||||
if (list_node(node) == data) {
|
||||
p_node_ret = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return p_node_ret;
|
||||
}
|
||||
|
||||
size_t list_length(const list_t *list)
|
||||
{
|
||||
assert(list != NULL);
|
||||
return list->length;
|
||||
}
|
||||
|
||||
void *list_front(const list_t *list)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(!list_is_empty(list));
|
||||
|
||||
return list->head->data;
|
||||
}
|
||||
|
||||
void *list_back(const list_t *list) {
|
||||
assert(list != NULL);
|
||||
assert(!list_is_empty(list));
|
||||
|
||||
return list->tail->data;
|
||||
}
|
||||
|
||||
list_node_t *list_back_node(const list_t *list) {
|
||||
assert(list != NULL);
|
||||
assert(!list_is_empty(list));
|
||||
|
||||
return list->tail;
|
||||
}
|
||||
|
||||
bool list_insert_after(list_t *list, list_node_t *prev_node, void *data) {
|
||||
assert(list != NULL);
|
||||
assert(prev_node != NULL);
|
||||
assert(data != NULL);
|
||||
list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t));
|
||||
if (!node) {
|
||||
OSI_TRACE_ERROR("%s osi_calloc failed.\n", __FUNCTION__ );
|
||||
return false;
|
||||
}
|
||||
node->next = prev_node->next;
|
||||
node->data = data;
|
||||
prev_node->next = node;
|
||||
if (list->tail == prev_node) {
|
||||
list->tail = node;
|
||||
}
|
||||
++list->length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool list_prepend(list_t *list, void *data)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(data != NULL);
|
||||
list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t));
|
||||
if (!node) {
|
||||
OSI_TRACE_ERROR("%s osi_calloc failed.\n", __FUNCTION__ );
|
||||
return false;
|
||||
}
|
||||
node->next = list->head;
|
||||
node->data = data;
|
||||
list->head = node;
|
||||
if (list->tail == NULL) {
|
||||
list->tail = list->head;
|
||||
}
|
||||
++list->length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool list_append(list_t *list, void *data)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(data != NULL);
|
||||
list_node_t *node = (list_node_t *)osi_calloc(sizeof(list_node_t));
|
||||
if (!node) {
|
||||
OSI_TRACE_ERROR("%s osi_calloc failed.\n", __FUNCTION__ );
|
||||
return false;
|
||||
}
|
||||
node->next = NULL;
|
||||
node->data = data;
|
||||
if (list->tail == NULL) {
|
||||
list->head = node;
|
||||
list->tail = node;
|
||||
} else {
|
||||
list->tail->next = node;
|
||||
list->tail = node;
|
||||
}
|
||||
++list->length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool list_remove(list_t *list, void *data)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
if (list_is_empty(list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (list->head->data == data) {
|
||||
list_node_t *next = list_free_node(list, list->head);
|
||||
if (list->tail == list->head) {
|
||||
list->tail = next;
|
||||
}
|
||||
list->head = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
|
||||
if (node->data == data) {
|
||||
prev->next = list_free_node(list, node);
|
||||
if (list->tail == node) {
|
||||
list->tail = prev;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool list_delete(list_t *list, void *data)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(data != NULL);
|
||||
|
||||
if (list_is_empty(list)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (list->head->data == data) {
|
||||
list_node_t *next = list_delete_node(list, list->head);
|
||||
if (list->tail == list->head) {
|
||||
list->tail = next;
|
||||
}
|
||||
list->head = next;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (list_node_t *prev = list->head, *node = list->head->next; node; prev = node, node = node->next)
|
||||
if (node->data == data) {
|
||||
prev->next = list_delete_node(list, node);
|
||||
if (list->tail == node) {
|
||||
list->tail = prev;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void list_clear(list_t *list)
|
||||
{
|
||||
assert(list != NULL);
|
||||
for (list_node_t *node = list->head; node; ) {
|
||||
node = list_free_node(list, node);
|
||||
}
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
list->length = 0;
|
||||
}
|
||||
|
||||
list_node_t *list_foreach(const list_t *list, list_iter_cb callback, void *context)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(callback != NULL);
|
||||
|
||||
for (list_node_t *node = list->head; node; ) {
|
||||
list_node_t *next = node->next;
|
||||
if (!callback(node->data, context)) {
|
||||
return node;
|
||||
}
|
||||
node = next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_node_t *list_begin(const list_t *list)
|
||||
{
|
||||
assert(list != NULL);
|
||||
return list->head;
|
||||
}
|
||||
|
||||
list_node_t *list_end(UNUSED_ATTR const list_t *list)
|
||||
{
|
||||
assert(list != NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_node_t *list_next(const list_node_t *node)
|
||||
{
|
||||
assert(node != NULL);
|
||||
return node->next;
|
||||
}
|
||||
|
||||
void *list_node(const list_node_t *node)
|
||||
{
|
||||
assert(node != NULL);
|
||||
return node->data;
|
||||
}
|
||||
|
||||
list_node_t *list_free_node(list_t *list, list_node_t *node)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(node != NULL);
|
||||
|
||||
list_node_t *next = node->next;
|
||||
|
||||
if (list->free_cb) {
|
||||
list->free_cb(node->data);
|
||||
}
|
||||
osi_free(node);
|
||||
--list->length;
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
// remove the element from list but do not free the node data
|
||||
list_node_t *list_delete_node(list_t *list, list_node_t *node)
|
||||
{
|
||||
assert(list != NULL);
|
||||
assert(node != NULL);
|
||||
|
||||
list_node_t *next = node->next;
|
||||
|
||||
osi_free(node);
|
||||
--list->length;
|
||||
|
||||
return next;
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include "osi/mutex.h"
|
||||
|
||||
|
||||
/* static section */
|
||||
static osi_mutex_t gl_mutex; /* Recursive Type */
|
||||
|
||||
|
||||
/** Create a new mutex
|
||||
* @param mutex pointer to the mutex to create
|
||||
* @return a new mutex */
|
||||
int osi_mutex_new(osi_mutex_t *mutex)
|
||||
{
|
||||
int xReturn = -1;
|
||||
|
||||
*mutex = xSemaphoreCreateMutex();
|
||||
|
||||
if (*mutex != NULL) {
|
||||
xReturn = 0;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
|
||||
/** Lock a mutex
|
||||
* @param mutex the mutex to lock */
|
||||
int osi_mutex_lock(osi_mutex_t *mutex, uint32_t timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (timeout == OSI_MUTEX_MAX_TIMEOUT) {
|
||||
if (xSemaphoreTake(*mutex, portMAX_DELAY) != pdTRUE) {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
if (xSemaphoreTake(*mutex, timeout / portTICK_PERIOD_MS) != pdTRUE) {
|
||||
ret = -2;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Unlock a mutex
|
||||
* @param mutex the mutex to unlock */
|
||||
void osi_mutex_unlock(osi_mutex_t *mutex)
|
||||
{
|
||||
xSemaphoreGive(*mutex);
|
||||
}
|
||||
|
||||
/** Delete a semaphore
|
||||
* @param mutex the mutex to delete */
|
||||
void osi_mutex_free(osi_mutex_t *mutex)
|
||||
{
|
||||
vSemaphoreDelete(*mutex);
|
||||
*mutex = NULL;
|
||||
}
|
||||
|
||||
int osi_mutex_global_init(void)
|
||||
{
|
||||
gl_mutex = xSemaphoreCreateRecursiveMutex();
|
||||
if (gl_mutex == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void osi_mutex_global_deinit(void)
|
||||
{
|
||||
vSemaphoreDelete(gl_mutex);
|
||||
}
|
||||
|
||||
void osi_mutex_global_lock(void)
|
||||
{
|
||||
xSemaphoreTakeRecursive(gl_mutex, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void osi_mutex_global_unlock(void)
|
||||
{
|
||||
xSemaphoreGiveRecursive(gl_mutex);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include "osi/osi.h"
|
||||
#include "osi/mutex.h"
|
||||
|
||||
int osi_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (osi_mutex_global_init() != 0) {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void osi_deinit(void)
|
||||
{
|
||||
osi_mutex_global_deinit();
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "osi/pkt_queue.h"
|
||||
#include "osi/allocator.h"
|
||||
#include "osi/mutex.h"
|
||||
|
||||
|
||||
STAILQ_HEAD(pkt_queue_header, pkt_linked_item);
|
||||
|
||||
struct pkt_queue {
|
||||
osi_mutex_t lock;
|
||||
size_t length;
|
||||
struct pkt_queue_header header;
|
||||
} pkt_queue_t;
|
||||
|
||||
struct pkt_queue *pkt_queue_create(void)
|
||||
{
|
||||
struct pkt_queue *queue = calloc(1, sizeof(struct pkt_queue));
|
||||
if (queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
if (osi_mutex_new(&queue->lock) != 0) {
|
||||
osi_free(queue);
|
||||
}
|
||||
struct pkt_queue_header *p = &queue->header;
|
||||
STAILQ_INIT(p);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
||||
static void pkt_queue_cleanup(struct pkt_queue *queue, pkt_queue_free_cb free_cb)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct pkt_queue_header *header = &queue->header;
|
||||
pkt_linked_item_t *item = STAILQ_FIRST(header);
|
||||
pkt_linked_item_t *tmp;
|
||||
|
||||
pkt_queue_free_cb free_func = (free_cb != NULL) ? free_cb : (pkt_queue_free_cb)osi_free_func;
|
||||
|
||||
while (item != NULL) {
|
||||
tmp = STAILQ_NEXT(item, next);
|
||||
free_func(item);
|
||||
item = tmp;
|
||||
queue->length--;
|
||||
}
|
||||
STAILQ_INIT(header);
|
||||
queue->length = 0;
|
||||
}
|
||||
|
||||
void pkt_queue_flush(struct pkt_queue *queue, pkt_queue_free_cb free_cb)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return;
|
||||
}
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
pkt_queue_cleanup(queue, free_cb);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
void pkt_queue_destroy(struct pkt_queue *queue, pkt_queue_free_cb free_cb)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return;
|
||||
}
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
pkt_queue_cleanup(queue, free_cb);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
osi_mutex_free(&queue->lock);
|
||||
osi_free(queue);
|
||||
}
|
||||
|
||||
pkt_linked_item_t *pkt_queue_dequeue(struct pkt_queue *queue)
|
||||
{
|
||||
if (queue == NULL || queue->length == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pkt_linked_item *item;
|
||||
struct pkt_queue_header *header;
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
header = &queue->header;
|
||||
item = STAILQ_FIRST(header);
|
||||
if (item != NULL) {
|
||||
STAILQ_REMOVE_HEAD(header, next);
|
||||
if (queue->length > 0) {
|
||||
queue->length--;
|
||||
}
|
||||
}
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
bool pkt_queue_enqueue(struct pkt_queue *queue, pkt_linked_item_t *item)
|
||||
{
|
||||
if (queue == NULL || item == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct pkt_queue_header *header;
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
header = &queue->header;
|
||||
STAILQ_INSERT_TAIL(header, item, next);
|
||||
queue->length++;
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t pkt_queue_length(const struct pkt_queue *queue)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return queue->length;
|
||||
}
|
||||
|
||||
bool pkt_queue_is_empty(const struct pkt_queue *queue)
|
||||
{
|
||||
return pkt_queue_length(queue) == 0;
|
||||
}
|
||||
|
||||
pkt_linked_item_t *pkt_queue_try_peek_first(struct pkt_queue *queue)
|
||||
{
|
||||
if (queue == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct pkt_queue_header *header = &queue->header;
|
||||
pkt_linked_item_t *item;
|
||||
osi_mutex_lock(&queue->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
item = STAILQ_FIRST(header);
|
||||
osi_mutex_unlock(&queue->lock);
|
||||
|
||||
return item;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2015 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
#include "osi/semaphore.h"
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Creates and returns a new semaphore. The "init_count" argument specifies
|
||||
// the initial state of the semaphore, "max_count" specifies the maximum value
|
||||
// that can be reached.
|
||||
int osi_sem_new(osi_sem_t *sem, uint32_t max_count, uint32_t init_count)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if (sem) {
|
||||
*sem = xSemaphoreCreateCounting(max_count, init_count);
|
||||
if ((*sem) != NULL) {
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
// Give a semaphore
|
||||
void osi_sem_give(osi_sem_t *sem)
|
||||
{
|
||||
xSemaphoreGive(*sem);
|
||||
}
|
||||
|
||||
/*
|
||||
Blocks the thread while waiting for the semaphore to be
|
||||
signaled. If the "timeout" argument is non-zero, the thread should
|
||||
only be blocked for the specified time (measured in
|
||||
milliseconds).
|
||||
|
||||
*/
|
||||
int
|
||||
osi_sem_take(osi_sem_t *sem, uint32_t timeout)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (timeout == OSI_SEM_MAX_TIMEOUT) {
|
||||
if (xSemaphoreTake(*sem, portMAX_DELAY) != pdTRUE) {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
if (xSemaphoreTake(*sem, timeout / portTICK_PERIOD_MS) != pdTRUE) {
|
||||
ret = -2;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Deallocates a semaphore
|
||||
void osi_sem_free(osi_sem_t *sem)
|
||||
{
|
||||
vSemaphoreDelete(*sem);
|
||||
*sem = NULL;
|
||||
}
|
||||
@@ -0,0 +1,453 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "osi/allocator.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "osi/semaphore.h"
|
||||
#include "osi/thread.h"
|
||||
#include "osi/mutex.h"
|
||||
|
||||
struct work_item {
|
||||
osi_thread_func_t func;
|
||||
void *context;
|
||||
};
|
||||
|
||||
struct work_queue {
|
||||
QueueHandle_t queue;
|
||||
size_t capacity;
|
||||
};
|
||||
|
||||
struct osi_thread {
|
||||
TaskHandle_t thread_handle; /*!< Store the thread object */
|
||||
int thread_id; /*!< May for some OS, such as Linux */
|
||||
bool stop;
|
||||
uint8_t work_queue_num; /*!< Work queue number */
|
||||
struct work_queue **work_queues; /*!< Point to queue array, and the priority inverse array index */
|
||||
osi_sem_t work_sem;
|
||||
osi_sem_t stop_sem;
|
||||
};
|
||||
|
||||
struct osi_thread_start_arg {
|
||||
osi_thread_t *thread;
|
||||
osi_sem_t start_sem;
|
||||
int error;
|
||||
};
|
||||
|
||||
struct osi_event {
|
||||
struct work_item item;
|
||||
osi_mutex_t lock;
|
||||
uint16_t is_queued;
|
||||
uint16_t queue_idx;
|
||||
osi_thread_t *thread;
|
||||
};
|
||||
|
||||
static const size_t DEFAULT_WORK_QUEUE_CAPACITY = 100;
|
||||
|
||||
static struct work_queue *osi_work_queue_create(size_t capacity)
|
||||
{
|
||||
if (capacity == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct work_queue *wq = (struct work_queue *)osi_malloc(sizeof(struct work_queue));
|
||||
if (wq != NULL) {
|
||||
wq->queue = xQueueCreate(capacity, sizeof(struct work_item));
|
||||
if (wq->queue != 0) {
|
||||
wq->capacity = capacity;
|
||||
return wq;
|
||||
} else {
|
||||
osi_free(wq);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void osi_work_queue_delete(struct work_queue *wq)
|
||||
{
|
||||
if (wq != NULL) {
|
||||
if (wq->queue != 0) {
|
||||
vQueueDelete(wq->queue);
|
||||
}
|
||||
wq->queue = 0;
|
||||
wq->capacity = 0;
|
||||
osi_free(wq);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static bool osi_thead_work_queue_get(struct work_queue *wq, struct work_item *item)
|
||||
{
|
||||
assert (wq != NULL);
|
||||
assert (wq->queue != 0);
|
||||
assert (item != NULL);
|
||||
|
||||
if (pdTRUE == xQueueReceive(wq->queue, item, 0)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool osi_thead_work_queue_put(struct work_queue *wq, const struct work_item *item, uint32_t timeout)
|
||||
{
|
||||
assert (wq != NULL);
|
||||
assert (wq->queue != 0);
|
||||
assert (item != NULL);
|
||||
|
||||
bool ret = true;
|
||||
if (timeout == OSI_SEM_MAX_TIMEOUT) {
|
||||
if (xQueueSend(wq->queue, item, portMAX_DELAY) != pdTRUE) {
|
||||
ret = false;
|
||||
}
|
||||
} else {
|
||||
if (xQueueSend(wq->queue, item, timeout / portTICK_PERIOD_MS) != pdTRUE) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t osi_thead_work_queue_len(struct work_queue *wq)
|
||||
{
|
||||
assert (wq != NULL);
|
||||
assert (wq->queue != 0);
|
||||
assert (wq->capacity != 0);
|
||||
|
||||
size_t available_spaces = (size_t)uxQueueSpacesAvailable(wq->queue);
|
||||
|
||||
if (available_spaces <= wq->capacity) {
|
||||
return wq->capacity - available_spaces;
|
||||
} else {
|
||||
assert (0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void osi_thread_run(void *arg)
|
||||
{
|
||||
struct osi_thread_start_arg *start = (struct osi_thread_start_arg *)arg;
|
||||
osi_thread_t *thread = start->thread;
|
||||
|
||||
osi_sem_give(&start->start_sem);
|
||||
|
||||
while (1) {
|
||||
int idx = 0;
|
||||
|
||||
osi_sem_take(&thread->work_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
|
||||
if (thread->stop) {
|
||||
break;
|
||||
}
|
||||
|
||||
struct work_item item;
|
||||
while (!thread->stop && idx < thread->work_queue_num) {
|
||||
if (osi_thead_work_queue_get(thread->work_queues[idx], &item) == true) {
|
||||
item.func(item.context);
|
||||
idx = 0;
|
||||
continue;
|
||||
} else {
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
thread->thread_handle = NULL;
|
||||
osi_sem_give(&thread->stop_sem);
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static int osi_thread_join(osi_thread_t *thread, uint32_t wait_ms)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
return osi_sem_take(&thread->stop_sem, wait_ms);
|
||||
}
|
||||
|
||||
static void osi_thread_stop(osi_thread_t *thread)
|
||||
{
|
||||
int ret;
|
||||
|
||||
assert(thread != NULL);
|
||||
|
||||
//stop the thread
|
||||
thread->stop = true;
|
||||
osi_sem_give(&thread->work_sem);
|
||||
|
||||
//join
|
||||
ret = osi_thread_join(thread, 1000); //wait 1000ms
|
||||
|
||||
//if join failed, delete the task here
|
||||
if (ret != 0 && thread->thread_handle) {
|
||||
vTaskDelete(thread->thread_handle);
|
||||
}
|
||||
}
|
||||
|
||||
//in linux, the stack_size, priority and core may not be set here, the code will be ignore the arguments
|
||||
osi_thread_t *osi_thread_create(const char *name, size_t stack_size, int priority, osi_thread_core_t core, uint8_t work_queue_num, const size_t work_queue_len[])
|
||||
{
|
||||
int ret;
|
||||
struct osi_thread_start_arg start_arg = {0};
|
||||
|
||||
if (stack_size <= 0 ||
|
||||
core < OSI_THREAD_CORE_0 || core > OSI_THREAD_CORE_AFFINITY ||
|
||||
work_queue_num <= 0 || work_queue_len == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
osi_thread_t *thread = (osi_thread_t *)osi_calloc(sizeof(osi_thread_t));
|
||||
if (thread == NULL) {
|
||||
goto _err;
|
||||
}
|
||||
|
||||
thread->stop = false;
|
||||
thread->work_queues = (struct work_queue **)osi_calloc(sizeof(struct work_queue *) * work_queue_num);
|
||||
if (thread->work_queues == NULL) {
|
||||
goto _err;
|
||||
}
|
||||
thread->work_queue_num = work_queue_num;
|
||||
|
||||
for (int i = 0; i < thread->work_queue_num; i++) {
|
||||
size_t queue_len = work_queue_len[i] ? work_queue_len[i] : DEFAULT_WORK_QUEUE_CAPACITY;
|
||||
thread->work_queues[i] = osi_work_queue_create(queue_len);
|
||||
if (thread->work_queues[i] == NULL) {
|
||||
goto _err;
|
||||
}
|
||||
}
|
||||
|
||||
ret = osi_sem_new(&thread->work_sem, 1, 0);
|
||||
if (ret != 0) {
|
||||
goto _err;
|
||||
}
|
||||
|
||||
ret = osi_sem_new(&thread->stop_sem, 1, 0);
|
||||
if (ret != 0) {
|
||||
goto _err;
|
||||
}
|
||||
|
||||
start_arg.thread = thread;
|
||||
ret = osi_sem_new(&start_arg.start_sem, 1, 0);
|
||||
if (ret != 0) {
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (xTaskCreatePinnedToCore(osi_thread_run, name, stack_size, &start_arg, priority, &thread->thread_handle, core) != pdPASS) {
|
||||
goto _err;
|
||||
}
|
||||
|
||||
osi_sem_take(&start_arg.start_sem, OSI_SEM_MAX_TIMEOUT);
|
||||
osi_sem_free(&start_arg.start_sem);
|
||||
|
||||
return thread;
|
||||
|
||||
_err:
|
||||
|
||||
if (thread) {
|
||||
if (start_arg.start_sem) {
|
||||
osi_sem_free(&start_arg.start_sem);
|
||||
}
|
||||
|
||||
if (thread->thread_handle) {
|
||||
vTaskDelete(thread->thread_handle);
|
||||
}
|
||||
|
||||
for (int i = 0; i < thread->work_queue_num; i++) {
|
||||
if (thread->work_queues[i]) {
|
||||
osi_work_queue_delete(thread->work_queues[i]);
|
||||
}
|
||||
thread->work_queues[i] = NULL;
|
||||
}
|
||||
|
||||
if (thread->work_queues) {
|
||||
osi_free(thread->work_queues);
|
||||
thread->work_queues = NULL;
|
||||
}
|
||||
|
||||
if (thread->work_sem) {
|
||||
osi_sem_free(&thread->work_sem);
|
||||
}
|
||||
|
||||
if (thread->stop_sem) {
|
||||
osi_sem_free(&thread->stop_sem);
|
||||
}
|
||||
|
||||
osi_free(thread);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void osi_thread_free(osi_thread_t *thread)
|
||||
{
|
||||
if (!thread)
|
||||
return;
|
||||
|
||||
osi_thread_stop(thread);
|
||||
|
||||
for (int i = 0; i < thread->work_queue_num; i++) {
|
||||
if (thread->work_queues[i]) {
|
||||
osi_work_queue_delete(thread->work_queues[i]);
|
||||
thread->work_queues[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (thread->work_queues) {
|
||||
osi_free(thread->work_queues);
|
||||
thread->work_queues = NULL;
|
||||
}
|
||||
|
||||
if (thread->work_sem) {
|
||||
osi_sem_free(&thread->work_sem);
|
||||
}
|
||||
|
||||
if (thread->stop_sem) {
|
||||
osi_sem_free(&thread->stop_sem);
|
||||
}
|
||||
|
||||
|
||||
osi_free(thread);
|
||||
}
|
||||
|
||||
bool osi_thread_post(osi_thread_t *thread, osi_thread_func_t func, void *context, int queue_idx, uint32_t timeout)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
assert(func != NULL);
|
||||
|
||||
if (queue_idx >= thread->work_queue_num) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct work_item item;
|
||||
|
||||
item.func = func;
|
||||
item.context = context;
|
||||
|
||||
if (osi_thead_work_queue_put(thread->work_queues[queue_idx], &item, timeout) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
osi_sem_give(&thread->work_sem);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool osi_thread_set_priority(osi_thread_t *thread, int priority)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
|
||||
vTaskPrioritySet(thread->thread_handle, priority);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *osi_thread_name(osi_thread_t *thread)
|
||||
{
|
||||
assert(thread != NULL);
|
||||
|
||||
return pcTaskGetName(thread->thread_handle);
|
||||
}
|
||||
|
||||
int osi_thread_queue_wait_size(osi_thread_t *thread, int wq_idx)
|
||||
{
|
||||
if (wq_idx < 0 || wq_idx >= thread->work_queue_num) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)(osi_thead_work_queue_len(thread->work_queues[wq_idx]));
|
||||
}
|
||||
|
||||
|
||||
struct osi_event *osi_event_create(osi_thread_func_t func, void *context)
|
||||
{
|
||||
struct osi_event *event = osi_calloc(sizeof(struct osi_event));
|
||||
if (event != NULL) {
|
||||
if (osi_mutex_new(&event->lock) == 0) {
|
||||
event->item.func = func;
|
||||
event->item.context = context;
|
||||
return event;
|
||||
}
|
||||
osi_free(event);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void osi_event_delete(struct osi_event* event)
|
||||
{
|
||||
if (event != NULL) {
|
||||
osi_mutex_free(&event->lock);
|
||||
memset(event, 0, sizeof(struct osi_event));
|
||||
osi_free(event);
|
||||
}
|
||||
}
|
||||
|
||||
bool osi_event_bind(struct osi_event* event, osi_thread_t *thread, int queue_idx)
|
||||
{
|
||||
if (event == NULL || event->thread != NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thread == NULL || queue_idx >= thread->work_queue_num) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event->thread = thread;
|
||||
event->queue_idx = queue_idx;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void osi_thread_generic_event_handler(void *context)
|
||||
{
|
||||
struct osi_event *event = (struct osi_event *)context;
|
||||
if (event != NULL && event->item.func != NULL) {
|
||||
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
event->is_queued = 0;
|
||||
osi_mutex_unlock(&event->lock);
|
||||
event->item.func(event->item.context);
|
||||
}
|
||||
}
|
||||
|
||||
bool osi_thread_post_event(struct osi_event *event, uint32_t timeout)
|
||||
{
|
||||
assert(event != NULL && event->thread != NULL);
|
||||
assert(event->queue_idx >= 0 && event->queue_idx < event->thread->work_queue_num);
|
||||
bool ret = false;
|
||||
if (event->is_queued == 0) {
|
||||
uint16_t acquire_cnt = 0;
|
||||
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
event->is_queued += 1;
|
||||
acquire_cnt = event->is_queued;
|
||||
osi_mutex_unlock(&event->lock);
|
||||
|
||||
if (acquire_cnt == 1) {
|
||||
ret = osi_thread_post(event->thread, osi_thread_generic_event_handler, event, event->queue_idx, timeout);
|
||||
if (!ret) {
|
||||
// clear "is_queued" when post failure, to allow for following event posts
|
||||
osi_mutex_lock(&event->lock, OSI_MUTEX_MAX_TIMEOUT);
|
||||
event->is_queued = 0;
|
||||
osi_mutex_unlock(&event->lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user