ESP SPP API |
Добавил(а) microsin |
SPP расшифровывается как Serial Port Protocol, в данном контексте это библиотека Espressif для ESP32, которая позволяет организовать поддержку последовательного порта по протоколу Classic Bluetooth. С помощью этой библиотеки можно создать устройство Bluetooth, которое после успешного соединения (pairing) на компьютере будет представляться как COM-порт. Примечание: в этой статье приведен перевод главы, посвященной SPP из документации [1]. Незнакомые термины и сокращения см. в Словарике, в конце статьи. Сначала немного разберемся с терминологией. Классическое устройство Bluetooth может работать либо как инициирующее соединение устройство (обычно это смартфон или компьютер), тогда оно обозначается как INITIATOR, и является клиентом для сервера. Либо оно работает как принимающее соединение устройство (клавиатура, последовательный порт, аудиоустройство и т. д.), тогда оно обозначается как ACCEPTOR, прослушивает входящие соединения и является сервером. Модуль SPP может работать либо в режиме передачи данных ESP_SPP_MODE_CB, либо в режиме ESP_SPP_MODE_VFS, виртуальной файловой системы [3]. Пример см. в папке bluetooth/bluedroid/classic_bt среди примеров ESP-IDF [4], где содержится пример приложения SPP demo. Этот пример позволяет обнаружить службу (service) подключиться, отправить и принять данные SPP. Поставляется 2 основных примера: bluetooth/bluedroid/classic_bt/bt_spp_acceptor Прием данных осуществляется в обработке события ESP_SPP_DATA_IND_EVT. Передача данных не демонстрируется, но её можно легко осуществить с помощью функции esp_spp_write и обработки событий ESP_SPP_WRITE_EVT и ESP_SPP_CONG_EVT. Файл заголовка для API-функций: components/bt/host/bluedroid/api/include/api/esp_spp_api.h Функции, которые возвращают значения типа esp_err_t, в случае успеха возвратят ESP_OK, иначе будет возвращен код ошибки. Базовые коды ошибок определены в заголовке esp_err.h, другие коды ошибок определяются в заголовочных файлах отдельных модулей библиотеки. esp_err_t esp_spp_register_callback (esp_spp_cb_t callback); Эта функция вызывается для инициализации callback-функции для модуля SPP. Параметры [in] callback: указатель на инициализируемую callback-функцию. esp_err_t esp_spp_init (esp_spp_mode_t mode); Эта функция вызывается для инициализации модуля SPP. Когда операция завершена, будет вызвана callback-функция с событием ESP_SPP_INIT_EVT. Эта функция должна быть вызвана после успешного завершения esp_bluedroid_enable(). Параметры [in] mode: выбор режима SPP, ESP_SPP_MODE_CB или ESP_SPP_MODE_VFS. esp_err_t esp_spp_deinit (void); Эта функция вызывается для отмены инициализации модуля SPP. Операция сначала закроет активное соединение SPP, затем будет вызвана callback-функция с событием ESP_SPP_CLOSE_EVT, и значение handle в параметре события будет равно дескриптору соединения. Когда операция завершена, будет вызвана callback-функция с событием ESP_SPP_UNINIT_EVT. Эта функция должна быть вызвана после успешного завершения esp_spp_init(). esp_err_t esp_spp_start_discovery (esp_bd_addr_t bd_addr); Эта функция вызывается для распознавания службы (service discovery) для служб, которые предоставлены имеющимся устройством пира. Когда операция завершена, будет вызвана callback-функция с событием ESP_SPP_DISCOVERY_COMP_EVT. Эта функция должна быть вызвана после успешного вызова esp_spp_init() и перед esp_spp_deinit(). Параметры [in] bd_addr: адрес внешнего удаленного устройства bluetooth. esp_err_t esp_spp_connect (esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t remote_scn, esp_bd_addr_t peer_bd_addr); Эта функция выполняет соединение SPP с внешним удаленным устройством (пиром) по указанному адресу. Когда соединение инициировано или не получилось инициировать соединение, будет вызвана callback-функция с событием ESP_SPP_CL_INIT_EVT. Когда соединение было установлено или потерпело неудачу, будет вызвана callback-функция с событием ESP_SPP_OPEN_EVT. Эта функция должна быть вызвана после успешного esp_spp_init() successful и перед esp_spp_deinit(). Параметры [in] sec_mask: Security Setting Mask. Рекомендуется использовать только ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE или ESP_SPP_SEC_AUTHENTICATE. esp_err_t esp_spp_disconnect (uint32_t handle); Эта функция закроет соединение SPP. Когда операция завершена, будет вызвана callback-функция с событием ESP_SPP_CLOSE_EVT. Эта функция должна быть вызвана после успеха esp_spp_init() и перед esp_spp_deinit(). Параметры [in] handle: дескриптор соединения. esp_err_t esp_spp_start_srv (esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name); Эта функция создает сервер SPP, и начинает прослушивание радиоканала на предмет поступления запроса соединения (SPP connection request) от удаленного устройства Bluetooth. Когда сервер успешно запустится, будет вызвана callback-функция с событием ESP_SPP_START_EVT. Когда установится соединение, будет вызвана callback-функция с событием ESP_SPP_SRV_OPEN_EVT. Эта функция должна быть вызвана после успеха esp_spp_init() и перед esp_spp_deinit(). Параметры [in] sec_mask: Security Setting Mask. Рекомендуется использовать только ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE или ESP_SPP_SEC_AUTHENTICATE. esp_err_t esp_spp_stop_srv (void); Останавливает все серверы SPP. Операция закроет сначала все активные соединения SPP, затем будет вызвана callback-функция с событием ESP_SPP_CLOSE_EVT, параметр handle будет соответствовать дескриптору соединения (если соединений было несколько, то callback-функция будет вызвана соответствующее количество раз). Когда операция завершится, будет вызвана callback-функция с событием ESP_SPP_SRV_STOP_EVT. Эта функция должна быть вызвана после успеха esp_spp_init() и перед esp_spp_deinit(). esp_err_t esp_spp_stop_srv_scn (uint8_t scn); Остановит определенный сервер SPP. Операция закроет сначала все активные соединения SPP, затем будет вызвана callback-функция с событием ESP_SPP_CLOSE_EVT, параметр handle будет соответствовать дескриптору соединений. Когда операция завершится, будет вызвана callback-функция с событием ESP_SPP_SRV_STOP_EVT. Эта функция должна быть вызвана после успеха esp_spp_init() и перед esp_spp_deinit(). Параметры [in] scn: номер канала сервера (server channel number). esp_err_t esp_spp_write (uint32_t handle, int len, uint8_t *p_data); Записывает данные, только для режима ESP_SPP_MODE_CB. Когда эту функцию нужно вызывать несколько раз, строго рекомендуется делать повторные вызовы после получения предыдущего события ESP_SPP_WRITE_EVT с параметром cong равным false (что означает отсутствие перегрузки канала данными). Если предыдущее событие ESP_SPP_WRITE_EVT было с параметром cong равным true (означает перегрузку канала данными), то функция может быть вызвана повторно, когда принято событие ESP_SPP_CONG_EVT с параметром cong равным false. Эта функция должна вызываться после установки соединения между initiator и acceptor. Параметры [in] handle: дескриптор соединения. esp_err_t esp_spp_vfs_register (void); Эта функция используется для регистрации VFS. Сейчас SPP поддерживает только операции write, read и close. [Объединения] Объединение для параметра callback-функции SPP. typedef union { // Событие SPP_INIT_EVT struct spp_init_evt_param { esp_spp_status_t status; /*!< статус */ } init; // Событие SPP_UNINIT_EVT struct spp_uninit_evt_param { esp_spp_status_t status; /*!< статус */ } uninit; // Событие SPP_DISCOVERY_COMP_EVT struct spp_discovery_comp_evt_param { esp_spp_status_t status; /*!< статус */ uint8_t scn_num; /*!< номер канала сервера */ uint8_t scn[ESP_SPP_MAX_SCN]; /*!< channel # */ const char *service_name[ESP_SPP_MAX_SCN]; /*!< имя сервиса */ } disc_comp; // Событие ESP_SPP_OPEN_EVT struct spp_open_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ int fd; /*!< дескриптор файла, только для ESP_SPP_MODE_VFS */ esp_bd_addr_t rem_bda; /*!< адрес пира */ } open; // Событие ESP_SPP_SRV_OPEN_EVT struct spp_srv_open_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ uint32_t new_listen_handle; /*!< новый дескриптор прослушивания */ int fd; /*!< дескриптор файла, только для ESP_SPP_MODE_VFS */ esp_bd_addr_t rem_bda; /*!< адрес пира */ } srv_open; // Событие ESP_SPP_CLOSE_EVT struct spp_close_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t port_status; /*!< состояние порта PORT */ uint32_t handle; /*!< дескриптор соединения */ bool async; /*!< FALSE, если отключение инициировано локально */ } close; // Событие ESP_SPP_START_EVT struct spp_start_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ uint8_t sec_id; /*!< security ID, используемый этим сервером */ uint8_t scn; /*!< номер канала сервера */ bool use_co; /*!< TRUE для использования co_rfc_data */ } start; // Событие ESP_SPP_SRV_STOP_EVT struct spp_srv_stop_evt_param { esp_spp_status_t status; /*!< статус */ uint8_t scn; /*!< номер канала сервера */ } srv_stop; // Событие ESP_SPP_CL_INIT_EVT struct spp_cl_init_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ uint8_t sec_id; /*!< security ID, используемый этим сервером */ bool use_co; /*!< TRUE для использования co_rfc_data */ } cl_init; // Событие ESP_SPP_WRITE_EVT struct spp_write_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ int len; /*!< длина записанных данных */ bool cong; /*!< статус перегруженности */ } write; // Событие ESP_SPP_DATA_IND_EVT struct spp_data_ind_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ uint16_t len; /*!< длина данных */ uint8_t *data; /*!< принятые данные */ } data_ind; // Событие ESP_SPP_CONG_EVT struct spp_cong_evt_param { esp_spp_status_t status; /*!< статус */ uint32_t handle; /*!< дескриптор соединения */ bool cong; /*!< TRUE была перегрузка данными, FALSE перегрузки не было */ } cong; } esp_spp_cb_param_t; [Макросы] ESP_SPP_SEC_NONE ESP_SPP_SEC_AUTHORIZE ESP_SPP_SEC_AUTHENTICATE ESP_SPP_SEC_ENCRYPT ESP_SPP_SEC_MODE4_LEVEL4 ESP_SPP_SEC_MITM ESP_SPP_SEC_IN_16_DIGITS ESP_SPP_MAX_MTU ESP_SPP_MAX_SCN [Определения типов] typedef uint16_t esp_spp_sec_t; Тип, используемый для маски безопасности. typedef void() esp_spp_cb_t (esp_spp_cb_event_t event, esp_spp_cb_param_t *param); Тип для callback-функции SPP. Когда обрабатывается событие ESP_SPP_DATA_IND_EVT, настоятельно рекомендуется кешировать приходящие данные, и обрабатывать их в задаче приложения с более низким приоритетом вместо того, чтобы обрабатывать их непосредственно в callback-функции. Параметры event: тип события. [Перечисления] typedef enum { ESP_SPP_SUCCESS = 0, /*!< Успешная операция. */ ESP_SPP_FAILURE, /*!< Какая-то ошибка (generic failure). */ ESP_SPP_BUSY, /*!< Временная невозможность обработки этого запроса. */ ESP_SPP_NO_DATA, /*!< Нет данных. */ ESP_SPP_NO_RESOURCE, /*!< Недостаточно ресурсов. */ ESP_SPP_NEED_INIT, /*!< Сначала надо инициализировать модуль SPP. */ ESP_SPP_NEED_DEINIT, /*!< Сначала надо отменить инициализацию модуля SPP. */ ESP_SPP_NO_CONNECTION, /*!< Вероятно соединение закрыто. */ ESP_SPP_NO_SERVER, /*!< Нет сервера SPP. */ } esp_spp_status_t; typedef enum { ESP_SPP_ROLE_MASTER = 0, /*!< Роль мастера */ ESP_SPP_ROLE_SLAVE = 1, /*!< Роль подчиненного устройства */ } esp_spp_role_t; typedef enum { ESP_SPP_MODE_CB = 0, /*!< При поступлении данных будет вызвана callback-функция, где в её параметре будут
переданы эти данные. */ ESP_SPP_MODE_VFS = 1, /*!< Для чтения/записи данных используется VFS. */ } esp_spp_mode_t; Это перечисление используется для обозначения событий callback-функции. typedef enum { ESP_SPP_INIT_EVT = 0, /*!< При инициализации SPP. */ ESP_SPP_UNINIT_EVT = 1, /*!< При отмене инициализации SPP. */ ESP_SPP_DISCOVERY_COMP_EVT = 8, /*!< При завершении SDP. */ ESP_SPP_OPEN_EVT = 26, /*!< Когда открыто соединение с клиентом SPP. */ ESP_SPP_CLOSE_EVT = 27, /*!< Когда соединение SPP закрыто. */ ESP_SPP_START_EVT = 28, /*!< Когда запустился сервер SPP. */ ESP_SPP_CL_INIT_EVT = 29, /*!< Когда клиент SPP инициировал соединение. */ ESP_SPP_DATA_IND_EVT = 30, /*!< Когда на соединение SPP поступили данные. Только для режима ESP_SPP_MODE_CB. */ ESP_SPP_CONG_EVT = 31, /*!< Когда поменялся статус перегруженности данными соединения SPP.
Только для режима ESP_SPP_MODE_CB. */ ESP_SPP_WRITE_EVT = 33, /*!< Когда завершилась операция записи SPP. Только для режима ESP_SPP_MODE_CB. */ ESP_SPP_SRV_OPEN_EVT = 34, /*!< Когда открыто соединение сервера SPP. */ ESP_SPP_SRV_STOP_EVT = 35, /*!< Когда остановлен сервер SPP. */ } esp_spp_cb_event_t; [Словарик] acceptor устройство Bluietooth, ожидающее поступление запроса на соединение от устройства initiator. BD Address BD_ADDR, Bluetooth Device Address. BTA Bluetooth Application Layer. BTE Bluetooth Embedded System. initiator устройство Bluetooth, которое инициирует соединение с устройством acceptor. LMP Link Manager Protocol, протокол управления соединением. MITM Man-In-The_Middle, защита от атаки "человек посередине". MTU Maximum Transfer Unit, максимально допустимый размер для передаваемого/принимаемого блока данных. PDU Protocol Data Unit. peer пир, противоположный участник соединения Bluetooth. SCN Service Channel Number. SDP Service Discovery Protocol, протокол распознавания поддерживаемой службы. VFS Virtual FileSystem [3]. [Ссылки] 1. ESP SPP API site:docs.espressif.com. |