diff --git a/components/bt/bluedroid/api/esp_spp_api.c b/components/bt/bluedroid/api/esp_spp_api.c index fe4db951be..3fce8c1f8f 100644 --- a/components/bt/bluedroid/api/esp_spp_api.c +++ b/components/bt/bluedroid/api/esp_spp_api.c @@ -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 diff --git a/components/bt/bluedroid/api/include/api/esp_spp_api.h b/components/bt/bluedroid/api/include/api/esp_spp_api.h index 86e52c8cc8..e819158cd2 100644 --- a/components/bt/bluedroid/api/include/api/esp_spp_api.h +++ b/components/bt/bluedroid/api/include/api/esp_spp_api.h @@ -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 diff --git a/components/bt/bluedroid/bta/jv/bta_jv_api.c b/components/bt/bluedroid/bta/jv/bta_jv_api.c index e6a686e46f..5430d36bcb 100644 --- a/components/bt/bluedroid/bta/jv/bta_jv_api.c +++ b/components/bt/bluedroid/bta/jv/bta_jv_api.c @@ -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); } diff --git a/components/bt/bluedroid/btc/profile/std/include/btc_spp.h b/components/bt/bluedroid/btc/profile/std/include/btc_spp.h index a75fc1d626..69001d507c 100644 --- a/components/bt/bluedroid/btc/profile/std/include/btc_spp.h +++ b/components/bt/bluedroid/btc/profile/std/include/btc_spp.h @@ -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__ \ No newline at end of file diff --git a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c b/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c index d39bcc804b..82d84b2d02 100644 --- a/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c +++ b/components/bt/bluedroid/btc/profile/std/spp/btc_spp.c @@ -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 #include #include +#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; } - 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); + 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_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: - 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); + 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! 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); break; } - list_remove(slot->list, list_front(slot->list)); - osi_mutex_unlock(&spp_slot_mutex); + 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.len = p_data->rfc_write.len; + param.write.cong = p_data->rfc_write.cong; + btc_spp_cb_to_app(ESP_SPP_WRITE_EVT, ¶m); + 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; + } + 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: - 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); + 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; - 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__); + 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__); + } + } 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_slot_mutex); + 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 \ No newline at end of file diff --git a/components/bt/bluedroid/stack/l2cap/l2c_utils.c b/components/bt/bluedroid/stack/l2cap/l2c_utils.c index 9c9385250d..358a57b5f4 100644 --- a/components/bt/bluedroid/stack/l2cap/l2c_utils.c +++ b/components/bt/bluedroid/stack/l2cap/l2c_utils.c @@ -950,7 +950,7 @@ void l2cu_send_peer_disc_rsp (tL2C_LCB *p_lcb, UINT8 remote_id, UINT16 local_cid L2CAP_TRACE_WARNING("lcb already released\n"); return; } - + if ((p_buf = l2cu_build_header(p_lcb, L2CAP_DISC_RSP_LEN, L2CAP_CMD_DISC_RSP, remote_id)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no buffer for disc_rsp"); return; @@ -1649,7 +1649,7 @@ void l2cu_release_ccb (tL2C_CCB *p_ccb) p_ccb->fcrb.retrans_q = NULL; p_ccb->fcrb.waiting_for_ack_q = NULL; #endif ///CLASSIC_BT_INCLUDED == TRUE - + #if (CLASSIC_BT_INCLUDED == TRUE) l2c_fcr_cleanup (p_ccb); @@ -2545,10 +2545,10 @@ void l2cu_resubmit_pending_sec_req (BD_ADDR p_bda) l2c_csm_execute (p_ccb, L2CEVT_SEC_RE_SEND_CMD, NULL); } } - } + } } } -#endif ///CLASSIC_BT_INCLUDED == TRUE +#endif ///CLASSIC_BT_INCLUDED == TRUE #if L2CAP_CONFORMANCE_TESTING == 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); @@ -3428,7 +3428,7 @@ BT_HDR *l2cu_get_next_buffer_to_send (tL2C_LCB *p_lcb) return (p_buf); } #else - continue; + continue; #endif ///CLASSIC_BT_INCLUDED == TRUE } else { diff --git a/examples/bluetooth/bt_spp_acceptor/Makefile b/examples/bluetooth/bt_spp_acceptor/Makefile index 3d61babf60..a2666a75a1 100644 --- a/examples/bluetooth/bt_spp_acceptor/Makefile +++ b/examples/bluetooth/bt_spp_acceptor/Makefile @@ -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 diff --git a/examples/bluetooth/bt_spp_initiator/Makefile b/examples/bluetooth/bt_spp_initiator/Makefile index 38567f8506..d8630415f7 100644 --- a/examples/bluetooth/bt_spp_initiator/Makefile +++ b/examples/bluetooth/bt_spp_initiator/Makefile @@ -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 diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/Makefile b/examples/bluetooth/bt_spp_vfs_acceptor/Makefile new file mode 100644 index 0000000000..ea7d1e83b0 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/Makefile @@ -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 diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/README.rst b/examples/bluetooth/bt_spp_vfs_acceptor/README.rst new file mode 100644 index 0000000000..76571c45e3 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/README.rst @@ -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. \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk b/examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c b/examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c new file mode 100644 index 0000000000..76b74552c1 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/main/example_spp_vfs_acceptor_demo.c @@ -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 +#include +#include +#include +#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; + } +} + diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c b/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c new file mode 100644 index 0000000000..7db4970777 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.c @@ -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 +#include +#include +#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); +} \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h b/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h new file mode 100644 index 0000000000..512773ecbe --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/main/spp_task.h @@ -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 +#include +#include + +#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__ \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults b/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults new file mode 100644 index 0000000000..a8ace21985 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_acceptor/sdkconfig.defaults @@ -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 \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_initiator/Makefile b/examples/bluetooth/bt_spp_vfs_initiator/Makefile new file mode 100644 index 0000000000..d0817d8fd3 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/Makefile @@ -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 diff --git a/examples/bluetooth/bt_spp_vfs_initiator/README.rst b/examples/bluetooth/bt_spp_vfs_initiator/README.rst new file mode 100644 index 0000000000..efb2513d91 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/README.rst @@ -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. \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/component.mk b/examples/bluetooth/bt_spp_vfs_initiator/main/component.mk new file mode 100644 index 0000000000..a98f634eae --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/main/component.mk @@ -0,0 +1,4 @@ +# +# "main" pseudo-component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c b/examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c new file mode 100644 index 0000000000..47089bf0cb --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/main/example_spp_vfs_initiator_demo.c @@ -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 +#include +#include +#include +#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; + } +} + diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c b/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c new file mode 100644 index 0000000000..a82ca19186 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.c @@ -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 +#include +#include +#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); +} \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h b/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h new file mode 100644 index 0000000000..512773ecbe --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/main/spp_task.h @@ -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 +#include +#include + +#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__ \ No newline at end of file diff --git a/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults b/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults new file mode 100644 index 0000000000..a8ace21985 --- /dev/null +++ b/examples/bluetooth/bt_spp_vfs_initiator/sdkconfig.defaults @@ -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 \ No newline at end of file