mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/btdm_bt_spp_vfs' into 'master'
component/bt: Add SPP profile with VFS See merge request idf/esp-idf!1883
This commit is contained in:
commit
ee9ab48347
@ -46,14 +46,11 @@ esp_err_t esp_spp_init(esp_spp_mode_t mode)
|
||||
btc_spp_args_t arg;
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
if (mode != ESP_SPP_MODE_CB) {
|
||||
LOG_ERROR("%s Watch this space!", __func__);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
msg.sig = BTC_SIG_API_CALL;
|
||||
msg.pid = BTC_PID_SPP;
|
||||
msg.act = BTC_SPP_ACT_INIT;
|
||||
|
||||
arg.init.mode = mode;
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
@ -166,4 +163,13 @@ esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data)
|
||||
|
||||
return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), btc_spp_arg_deep_copy) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
|
||||
}
|
||||
|
||||
esp_err_t esp_spp_vfs_register()
|
||||
{
|
||||
ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
|
||||
|
||||
btc_spp_vfs_register();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
|
||||
|
@ -62,9 +62,9 @@ typedef enum {
|
||||
ESP_SPP_CLOSE_EVT = 27, /*!< When SPP connection closed, the event comes */
|
||||
ESP_SPP_START_EVT = 28, /*!< When SPP server started, the event comes */
|
||||
ESP_SPP_CL_INIT_EVT = 29, /*!< When SPP client initiated a connection, the event comes */
|
||||
ESP_SPP_DATA_IND_EVT = 30, /*!< When SPP connection received data, the event comes */
|
||||
ESP_SPP_CONG_EVT = 31, /*!< When SPP connection congestion status changed, the event comes */
|
||||
ESP_SPP_WRITE_EVT = 33, /*!< When SPP write operation completes, the event comes */
|
||||
ESP_SPP_DATA_IND_EVT = 30, /*!< When SPP connection received data, the event comes, olny for ESP_SPP_MODE_CB */
|
||||
ESP_SPP_CONG_EVT = 31, /*!< When SPP connection congestion status changed, the event comes, olny for ESP_SPP_MODE_CB */
|
||||
ESP_SPP_WRITE_EVT = 33, /*!< When SPP write operation completes, the event comes, olny for ESP_SPP_MODE_CB */
|
||||
ESP_SPP_SRV_OPEN_EVT = 34, /*!< When SPP Server connection open, the event comes */
|
||||
} esp_spp_cb_event_t;
|
||||
|
||||
@ -95,6 +95,7 @@ typedef union {
|
||||
struct spp_open_evt_param {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint32_t handle; /*!< The connection handle */
|
||||
int fd; /*!< The file descriptor olny for ESP_SPP_MODE_VFS*/
|
||||
esp_bd_addr_t rem_bda; /*!< The peer address */
|
||||
} open; /*!< SPP callback param of ESP_SPP_OPEN_EVT */
|
||||
|
||||
@ -105,6 +106,7 @@ typedef union {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint32_t handle; /*!< The connection handle */
|
||||
uint32_t new_listen_handle; /*!< The new listen handle */
|
||||
int fd; /*!< The file descriptor olny for ESP_SPP_MODE_VFS*/
|
||||
esp_bd_addr_t rem_bda; /*!< The peer address */
|
||||
} srv_open; /*!< SPP callback param of ESP_SPP_SRV_OPEN_EVT */
|
||||
/**
|
||||
@ -142,7 +144,6 @@ typedef union {
|
||||
struct spp_write_evt_param {
|
||||
esp_spp_status_t status; /*!< status */
|
||||
uint32_t handle; /*!< The connection handle */
|
||||
uint32_t req_id; /*!< The req_id in the associated BTA_JvRfcommWrite() */
|
||||
int len; /*!< The length of the data written. */
|
||||
bool cong; /*!< congestion status */
|
||||
} write; /*!< SPP callback param of ESP_SPP_WRITE_EVT */
|
||||
@ -275,7 +276,7 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function closes an SPP connection.
|
||||
* @brief This function is used to write data, olny for ESP_SPP_MODE_CB.
|
||||
*
|
||||
* @param[in] handle: The connection handle.
|
||||
* @param[in] len: The length of the data written.
|
||||
@ -287,6 +288,16 @@ esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
|
||||
*/
|
||||
esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data);
|
||||
|
||||
|
||||
/**
|
||||
* @brief This function is used to register VFS.
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: success
|
||||
* - other: failed
|
||||
*/
|
||||
esp_err_t esp_spp_vfs_register(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -1068,7 +1068,6 @@ tBTA_JV_STATUS BTA_JvRfcommReady(UINT32 handle, UINT32 *p_data_size)
|
||||
** BTA_JV_FAILURE, otherwise.
|
||||
**
|
||||
*******************************************************************************/
|
||||
// UINT8 spp_data[10] = {1,2,3,4,5,6,7,8,9,0};
|
||||
|
||||
tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p_data)
|
||||
{
|
||||
@ -1093,7 +1092,6 @@ tBTA_JV_STATUS BTA_JvRfcommWrite(UINT32 handle, UINT32 req_id, int len, UINT8 *p
|
||||
bta_sys_sendmsg(p_msg);
|
||||
status = BTA_JV_SUCCESS;
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,8 @@
|
||||
#define ESP_SPP_MAX_SESSION BTA_JV_MAX_RFC_SR_SESSION
|
||||
#define ESP_SPP_SERVER_NAME_MAX 32
|
||||
|
||||
#define ESP_SPP_RINGBUF_SIZE 1000
|
||||
|
||||
typedef enum {
|
||||
BTC_SPP_ACT_INIT = 0,
|
||||
BTC_SPP_ACT_UNINIT,
|
||||
@ -40,6 +42,7 @@ typedef enum {
|
||||
typedef union {
|
||||
//BTC_SPP_ACT_INIT
|
||||
struct init_arg {
|
||||
esp_spp_mode_t mode;
|
||||
} init;
|
||||
//BTC_SPP_ACT_UNINIT
|
||||
struct uninit_arg {
|
||||
@ -84,6 +87,6 @@ void btc_spp_call_handler(btc_msg_t *msg);
|
||||
void btc_spp_cb_handler(btc_msg_t *msg);
|
||||
void btc_spp_arg_deep_copy(btc_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
|
||||
void btc_spp_vfs_register(void);
|
||||
#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
|
||||
#endif ///__BTC_SPP_H__
|
@ -22,11 +22,13 @@
|
||||
#include "osi/allocator.h"
|
||||
#include "esp_spp_api.h"
|
||||
#include "osi/list.h"
|
||||
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "osi/mutex.h"
|
||||
#include <sys/errno.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_vfs_dev.h"
|
||||
|
||||
|
||||
#if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
|
||||
@ -36,71 +38,127 @@ typedef struct {
|
||||
bool connected;
|
||||
uint8_t scn;
|
||||
uint8_t max_session;
|
||||
RingbufHandle_t ringbuf_read;
|
||||
RingbufHandle_t ringbuf_write;
|
||||
uint32_t id;
|
||||
uint32_t mtu;//unused
|
||||
uint32_t sdp_handle;
|
||||
uint32_t rfc_handle;
|
||||
uint32_t rfc_port_handle;
|
||||
int fd;
|
||||
uint8_t *write_data;
|
||||
esp_spp_role_t role;
|
||||
esp_spp_sec_t security;
|
||||
esp_bd_addr_t addr;
|
||||
list_t *list;
|
||||
list_t *incoming_list;
|
||||
uint8_t service_uuid[16];
|
||||
char service_name[ESP_SPP_SERVER_NAME_MAX];
|
||||
} spp_slot_t;
|
||||
static spp_slot_t *spp_slots[BTA_JV_MAX_RFC_SR_SESSION + 1];
|
||||
static uint32_t spp_slot_id = 0;
|
||||
static osi_mutex_t spp_slot_mutex;
|
||||
|
||||
static struct spp_local_param_t {
|
||||
spp_slot_t *spp_slots[BTA_JV_MAX_RFC_SR_SESSION + 1];
|
||||
uint32_t spp_slot_id;
|
||||
esp_spp_mode_t spp_mode;
|
||||
int spp_max_fd;
|
||||
int spp_min_fd;
|
||||
int spp_fd;
|
||||
osi_mutex_t spp_slot_mutex;
|
||||
} spp_local_param;
|
||||
|
||||
static void spp_osi_free(void *p)
|
||||
{
|
||||
osi_free(p);
|
||||
}
|
||||
static spp_slot_t *malloc_spp_slot(void)
|
||||
|
||||
static int find_free_fd()
|
||||
{
|
||||
if (++spp_slot_id == 0) {
|
||||
spp_slot_id = 1;
|
||||
spp_local_param.spp_fd = 1;
|
||||
if (spp_local_param.spp_fd < spp_local_param.spp_min_fd || spp_local_param.spp_fd > spp_local_param.spp_max_fd){
|
||||
spp_local_param.spp_fd = spp_local_param.spp_min_fd;
|
||||
}
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_slots[i] == NULL) {
|
||||
spp_slots[i] = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t));
|
||||
if (!spp_slots[i]) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->fd == spp_local_param.spp_fd) {
|
||||
i = 1;
|
||||
spp_local_param.spp_fd++;
|
||||
if (spp_local_param.spp_fd < spp_local_param.spp_min_fd || spp_local_param.spp_fd > spp_local_param.spp_max_fd){
|
||||
spp_local_param.spp_fd = spp_local_param.spp_min_fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
return spp_local_param.spp_fd++;
|
||||
}
|
||||
|
||||
static spp_slot_t *malloc_spp_slot(void)
|
||||
{
|
||||
if (++spp_local_param.spp_slot_id == 0) {
|
||||
spp_local_param.spp_slot_id = 1;
|
||||
}
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_local_param.spp_slots[i] == NULL) {
|
||||
spp_local_param.spp_slots[i] = (spp_slot_t *)osi_malloc(sizeof(spp_slot_t));
|
||||
if (!spp_local_param.spp_slots[i]) {
|
||||
return NULL;
|
||||
}
|
||||
spp_slots[i]->id = spp_slot_id;
|
||||
spp_slots[i]->serial = i;
|
||||
spp_slots[i]->connected = FALSE;
|
||||
spp_slots[i]->list = list_new(spp_osi_free);
|
||||
return spp_slots[i];
|
||||
spp_local_param.spp_slots[i]->id = spp_local_param.spp_slot_id;
|
||||
spp_local_param.spp_slots[i]->serial = i;
|
||||
spp_local_param.spp_slots[i]->connected = FALSE;
|
||||
spp_local_param.spp_slots[i]->write_data = NULL;
|
||||
spp_local_param.spp_slots[i]->list = list_new(spp_osi_free);
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
||||
spp_local_param.spp_slots[i]->incoming_list = list_new(spp_osi_free);
|
||||
spp_local_param.spp_slots[i]->fd = find_free_fd();
|
||||
spp_local_param.spp_slots[i]->ringbuf_read = xRingbufferCreate(ESP_SPP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
|
||||
spp_local_param.spp_slots[i]->ringbuf_write = xRingbufferCreate(ESP_SPP_RINGBUF_SIZE, RINGBUF_TYPE_BYTEBUF);
|
||||
}
|
||||
return spp_local_param.spp_slots[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static spp_slot_t *find_slot_by_id(uint32_t id)
|
||||
{
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_slots[i] != NULL && spp_slots[i]->id == id) {
|
||||
return spp_slots[i];
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->id == id) {
|
||||
return spp_local_param.spp_slots[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static spp_slot_t *find_slot_by_handle(uint32_t handle)
|
||||
{
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_slots[i] != NULL && spp_slots[i]->rfc_handle == handle) {
|
||||
return spp_slots[i];
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->rfc_handle == handle) {
|
||||
return spp_local_param.spp_slots[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static spp_slot_t *find_slot_by_fd(int fd)
|
||||
{
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->fd == fd) {
|
||||
return spp_local_param.spp_slots[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void free_spp_slot(spp_slot_t *slot)
|
||||
{
|
||||
if (!slot) {
|
||||
return;
|
||||
}
|
||||
spp_slots[slot->serial] = NULL;
|
||||
spp_local_param.spp_slots[slot->serial] = NULL;
|
||||
list_free(slot->list);
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
||||
list_free(slot->incoming_list);
|
||||
vRingbufferDelete(slot->ringbuf_read);
|
||||
vRingbufferDelete(slot->ringbuf_write);
|
||||
}
|
||||
osi_free(slot);
|
||||
}
|
||||
|
||||
@ -118,6 +176,7 @@ static void btc_create_server_fail_cb(void)
|
||||
param.start.status = ESP_SPP_FAILURE;
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
}
|
||||
|
||||
static void btc_disconnect_cb(uint32_t handle)
|
||||
{
|
||||
esp_spp_cb_param_t param;
|
||||
@ -134,8 +193,8 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
|
||||
void *new_user_data = NULL;
|
||||
|
||||
uint32_t id = (uintptr_t)user_data;
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot, *slot_new;
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
switch (event) {
|
||||
case BTA_JV_RFCOMM_SRV_OPEN_EVT:
|
||||
slot = find_slot_by_id(id);
|
||||
@ -190,7 +249,7 @@ static void *btc_spp_rfcomm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *u
|
||||
default:
|
||||
break;
|
||||
}
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
msg.pid = BTC_PID_SPP;
|
||||
msg.act = event;
|
||||
@ -214,31 +273,31 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
|
||||
spp_slot_t *slot;
|
||||
switch (event) {
|
||||
case BTA_JV_GET_SCN_EVT:
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
slot = find_slot_by_id(id);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
if (p_data->scn == 0) {
|
||||
LOG_ERROR("%s unable to get scn, start server fail!", __func__);
|
||||
btc_create_server_fail_cb();
|
||||
free_spp_slot(slot);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
|
||||
slot->scn = p_data->scn;
|
||||
BTA_JvCreateRecordByUser(slot->service_name, slot->scn, (void *)slot->id);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
case BTA_JV_CREATE_RECORD_EVT:
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
slot = find_slot_by_id(id);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
if (p_data->create_rec.status == BTA_JV_SUCCESS) {
|
||||
@ -251,7 +310,7 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
|
||||
BTA_JvFreeChannel(slot->scn, BTA_JV_CONN_TYPE_RFCOMM);
|
||||
free_spp_slot(slot);
|
||||
}
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
default:
|
||||
msg.sig = BTC_SIG_API_CB;
|
||||
@ -267,48 +326,52 @@ static void btc_spp_dm_inter_cb(tBTA_JV_EVT event, tBTA_JV *p_data, void *user_d
|
||||
}
|
||||
}
|
||||
|
||||
static void btc_spp_init(void)
|
||||
static void btc_spp_init(btc_spp_args_t *arg)
|
||||
{
|
||||
if (osi_mutex_new(&spp_slot_mutex) != 0) {
|
||||
if (osi_mutex_new(&spp_local_param.spp_slot_mutex) != 0) {
|
||||
LOG_ERROR("%s osi_mutex_new failed\n", __func__);
|
||||
}
|
||||
spp_local_param.spp_mode = arg->init.mode;
|
||||
spp_local_param.spp_slot_id = 0;
|
||||
BTA_JvEnable((tBTA_JV_DM_CBACK *)btc_spp_dm_inter_cb);
|
||||
}
|
||||
|
||||
static void btc_spp_uninit(void)
|
||||
{
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_slots[i] != NULL && spp_slots[i]->connected) {
|
||||
BTA_JvRfcommClose(spp_slots[i]->rfc_handle, (void *)spp_slots[i]->id);
|
||||
free_spp_slot(spp_slots[i]);
|
||||
spp_slots[i] = NULL;
|
||||
if (spp_local_param.spp_slots[i] != NULL && spp_local_param.spp_slots[i]->connected) {
|
||||
BTA_JvRfcommClose(spp_local_param.spp_slots[i]->rfc_handle, (void *)spp_local_param.spp_slots[i]->id);
|
||||
free_spp_slot(spp_local_param.spp_slots[i]);
|
||||
spp_local_param.spp_slots[i] = NULL;
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i <= BTA_JV_MAX_RFC_SR_SESSION; i++) {
|
||||
if (spp_slots[i] != NULL && !(spp_slots[i]->connected)) {
|
||||
BTA_JvDeleteRecord(spp_slots[i]->sdp_handle);
|
||||
BTA_JvFreeChannel(spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM);
|
||||
free_spp_slot(spp_slots[i]);
|
||||
spp_slots[i] = NULL;
|
||||
if (spp_local_param.spp_slots[i] != NULL && !(spp_local_param.spp_slots[i]->connected)) {
|
||||
BTA_JvDeleteRecord(spp_local_param.spp_slots[i]->sdp_handle);
|
||||
BTA_JvFreeChannel(spp_local_param.spp_slots[i]->scn, BTA_JV_CONN_TYPE_RFCOMM);
|
||||
free_spp_slot(spp_local_param.spp_slots[i]);
|
||||
spp_local_param.spp_slots[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
BTA_JvDisable();
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_free(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
osi_mutex_free(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
|
||||
static void btc_spp_start_discovery(btc_spp_args_t *arg)
|
||||
{
|
||||
BTA_JvStartDiscovery(arg->start_discovery.bd_addr, arg->start_discovery.num_uuid, arg->start_discovery.p_uuid_list, NULL);
|
||||
}
|
||||
|
||||
static void btc_spp_connect(btc_spp_args_t *arg)
|
||||
{
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = malloc_spp_slot();
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to malloc RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return;
|
||||
}
|
||||
slot->security = arg->connect.sec_mask;
|
||||
@ -317,29 +380,31 @@ static void btc_spp_connect(btc_spp_args_t *arg)
|
||||
memcpy(slot->addr, arg->connect.peer_bd_addr, ESP_BD_ADDR_LEN);
|
||||
BTA_JvRfcommConnect(arg->connect.sec_mask, arg->connect.role, arg->connect.remote_scn,
|
||||
arg->connect.peer_bd_addr, (tBTA_JV_RFCOMM_CBACK *)btc_spp_rfcomm_inter_cb, (void *)slot->id);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
|
||||
static void btc_spp_disconnect(btc_spp_args_t *arg)
|
||||
{
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_handle(arg->disconnect.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return;
|
||||
}
|
||||
BTA_JvRfcommClose(arg->disconnect.handle, (void *)slot->id);
|
||||
btc_disconnect_cb(slot->rfc_handle);
|
||||
free_spp_slot(slot);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
|
||||
static void btc_spp_start_srv(btc_spp_args_t *arg)
|
||||
{
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = malloc_spp_slot();
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to malloc RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return;
|
||||
}
|
||||
slot->security = arg->start_srv.sec_mask;
|
||||
@ -349,21 +414,34 @@ static void btc_spp_start_srv(btc_spp_args_t *arg)
|
||||
strcpy(slot->service_name, arg->start_srv.name);
|
||||
|
||||
BTA_JvGetChannelId(BTA_JV_CONN_TYPE_RFCOMM, (void *)slot->id, arg->start_srv.local_scn);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
|
||||
static void btc_spp_write(btc_spp_args_t *arg)
|
||||
{
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_handle(arg->write.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return;
|
||||
}
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
||||
size_t item_size = 0;
|
||||
if (slot->write_data != NULL) {
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return;
|
||||
}
|
||||
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0,990);
|
||||
if (item_size != 0){
|
||||
slot->write_data = data;
|
||||
BTA_JvRfcommWrite(arg->write.handle, slot->id, item_size, data);
|
||||
}
|
||||
} else {
|
||||
list_append(slot->list, arg->write.p_data);
|
||||
BTA_JvRfcommWrite(arg->write.handle, slot->id, arg->write.len, arg->write.p_data);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
|
||||
|
||||
@ -418,7 +496,7 @@ void btc_spp_call_handler(btc_msg_t *msg)
|
||||
btc_spp_args_t *arg = (btc_spp_args_t *)(msg->arg);
|
||||
switch (msg->act) {
|
||||
case BTC_SPP_ACT_INIT:
|
||||
btc_spp_init();
|
||||
btc_spp_init(arg);
|
||||
break;
|
||||
case BTC_SPP_ACT_UNINIT:
|
||||
btc_spp_uninit();
|
||||
@ -449,6 +527,7 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
{
|
||||
esp_spp_cb_param_t param;
|
||||
tBTA_JV *p_data = (tBTA_JV *)msg->arg;
|
||||
spp_slot_t *slot;
|
||||
switch (msg->act) {
|
||||
case BTA_JV_ENABLE_EVT:
|
||||
param.init.status = p_data->status;
|
||||
@ -468,6 +547,17 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
btc_spp_cb_to_app(ESP_SPP_CL_INIT_EVT, ¶m);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_OPEN_EVT:
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
slot = find_slot_by_handle(p_data->rfc_open.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
param.open.fd = slot->fd;
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
param.open.status = p_data->rfc_open.status;
|
||||
param.open.handle = p_data->rfc_open.handle;
|
||||
memcpy(param.open.rem_bda, p_data->rfc_open.rem_bda, ESP_BD_ADDR_LEN);
|
||||
@ -481,6 +571,17 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
btc_spp_cb_to_app(ESP_SPP_START_EVT, ¶m);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_SRV_OPEN_EVT:
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_VFS) {
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
slot = find_slot_by_handle(p_data->rfc_srv_open.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
param.srv_open.fd = slot->fd;
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
param.srv_open.status = p_data->rfc_srv_open.status;
|
||||
param.srv_open.handle = p_data->rfc_srv_open.handle;
|
||||
param.srv_open.new_listen_handle = p_data->rfc_srv_open.new_listen_handle;
|
||||
@ -488,21 +589,43 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
btc_spp_cb_to_app(ESP_SPP_SRV_OPEN_EVT, ¶m);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_WRITE_EVT:
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
slot = find_slot_by_handle(p_data->rfc_write.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB){
|
||||
param.write.status = p_data->rfc_write.status;
|
||||
param.write.handle = p_data->rfc_write.handle;
|
||||
param.write.req_id = p_data->rfc_write.req_id;
|
||||
param.write.len = p_data->rfc_write.len;
|
||||
param.write.cong = p_data->rfc_write.cong;
|
||||
btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m);
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_handle(p_data->rfc_write.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot! disconnect fail!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
list_remove(slot->list, list_front(slot->list));
|
||||
} else {
|
||||
if (p_data->rfc_write.status != BTA_JV_SUCCESS) {
|
||||
if (slot->write_data != NULL){
|
||||
vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
|
||||
slot->write_data = NULL;
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
list_remove(slot->list, list_front(slot->list));
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
if (p_data->rfc_write.cong == 0) {
|
||||
if (slot->write_data != NULL){
|
||||
vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
|
||||
slot->write_data = NULL;
|
||||
}
|
||||
size_t item_size = 0;
|
||||
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0,990);
|
||||
if (item_size != 0){
|
||||
slot->write_data = data;
|
||||
BTA_JvRfcommWrite(slot->rfc_handle, slot->id, item_size, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_CLOSE_EVT:
|
||||
param.close.status = p_data->rfc_close.status;
|
||||
@ -512,10 +635,33 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
btc_spp_cb_to_app(ESP_SPP_CLOSE_EVT, ¶m);
|
||||
break;
|
||||
case BTA_JV_RFCOMM_CONG_EVT:
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
|
||||
param.cong.status = p_data->rfc_cong.status;
|
||||
param.cong.handle = p_data->rfc_cong.handle;
|
||||
param.cong.cong = p_data->rfc_cong.cong;
|
||||
btc_spp_cb_to_app(ESP_SPP_CONG_EVT, ¶m);
|
||||
} else {
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
slot = find_slot_by_handle(p_data->rfc_cong.handle);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
break;
|
||||
}
|
||||
if (p_data->rfc_cong.cong == 0) {
|
||||
if (slot->write_data != NULL){
|
||||
vRingbufferReturnItem(slot->ringbuf_write,slot->write_data);
|
||||
slot->write_data = NULL;
|
||||
}
|
||||
size_t item_size = 0;
|
||||
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_write, &item_size, 0,990);
|
||||
if (item_size != 0){
|
||||
slot->write_data = data;
|
||||
BTA_JvRfcommWrite(slot->rfc_handle, slot->id, item_size, data);
|
||||
}
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
}
|
||||
break;
|
||||
case BTA_JV_RFCOMM_DATA_IND_EVT:
|
||||
param.data_ind.status = ESP_SPP_SUCCESS;
|
||||
@ -538,9 +684,25 @@ void btc_spp_cb_handler(btc_msg_t *msg)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* If there is too much data not accepted, wait until accepted,or discard it when timeout!
|
||||
* @param list list
|
||||
* @param p_buf incoming data
|
||||
*/
|
||||
static void spp_delay_append(list_t *list, BT_HDR *p_buf){
|
||||
uint8_t count = 0;
|
||||
while (count++ < 100) {
|
||||
if (list_length(list) < 200){
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
list_append(list, p_buf);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return;
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
osi_free(p_buf);
|
||||
LOG_WARN("%s There is too much data not accepted, discard it!", __func__);
|
||||
}
|
||||
|
||||
int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
|
||||
{
|
||||
@ -552,22 +714,38 @@ int bta_co_rfc_data_incoming(void *user_data, BT_HDR *p_buf)
|
||||
msg.act = BTA_JV_RFCOMM_DATA_IND_EVT;
|
||||
|
||||
uint32_t id = (uintptr_t)user_data;
|
||||
osi_mutex_lock(&spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_id(id);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return 0;
|
||||
}
|
||||
p_data.data_ind.handle = slot->rfc_handle;
|
||||
|
||||
if (spp_local_param.spp_mode == ESP_SPP_MODE_CB) {
|
||||
p_data.data_ind.p_buf = p_buf;
|
||||
status = btc_transfer_context(&msg, &p_data,
|
||||
sizeof(tBTA_JV), NULL);
|
||||
|
||||
if (status != BT_STATUS_SUCCESS) {
|
||||
LOG_ERROR("%s btc_transfer_context failed\n", __func__);
|
||||
}
|
||||
osi_mutex_unlock(&spp_slot_mutex);
|
||||
} else {
|
||||
if (list_is_empty(slot->incoming_list)) {
|
||||
BaseType_t done = xRingbufferSend(slot->ringbuf_read, p_buf->data + p_buf->offset, p_buf->len, 0);
|
||||
if (done) {
|
||||
osi_free (p_buf);
|
||||
} else {
|
||||
list_append(slot->incoming_list, p_buf);
|
||||
}
|
||||
} else {
|
||||
list_t *list = slot->incoming_list;
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
spp_delay_append(list,p_buf);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return 1;
|
||||
}
|
||||
int bta_co_rfc_data_outgoing_size(void *user_data, int *size)
|
||||
@ -579,4 +757,87 @@ int bta_co_rfc_data_outgoing(void *user_data, uint8_t *buf, uint16_t size)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static ssize_t spp_vfs_write(int fd, const void * data, size_t size)
|
||||
{
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_fd(fd);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return -1;
|
||||
}
|
||||
BaseType_t done = xRingbufferSend(slot->ringbuf_write, (void *)data, size, 0);
|
||||
esp_spp_write(slot->rfc_handle, 0, NULL);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
if (done){
|
||||
return size;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
static int spp_vfs_close(int fd)
|
||||
{
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_fd(fd);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return -1;
|
||||
}
|
||||
esp_spp_disconnect(slot->rfc_handle);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool incoming_list_2_ringbuf_read(spp_slot_t *slot)
|
||||
{
|
||||
while (!list_is_empty(slot->incoming_list)) {
|
||||
BT_HDR *p_buf = list_front(slot->incoming_list);
|
||||
BaseType_t done = xRingbufferSend(slot->ringbuf_read, p_buf->data + p_buf->offset, p_buf->len, 0);
|
||||
if (done) {
|
||||
list_remove(slot->incoming_list, p_buf);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t spp_vfs_read(int fd, void * dst, size_t size)
|
||||
{
|
||||
osi_mutex_lock(&spp_local_param.spp_slot_mutex, OSI_MUTEX_MAX_TIMEOUT);
|
||||
spp_slot_t *slot = find_slot_by_fd(fd);
|
||||
if (!slot) {
|
||||
LOG_ERROR("%s unable to find RFCOMM slot!", __func__);
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return -1;
|
||||
}
|
||||
incoming_list_2_ringbuf_read(slot);
|
||||
size_t item_size = 0;
|
||||
uint8_t *data = xRingbufferReceiveUpTo(slot->ringbuf_read, &item_size, 0, size);
|
||||
if (item_size > 0){
|
||||
memcpy(dst, data, item_size);
|
||||
vRingbufferReturnItem(slot->ringbuf_read, data);
|
||||
}
|
||||
osi_mutex_unlock(&spp_local_param.spp_slot_mutex);
|
||||
return item_size;
|
||||
}
|
||||
|
||||
void btc_spp_vfs_register()
|
||||
{
|
||||
esp_vfs_t vfs = {
|
||||
.flags = ESP_VFS_FLAG_DEFAULT | ESP_VFS_FLAG_SHARED_FD_SPACE,
|
||||
.write = spp_vfs_write,
|
||||
.open = NULL,
|
||||
.fstat = NULL,
|
||||
.close = spp_vfs_close,
|
||||
.read = spp_vfs_read,
|
||||
.fcntl = NULL
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_vfs_register_socket_space(&vfs, NULL, &spp_local_param.spp_min_fd, &spp_local_param.spp_max_fd));
|
||||
spp_local_param.spp_fd = spp_local_param.spp_min_fd;
|
||||
}
|
||||
|
||||
#endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
|
@ -2585,7 +2585,7 @@ void l2cu_adjust_out_mps (tL2C_CCB *p_ccb)
|
||||
|
||||
if (packet_size <= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN)) {
|
||||
/* something is very wrong */
|
||||
L2CAP_TRACE_ERROR ("l2cu_adjust_out_mps bad packet size: %u will use MPS: %u", packet_size, p_ccb->peer_cfg.fcr.mps);
|
||||
L2CAP_TRACE_DEBUG ("l2cu_adjust_out_mps bad packet size: %u will use MPS: %u", packet_size, p_ccb->peer_cfg.fcr.mps);
|
||||
p_ccb->tx_mps = p_ccb->peer_cfg.fcr.mps;
|
||||
} else {
|
||||
packet_size -= (L2CAP_PKT_OVERHEAD + L2CAP_FCR_OVERHEAD + L2CAP_SDU_LEN_OVERHEAD + L2CAP_FCS_LEN);
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
PROJECT_NAME := bt_spp_acceptor_demo
|
||||
|
||||
#COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
PROJECT_NAME := bt_spp_initiator_demo
|
||||
|
||||
#COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
10
examples/bluetooth/bt_spp_vfs_acceptor/Makefile
Normal file
10
examples/bluetooth/bt_spp_vfs_acceptor/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := bt_spp_vfs_acceptor_demo
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
14
examples/bluetooth/bt_spp_vfs_acceptor/README.rst
Normal file
14
examples/bluetooth/bt_spp_vfs_acceptor/README.rst
Normal file
@ -0,0 +1,14 @@
|
||||
ESP-IDF BT-SPP-VFS-ACCEPTOR demo
|
||||
======================
|
||||
|
||||
Demo of SPP acceptor role
|
||||
|
||||
This is the demo for user to use ESP_APIs to create a SPP acceptor.
|
||||
|
||||
Options choose step:
|
||||
1. make menuconfig.
|
||||
2. enter menuconfig "Component config", choose "Bluetooth"
|
||||
3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
|
||||
4. choose your options.
|
||||
|
||||
After the program started, bt_spp_vfs_initator will connect it and send data.
|
4
examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk
Normal file
4
examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk
Normal file
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -0,0 +1,150 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* This file is for bt_spp_vfs_acceptor demo. It can create servers, wait for connected and receive data.
|
||||
* run bt_spp_vfs_acceptor demo, the bt_spp_vfs_initiator demo will automatically connect the bt_spp_vfs_acceptor demo,
|
||||
* then receive data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gap_bt_api.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_spp_api.h"
|
||||
#include "spp_task.h"
|
||||
|
||||
#include "time.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
#include "esp_vfs.h"
|
||||
#include "sys/unistd.h"
|
||||
|
||||
#define SPP_TAG "SPP_ACCEPTOR_DEMO"
|
||||
#define SPP_SERVER_NAME "SPP_SERVER"
|
||||
#define EXCAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR"
|
||||
|
||||
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS;
|
||||
|
||||
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE;
|
||||
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE;
|
||||
|
||||
#define SPP_DATA_LEN 100
|
||||
static uint8_t spp_data[SPP_DATA_LEN];
|
||||
|
||||
static void spp_read_handle(void * param)
|
||||
{
|
||||
int size = 0;
|
||||
int fd = (int)param;
|
||||
do {
|
||||
size = read (fd, spp_data, SPP_DATA_LEN);
|
||||
ESP_LOGI(SPP_TAG, "fd = %d data_len = %d", fd, size);
|
||||
if (size == -1) {
|
||||
break;
|
||||
}
|
||||
esp_log_buffer_hex(SPP_TAG, spp_data, size);
|
||||
if (size == 0) {
|
||||
/*read fail due to there is no data, retry after 1s*/
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
} while (1);
|
||||
spp_wr_task_shut_down();
|
||||
}
|
||||
|
||||
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_SPP_INIT_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
|
||||
esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME);
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
esp_spp_start_srv(sec_mask,role_slave, 0, SPP_SERVER_NAME);
|
||||
break;
|
||||
case ESP_SPP_DISCOVERY_COMP_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT");
|
||||
break;
|
||||
case ESP_SPP_OPEN_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
|
||||
break;
|
||||
case ESP_SPP_CLOSE_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
|
||||
break;
|
||||
case ESP_SPP_START_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
|
||||
break;
|
||||
case ESP_SPP_CL_INIT_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
|
||||
break;
|
||||
case ESP_SPP_SRV_OPEN_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
|
||||
spp_wr_task_start_up(spp_read_handle, param->srv_open.fd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_spp_stack_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
{
|
||||
spp_task_work_dispatch((spp_task_cb_t)esp_spp_cb, event, param, sizeof(esp_spp_cb_param_t), NULL);
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( ret );
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s initialize controller failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s enable controller failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bluedroid_init() != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bluedroid_enable() != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s enable bluedroid failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_spp_register_callback(esp_spp_stack_cb) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s spp register failed", __func__);
|
||||
return;
|
||||
}
|
||||
esp_spp_vfs_register();
|
||||
spp_task_task_start_up();
|
||||
|
||||
if (esp_spp_init(esp_spp_mode) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s spp init failed", __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
128
examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c
Normal file
128
examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "spp_task.h"
|
||||
|
||||
static void spp_task_task_handler(void *arg);
|
||||
static bool spp_task_send_msg(spp_task_msg_t *msg);
|
||||
static void spp_task_work_dispatched(spp_task_msg_t *msg);
|
||||
|
||||
static xQueueHandle spp_task_task_queue = NULL;
|
||||
static xTaskHandle spp_task_task_handle = NULL;
|
||||
|
||||
bool spp_task_work_dispatch(spp_task_cb_t p_cback, uint16_t event, void *p_params, int param_len, spp_task_copy_cb_t p_copy_cback)
|
||||
{
|
||||
ESP_LOGD(SPP_TASK_TAG, "%s event 0x%x, param len %d", __func__, event, param_len);
|
||||
|
||||
spp_task_msg_t msg;
|
||||
memset(&msg, 0, sizeof(spp_task_msg_t));
|
||||
|
||||
msg.sig = SPP_TASK_SIG_WORK_DISPATCH;
|
||||
msg.event = event;
|
||||
msg.cb = p_cback;
|
||||
|
||||
if (param_len == 0) {
|
||||
return spp_task_send_msg(&msg);
|
||||
} else if (p_params && param_len > 0) {
|
||||
if ((msg.param = malloc(param_len)) != NULL) {
|
||||
memcpy(msg.param, p_params, param_len);
|
||||
/* check if caller has provided a copy callback to do the deep copy */
|
||||
if (p_copy_cback) {
|
||||
p_copy_cback(&msg, msg.param, p_params);
|
||||
}
|
||||
return spp_task_send_msg(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool spp_task_send_msg(spp_task_msg_t *msg)
|
||||
{
|
||||
if (msg == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xQueueSend(spp_task_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
|
||||
ESP_LOGE(SPP_TASK_TAG, "%s xQueue send failed", __func__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void spp_task_work_dispatched(spp_task_msg_t *msg)
|
||||
{
|
||||
if (msg->cb) {
|
||||
msg->cb(msg->event, msg->param);
|
||||
}
|
||||
}
|
||||
|
||||
static void spp_task_task_handler(void *arg)
|
||||
{
|
||||
spp_task_msg_t msg;
|
||||
for (;;) {
|
||||
if (pdTRUE == xQueueReceive(spp_task_task_queue, &msg, (portTickType)portMAX_DELAY)) {
|
||||
ESP_LOGD(SPP_TASK_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
|
||||
switch (msg.sig) {
|
||||
case SPP_TASK_SIG_WORK_DISPATCH:
|
||||
spp_task_work_dispatched(&msg);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(SPP_TASK_TAG, "%s, unhandled sig: %d", __func__, msg.sig);
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg.param) {
|
||||
free(msg.param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spp_task_task_start_up(void)
|
||||
{
|
||||
spp_task_task_queue = xQueueCreate(10, sizeof(spp_task_msg_t));
|
||||
xTaskCreate(spp_task_task_handler, "SPPAppT", 2048, NULL, 10, spp_task_task_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
void spp_task_task_shut_down(void)
|
||||
{
|
||||
if (spp_task_task_handle) {
|
||||
vTaskDelete(spp_task_task_handle);
|
||||
spp_task_task_handle = NULL;
|
||||
}
|
||||
if (spp_task_task_queue) {
|
||||
vQueueDelete(spp_task_task_queue);
|
||||
spp_task_task_queue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void spp_wr_task_start_up(spp_wr_task_cb_t p_cback, int fd)
|
||||
{
|
||||
xTaskCreate(p_cback, "write_read", 2048, (void *)fd, 5, NULL);
|
||||
}
|
||||
void spp_wr_task_shut_down(void)
|
||||
{
|
||||
vTaskDelete(NULL);
|
||||
}
|
63
examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h
Normal file
63
examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 __SPP_TASK_H__
|
||||
#define __SPP_TASK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SPP_TASK_TAG "SPP_TASK"
|
||||
|
||||
#define SPP_TASK_SIG_WORK_DISPATCH (0x01)
|
||||
|
||||
/**
|
||||
* @brief handler for the dispatched work
|
||||
*/
|
||||
typedef void (* spp_task_cb_t) (uint16_t event, void *param);
|
||||
|
||||
/* message to be sent */
|
||||
typedef struct {
|
||||
uint16_t sig; /*!< signal to spp_task_task */
|
||||
uint16_t event; /*!< message event id */
|
||||
spp_task_cb_t cb; /*!< context switch callback */
|
||||
void *param; /*!< parameter area needs to be last */
|
||||
} spp_task_msg_t;
|
||||
|
||||
/**
|
||||
* @brief parameter deep-copy function to be customized
|
||||
*/
|
||||
typedef void (* spp_task_copy_cb_t) (spp_task_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
/**
|
||||
* @brief work dispatcher for the application task
|
||||
*/
|
||||
bool spp_task_work_dispatch(spp_task_cb_t p_cback, uint16_t event, void *p_params, int param_len, spp_task_copy_cb_t p_copy_cback);
|
||||
|
||||
void spp_task_task_start_up(void);
|
||||
|
||||
void spp_task_task_shut_down(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief handler for write and read
|
||||
*/
|
||||
typedef void (* spp_wr_task_cb_t) (void *fd);
|
||||
|
||||
void spp_wr_task_start_up(spp_wr_task_cb_t p_cback, int fd);
|
||||
|
||||
void spp_wr_task_shut_down(void);
|
||||
|
||||
#endif ///__SPP_TASK_H__
|
@ -0,0 +1,6 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# and WiFi disabled by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_CLASSIC_BT_ENABLED=y
|
||||
CONFIG_WIFI_ENABLED=n
|
||||
CONFIG_BT_SPP_ENABLED=y
|
10
examples/bluetooth/bt_spp_vfs_initiator/Makefile
Normal file
10
examples/bluetooth/bt_spp_vfs_initiator/Makefile
Normal file
@ -0,0 +1,10 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := bt_spp_vfs_initiator_demo
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := components/include
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
14
examples/bluetooth/bt_spp_vfs_initiator/README.rst
Normal file
14
examples/bluetooth/bt_spp_vfs_initiator/README.rst
Normal file
@ -0,0 +1,14 @@
|
||||
ESP-IDF BT-SPP-VFS-INITATOR demo
|
||||
======================
|
||||
|
||||
Demo of SPP initator role
|
||||
|
||||
This is the demo for user to use ESP_APIs to create a SPP initator.
|
||||
|
||||
Options choose step:
|
||||
1. make menuconfig.
|
||||
2. enter menuconfig "Component config", choose "Bluetooth"
|
||||
3. enter menu Bluetooth, choose "Classic Bluetooth" and "SPP Profile"
|
||||
4. choose your options.
|
||||
|
||||
After the program started, It will connect to bt_spp_vfs_acceptor and send data.
|
@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
@ -0,0 +1,234 @@
|
||||
/*
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
*
|
||||
* This file is for bt_spp_vfs_initiator demo. It can discovery servers, connect one device and send data.
|
||||
* run bt_spp_vfs_initiator demo, the bt_spp_vfs_initiator demo will automatically connect the bt_spp_vfs_acceptor demo,
|
||||
* then send data.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_bt.h"
|
||||
#include "esp_bt_main.h"
|
||||
#include "esp_gap_bt_api.h"
|
||||
#include "esp_bt_device.h"
|
||||
#include "esp_spp_api.h"
|
||||
#include "spp_task.h"
|
||||
|
||||
#include "time.h"
|
||||
#include "sys/time.h"
|
||||
|
||||
#include "esp_vfs.h"
|
||||
#include "sys/unistd.h"
|
||||
|
||||
#define SPP_TAG "SPP_INITIATOR_DEMO"
|
||||
#define EXCAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR"
|
||||
|
||||
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_VFS;
|
||||
|
||||
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_NONE;
|
||||
static const esp_spp_role_t role_master = ESP_SPP_ROLE_MASTER;
|
||||
|
||||
static esp_bd_addr_t peer_bd_addr;
|
||||
static uint8_t peer_bdname_len;
|
||||
static char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
|
||||
static const char remote_device_name[] = "ESP_SPP_ACCEPTOR";
|
||||
static const esp_bt_inq_mode_t inq_mode = ESP_BT_INQ_MODE_GENERAL_INQUIRY;
|
||||
static const uint8_t inq_len = 30;
|
||||
static const uint8_t inq_num_rsps = 0;
|
||||
|
||||
#define SPP_DATA_LEN 20
|
||||
static uint8_t spp_data[SPP_DATA_LEN];
|
||||
|
||||
static void spp_write_handle(void * param)
|
||||
{
|
||||
int size = 0;
|
||||
int fd = (int)param;
|
||||
printf("%s %d %p\n", __func__,fd,param);
|
||||
do {
|
||||
size = write (fd, spp_data, SPP_DATA_LEN);
|
||||
ESP_LOGI(SPP_TAG, "fd = %d data_len = %d",fd, size);
|
||||
if (size == -1) {
|
||||
break;
|
||||
} else if ( size == 0) {
|
||||
/*write fail due to ringbuf is full, retry after 1s*/
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
} while (1);
|
||||
spp_wr_task_shut_down();
|
||||
}
|
||||
|
||||
static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
|
||||
{
|
||||
uint8_t *rmt_bdname = NULL;
|
||||
uint8_t rmt_bdname_len = 0;
|
||||
|
||||
if (!eir) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
|
||||
if (!rmt_bdname) {
|
||||
rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
|
||||
}
|
||||
|
||||
if (rmt_bdname) {
|
||||
if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
|
||||
rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
|
||||
}
|
||||
|
||||
if (bdname) {
|
||||
memcpy(bdname, rmt_bdname, rmt_bdname_len);
|
||||
bdname[rmt_bdname_len] = '\0';
|
||||
}
|
||||
if (bdname_len) {
|
||||
*bdname_len = rmt_bdname_len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
{
|
||||
switch (event) {
|
||||
case ESP_SPP_INIT_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
|
||||
esp_bt_dev_set_device_name(EXCAMPLE_DEVICE_NAME);
|
||||
esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
|
||||
esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
|
||||
|
||||
break;
|
||||
case ESP_SPP_DISCOVERY_COMP_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d scn_num=%d",param->disc_comp.status, param->disc_comp.scn_num);
|
||||
if (param->disc_comp.status == ESP_SPP_SUCCESS) {
|
||||
esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], peer_bd_addr);
|
||||
}
|
||||
break;
|
||||
case ESP_SPP_OPEN_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT");
|
||||
spp_wr_task_start_up(spp_write_handle, param->open.fd);
|
||||
break;
|
||||
case ESP_SPP_CLOSE_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT");
|
||||
break;
|
||||
case ESP_SPP_START_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
|
||||
break;
|
||||
case ESP_SPP_CL_INIT_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT");
|
||||
break;
|
||||
case ESP_SPP_SRV_OPEN_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
|
||||
{
|
||||
switch(event){
|
||||
case ESP_BT_GAP_DISC_RES_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
|
||||
esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
|
||||
for (int i = 0; i < param->disc_res.num_prop; i++){
|
||||
if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
|
||||
&& get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
|
||||
esp_log_buffer_char(SPP_TAG, peer_bdname, peer_bdname_len);
|
||||
if (strlen(remote_device_name) == peer_bdname_len
|
||||
&& strncmp(peer_bdname, remote_device_name, peer_bdname_len) == 0) {
|
||||
memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
|
||||
esp_spp_start_discovery(peer_bd_addr);
|
||||
esp_bt_gap_cancel_discovery();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
|
||||
break;
|
||||
case ESP_BT_GAP_RMT_SRVCS_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVCS_EVT");
|
||||
break;
|
||||
case ESP_BT_GAP_RMT_SRVC_REC_EVT:
|
||||
ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVC_REC_EVT");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void esp_spp_stack_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
{
|
||||
spp_task_work_dispatch((spp_task_cb_t)esp_spp_cb, event, param, sizeof(esp_spp_cb_param_t), NULL);
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
for (int i = 0; i < SPP_DATA_LEN; ++i) {
|
||||
spp_data[i] = i;
|
||||
}
|
||||
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK( ret );
|
||||
|
||||
|
||||
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
|
||||
if (esp_bt_controller_init(&bt_cfg) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s initialize controller failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s enable controller failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bluedroid_init() != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bluedroid_enable() != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s enable bluedroid failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_bt_gap_register_callback(esp_bt_gap_cb) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s gap register failed", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (esp_spp_register_callback(esp_spp_stack_cb) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s spp register failed", __func__);
|
||||
return;
|
||||
}
|
||||
esp_spp_vfs_register();
|
||||
spp_task_task_start_up();
|
||||
if (esp_spp_init(esp_spp_mode) != ESP_OK) {
|
||||
ESP_LOGE(SPP_TAG, "%s spp init failed", __func__);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
128
examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c
Normal file
128
examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "freertos/xtensa_api.h"
|
||||
#include "freertos/FreeRTOSConfig.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_log.h"
|
||||
#include "spp_task.h"
|
||||
|
||||
static void spp_task_task_handler(void *arg);
|
||||
static bool spp_task_send_msg(spp_task_msg_t *msg);
|
||||
static void spp_task_work_dispatched(spp_task_msg_t *msg);
|
||||
|
||||
static xQueueHandle spp_task_task_queue = NULL;
|
||||
static xTaskHandle spp_task_task_handle = NULL;
|
||||
|
||||
bool spp_task_work_dispatch(spp_task_cb_t p_cback, uint16_t event, void *p_params, int param_len, spp_task_copy_cb_t p_copy_cback)
|
||||
{
|
||||
ESP_LOGD(SPP_TASK_TAG, "%s event 0x%x, param len %d", __func__, event, param_len);
|
||||
|
||||
spp_task_msg_t msg;
|
||||
memset(&msg, 0, sizeof(spp_task_msg_t));
|
||||
|
||||
msg.sig = SPP_TASK_SIG_WORK_DISPATCH;
|
||||
msg.event = event;
|
||||
msg.cb = p_cback;
|
||||
|
||||
if (param_len == 0) {
|
||||
return spp_task_send_msg(&msg);
|
||||
} else if (p_params && param_len > 0) {
|
||||
if ((msg.param = malloc(param_len)) != NULL) {
|
||||
memcpy(msg.param, p_params, param_len);
|
||||
/* check if caller has provided a copy callback to do the deep copy */
|
||||
if (p_copy_cback) {
|
||||
p_copy_cback(&msg, msg.param, p_params);
|
||||
}
|
||||
return spp_task_send_msg(&msg);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool spp_task_send_msg(spp_task_msg_t *msg)
|
||||
{
|
||||
if (msg == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xQueueSend(spp_task_task_queue, msg, 10 / portTICK_RATE_MS) != pdTRUE) {
|
||||
ESP_LOGE(SPP_TASK_TAG, "%s xQueue send failed", __func__);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void spp_task_work_dispatched(spp_task_msg_t *msg)
|
||||
{
|
||||
if (msg->cb) {
|
||||
msg->cb(msg->event, msg->param);
|
||||
}
|
||||
}
|
||||
|
||||
static void spp_task_task_handler(void *arg)
|
||||
{
|
||||
spp_task_msg_t msg;
|
||||
for (;;) {
|
||||
if (pdTRUE == xQueueReceive(spp_task_task_queue, &msg, (portTickType)portMAX_DELAY)) {
|
||||
ESP_LOGD(SPP_TASK_TAG, "%s, sig 0x%x, 0x%x", __func__, msg.sig, msg.event);
|
||||
switch (msg.sig) {
|
||||
case SPP_TASK_SIG_WORK_DISPATCH:
|
||||
spp_task_work_dispatched(&msg);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(SPP_TASK_TAG, "%s, unhandled sig: %d", __func__, msg.sig);
|
||||
break;
|
||||
}
|
||||
|
||||
if (msg.param) {
|
||||
free(msg.param);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spp_task_task_start_up(void)
|
||||
{
|
||||
spp_task_task_queue = xQueueCreate(10, sizeof(spp_task_msg_t));
|
||||
xTaskCreate(spp_task_task_handler, "SPPAppT", 2048, NULL, 10, &spp_task_task_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
void spp_task_task_shut_down(void)
|
||||
{
|
||||
if (spp_task_task_handle) {
|
||||
vTaskDelete(spp_task_task_handle);
|
||||
spp_task_task_handle = NULL;
|
||||
}
|
||||
if (spp_task_task_queue) {
|
||||
vQueueDelete(spp_task_task_queue);
|
||||
spp_task_task_queue = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void spp_wr_task_start_up(spp_wr_task_cb_t p_cback, int fd)
|
||||
{
|
||||
xTaskCreate(p_cback, "write_read", 2048, (void *)fd, 5, NULL);
|
||||
}
|
||||
void spp_wr_task_shut_down(void)
|
||||
{
|
||||
vTaskDelete(NULL);
|
||||
}
|
63
examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h
Normal file
63
examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h
Normal file
@ -0,0 +1,63 @@
|
||||
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// 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 __SPP_TASK_H__
|
||||
#define __SPP_TASK_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define SPP_TASK_TAG "SPP_TASK"
|
||||
|
||||
#define SPP_TASK_SIG_WORK_DISPATCH (0x01)
|
||||
|
||||
/**
|
||||
* @brief handler for the dispatched work
|
||||
*/
|
||||
typedef void (* spp_task_cb_t) (uint16_t event, void *param);
|
||||
|
||||
/* message to be sent */
|
||||
typedef struct {
|
||||
uint16_t sig; /*!< signal to spp_task_task */
|
||||
uint16_t event; /*!< message event id */
|
||||
spp_task_cb_t cb; /*!< context switch callback */
|
||||
void *param; /*!< parameter area needs to be last */
|
||||
} spp_task_msg_t;
|
||||
|
||||
/**
|
||||
* @brief parameter deep-copy function to be customized
|
||||
*/
|
||||
typedef void (* spp_task_copy_cb_t) (spp_task_msg_t *msg, void *p_dest, void *p_src);
|
||||
|
||||
/**
|
||||
* @brief work dispatcher for the application task
|
||||
*/
|
||||
bool spp_task_work_dispatch(spp_task_cb_t p_cback, uint16_t event, void *p_params, int param_len, spp_task_copy_cb_t p_copy_cback);
|
||||
|
||||
void spp_task_task_start_up(void);
|
||||
|
||||
void spp_task_task_shut_down(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief handler for write and read
|
||||
*/
|
||||
typedef void (* spp_wr_task_cb_t) (void *fd);
|
||||
|
||||
void spp_wr_task_start_up(spp_wr_task_cb_t p_cback, int fd);
|
||||
|
||||
void spp_wr_task_shut_down(void);
|
||||
|
||||
#endif ///__SPP_TASK_H__
|
@ -0,0 +1,6 @@
|
||||
# Override some defaults so BT stack is enabled
|
||||
# and WiFi disabled by default in this example
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_CLASSIC_BT_ENABLED=y
|
||||
CONFIG_WIFI_ENABLED=n
|
||||
CONFIG_BT_SPP_ENABLED=y
|
Loading…
Reference in New Issue
Block a user