1 /*
2  * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef __ESP_SPP_API_H__
8 #define __ESP_SPP_API_H__
9 
10 #include "esp_err.h"
11 #include "esp_bt_defs.h"
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 #define ESP_SPP_MAX_MTU                 (3*330)     /*!< SPP max MTU */
18 #define ESP_SPP_MAX_SCN                 31          /*!< SPP max SCN */
19 #define ESP_SPP_MIN_TX_BUFFER_SIZE      100         /*!< SPP min tx buffer */
20 #define ESP_SPP_MAX_TX_BUFFER_SIZE      (ESP_SPP_MAX_MTU * 10)  /*!< SPP max tx buffer size */
21 
22 /**
23  * @brief SPP default configuration
24  */
25 #define BT_SPP_DEFAULT_CONFIG() { \
26     .mode = ESP_SPP_MODE_VFS, \
27     .enable_l2cap_ertm = true, \
28     .tx_buffer_size = ESP_SPP_MAX_TX_BUFFER_SIZE, \
29 }
30 
31 /* Security Setting Mask
32 Use these three mask modes on both sides:
33 1. ESP_SPP_SEC_NONE
34 2. ESP_SPP_SEC_AUTHENTICATE
35 3. (ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)
36 Use these three mask modes only on acceptor side:
37 1. ESP_SPP_SEC_IN_16_DIGITS
38 2. (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE)
39 3. (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)
40 Due to certain limitations, do not use these mask modes:
41 1. ESP_SPP_SEC_AUTHORIZE
42 2. ESP_SPP_SEC_MODE4_LEVEL4
43 3. ESP_SPP_SEC_MITM
44 */
45 #define ESP_SPP_SEC_NONE            0x0000    /*!< No security. relate to BTA_SEC_NONE in bta/bta_api.h */
46 #define ESP_SPP_SEC_AUTHORIZE       0x0001    /*!< Authorization required (only needed for out going connection ) relate to BTA_SEC_AUTHORIZE in bta/bta_api.h*/
47 #define ESP_SPP_SEC_AUTHENTICATE    0x0012    /*!< Authentication required.  relate to BTA_SEC_AUTHENTICATE in bta/bta_api.h*/
48 #define ESP_SPP_SEC_ENCRYPT         0x0024    /*!< Encryption required.  relate to BTA_SEC_ENCRYPT in bta/bta_api.h*/
49 #define ESP_SPP_SEC_MODE4_LEVEL4    0x0040    /*!< Mode 4 level 4 service, i.e. incoming/outgoing MITM and P-256 encryption  relate to BTA_SEC_MODE4_LEVEL4 in bta/bta_api.h*/
50 #define ESP_SPP_SEC_MITM            0x3000    /*!< Man-In-The_Middle protection  relate to BTA_SEC_MITM in bta/bta_api.h*/
51 #define ESP_SPP_SEC_IN_16_DIGITS    0x4000    /*!< Min 16 digit for pin code  relate to BTA_SEC_IN_16_DIGITS in bta/bta_api.h*/
52 typedef uint16_t esp_spp_sec_t;
53 
54 typedef enum {
55     ESP_SPP_SUCCESS   = 0,          /*!< Successful operation. */
56     ESP_SPP_FAILURE,                /*!< Generic failure. */
57     ESP_SPP_BUSY,                   /*!< Temporarily can not handle this request. */
58     ESP_SPP_NO_DATA,                /*!< No data */
59     ESP_SPP_NO_RESOURCE,            /*!< No more resource */
60     ESP_SPP_NEED_INIT,              /*!< SPP module shall init first */
61     ESP_SPP_NEED_DEINIT,            /*!< SPP module shall deinit first */
62     ESP_SPP_NO_CONNECTION,          /*!< Connection may have been closed */
63     ESP_SPP_NO_SERVER,              /*!< No SPP server */
64 } esp_spp_status_t;
65 
66 typedef enum {
67     ESP_SPP_ROLE_MASTER     = 0,          /*!< Role: master */
68     ESP_SPP_ROLE_SLAVE      = 1,          /*!< Role: slave */
69 } esp_spp_role_t;
70 
71 typedef enum {
72     ESP_SPP_MODE_CB         = 0,          /*!< When data is coming, a callback will come with data */
73     ESP_SPP_MODE_VFS        = 1,          /*!< Use VFS to write/read data */
74 } esp_spp_mode_t;
75 
76 /**
77  * @brief SPP configuration parameters
78  */
79 typedef struct {
80     esp_spp_mode_t mode;                  /*!< Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_VFS. */
81     bool enable_l2cap_ertm;               /*!< Enable/disable Logical Link Control and Adaptation Layer Protocol enhanced retransmission mode. */
82     uint16_t tx_buffer_size;              /*!< Tx buffer size for a new SPP channel. A smaller setting can save memory, but may incur a decrease in throughput. Only for ESP_SPP_MODE_VFS mode. */
83 } esp_spp_cfg_t;
84 
85 /**
86  * @brief SPP callback function events
87  */
88 typedef enum {
89     ESP_SPP_INIT_EVT                    = 0,                /*!< When SPP is initialized, the event comes */
90     ESP_SPP_UNINIT_EVT                  = 1,                /*!< When SPP is deinitialized, the event comes */
91     ESP_SPP_DISCOVERY_COMP_EVT          = 8,                /*!< When SDP discovery complete, the event comes */
92     ESP_SPP_OPEN_EVT                    = 26,               /*!< When SPP Client connection open, the event comes */
93     ESP_SPP_CLOSE_EVT                   = 27,               /*!< When SPP connection closed, the event comes */
94     ESP_SPP_START_EVT                   = 28,               /*!< When SPP server started, the event comes */
95     ESP_SPP_CL_INIT_EVT                 = 29,               /*!< When SPP client initiated a connection, the event comes */
96     ESP_SPP_DATA_IND_EVT                = 30,               /*!< When SPP connection received data, the event comes, only for ESP_SPP_MODE_CB */
97     ESP_SPP_CONG_EVT                    = 31,               /*!< When SPP connection congestion status changed, the event comes, only for ESP_SPP_MODE_CB */
98     ESP_SPP_WRITE_EVT                   = 33,               /*!< When SPP write operation completes, the event comes, only for ESP_SPP_MODE_CB */
99     ESP_SPP_SRV_OPEN_EVT                = 34,               /*!< When SPP Server connection open, the event comes */
100     ESP_SPP_SRV_STOP_EVT                = 35,               /*!< When SPP server stopped, the event comes */
101     ESP_SPP_VFS_REGISTER_EVT            = 36,               /*!< When SPP VFS register, the event comes */
102     ESP_SPP_VFS_UNREGISTER_EVT          = 37,               /*!< When SPP VFS unregister, the event comes */
103 } esp_spp_cb_event_t;
104 
105 
106 /**
107  * @brief SPP callback parameters union
108  */
109 typedef union {
110     /**
111      * @brief SPP_INIT_EVT
112      */
113     struct spp_init_evt_param {
114         esp_spp_status_t    status;         /*!< status */
115     } init;                                 /*!< SPP callback param of SPP_INIT_EVT */
116 
117     /**
118      * @brief SPP_UNINIT_EVT
119      */
120     struct spp_uninit_evt_param {
121         esp_spp_status_t    status;         /*!< status */
122     } uninit;                               /*!< SPP callback param of SPP_UNINIT_EVT */
123 
124     /**
125      * @brief SPP_DISCOVERY_COMP_EVT
126      */
127     struct spp_discovery_comp_evt_param {
128         esp_spp_status_t status;                   /*!< status */
129         uint8_t scn_num;                           /*!< The num of scn_num */
130         uint8_t scn[ESP_SPP_MAX_SCN];              /*!< channel # */
131         const char *service_name[ESP_SPP_MAX_SCN]; /*!< service_name */
132     } disc_comp;                            /*!< SPP callback param of SPP_DISCOVERY_COMP_EVT */
133 
134     /**
135      * @brief ESP_SPP_OPEN_EVT
136      */
137     struct spp_open_evt_param {
138         esp_spp_status_t    status;         /*!< status */
139         uint32_t            handle;         /*!< The connection handle */
140         int                 fd;             /*!< The file descriptor only for ESP_SPP_MODE_VFS */
141         esp_bd_addr_t       rem_bda;        /*!< The peer address */
142     } open;                                 /*!< SPP callback param of ESP_SPP_OPEN_EVT */
143 
144     /**
145      * @brief ESP_SPP_SRV_OPEN_EVT
146      */
147     struct spp_srv_open_evt_param {
148         esp_spp_status_t    status;         /*!< status */
149         uint32_t            handle;         /*!< The connection handle */
150         uint32_t            new_listen_handle;  /*!< The new listen handle */
151         int                 fd;             /*!< The file descriptor only for ESP_SPP_MODE_VFS */
152         esp_bd_addr_t       rem_bda;        /*!< The peer address */
153     } srv_open;                             /*!< SPP callback param of ESP_SPP_SRV_OPEN_EVT */
154     /**
155      * @brief ESP_SPP_CLOSE_EVT
156      */
157     struct spp_close_evt_param {
158         esp_spp_status_t    status;         /*!< status */
159         uint32_t            port_status;    /*!< PORT status */
160         uint32_t            handle;         /*!< The connection handle */
161         bool                async;          /*!< FALSE, if local initiates disconnect */
162     } close;                                /*!< SPP callback param of ESP_SPP_CLOSE_EVT */
163 
164     /**
165      * @brief ESP_SPP_START_EVT
166      */
167     struct spp_start_evt_param {
168         esp_spp_status_t    status;         /*!< status */
169         uint32_t            handle;         /*!< The connection handle */
170         uint8_t             sec_id;         /*!< security ID used by this server */
171         uint8_t             scn;            /*!< Server channel number */
172         bool                use_co;         /*!< TRUE to use co_rfc_data */
173     } start;                                /*!< SPP callback param of ESP_SPP_START_EVT */
174 
175     /**
176      * @brief ESP_SPP_SRV_STOP_EVT
177      */
178     struct spp_srv_stop_evt_param {
179         esp_spp_status_t    status;         /*!< status */
180         uint8_t             scn;            /*!< Server channel number */
181     } srv_stop;                             /*!< SPP callback param of ESP_SPP_SRV_STOP_EVT */
182 
183     /**
184      * @brief ESP_SPP_CL_INIT_EVT
185      */
186     struct spp_cl_init_evt_param {
187         esp_spp_status_t    status;         /*!< status */
188         uint32_t            handle;         /*!< The connection handle */
189         uint8_t             sec_id;         /*!< security ID used by this server */
190         bool                use_co;         /*!< TRUE to use co_rfc_data */
191     } cl_init;                              /*!< SPP callback param of ESP_SPP_CL_INIT_EVT */
192 
193     /**
194      * @brief ESP_SPP_WRITE_EVT
195      */
196     struct spp_write_evt_param {
197         esp_spp_status_t    status;         /*!< status */
198         uint32_t            handle;         /*!< The connection handle */
199         int                 len;            /*!< The length of the data written. */
200         bool                cong;           /*!< congestion status */
201     } write;                                /*!< SPP callback param of ESP_SPP_WRITE_EVT */
202 
203     /**
204      * @brief ESP_SPP_DATA_IND_EVT
205      */
206     struct spp_data_ind_evt_param {
207         esp_spp_status_t    status;         /*!< status */
208         uint32_t            handle;         /*!< The connection handle */
209         uint16_t            len;            /*!< The length of data */
210         uint8_t             *data;          /*!< The data received */
211     } data_ind;                             /*!< SPP callback param of ESP_SPP_DATA_IND_EVT */
212 
213     /**
214      * @brief ESP_SPP_CONG_EVT
215      */
216     struct spp_cong_evt_param {
217         esp_spp_status_t    status;         /*!< status */
218         uint32_t            handle;         /*!< The connection handle */
219         bool                cong;           /*!< TRUE, congested. FALSE, uncongested */
220     } cong;                                 /*!< SPP callback param of ESP_SPP_CONG_EVT */
221 
222     /**
223      * @brief ESP_SPP_VFS_REGISTER_EVT
224      */
225     struct spp_vfs_register_evt_param {
226         esp_spp_status_t    status;         /*!< status */
227     } vfs_register;                         /*!< SPP callback param of ESP_SPP_VFS_REGISTER_EVT */
228 
229     /**
230      * @brief ESP_SPP_VFS_UNREGISTER_EVT
231      */
232     struct spp_vfs_unregister_evt_param {
233         esp_spp_status_t    status;         /*!< status */
234     } vfs_unregister;                       /*!< SPP callback param of ESP_SPP_VFS_UNREGISTER_EVT */
235 } esp_spp_cb_param_t;                       /*!< SPP callback parameter union type */
236 
237 /**
238  * @brief       SPP callback function type.
239  *              When handle ESP_SPP_DATA_IND_EVT, it is strongly recommended to cache incoming data, and process them in
240  *              other lower priority application task rather than in this callback directly.
241  *
242  * @param       event:      Event type
243  * @param       param:      Point to callback parameter, currently is union type
244  */
245 typedef void (*esp_spp_cb_t)(esp_spp_cb_event_t event, esp_spp_cb_param_t *param);
246 
247 /**
248  * @brief       This function is called to init callbacks with SPP module.
249  *
250  * @param[in]   callback:   pointer to the init callback function.
251  *
252  * @return
253  *              - ESP_OK: success
254  *              - other: failed
255  */
256 esp_err_t esp_spp_register_callback(esp_spp_cb_t callback);
257 
258 /**
259  * @brief       This function is called to init SPP module.
260  *              When the operation is completed, the callback function will be called with ESP_SPP_INIT_EVT.
261  *              This function should be called after esp_bluedroid_enable() completes successfully.
262  *
263  * @param[in]   mode: Choose the mode of SPP, ESP_SPP_MODE_CB or ESP_SPP_MODE_VFS.
264  *
265  * @return
266  *              - ESP_OK: success
267  *              - other: failed
268  */
269 esp_err_t esp_spp_init(esp_spp_mode_t mode) __attribute__((deprecated("Please use esp_spp_enhanced_init")));
270 
271 
272 /**
273  * @brief       This function is called to init SPP module.
274  *              When the operation is completed, the callback function will be called with ESP_SPP_INIT_EVT.
275  *              This function should be called after esp_bluedroid_enable() completes successfully.
276  *
277  * @param[in]   cfg: SPP configuration.
278  *
279  * @note        The member variable enable_l2cap_etrm in esp_spp_cfg_t can affect all L2CAP channel
280  *              configurations of the upper layer RFCOMM protocol.
281  *
282  * @return
283  *              - ESP_OK: success
284  *              - other: failed
285  */
286 esp_err_t esp_spp_enhanced_init(const esp_spp_cfg_t *cfg);
287 
288 /**
289  * @brief       This function is called to uninit SPP module.
290  *              The operation will close all active SPP connection first, then the callback function will be called
291  *              with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
292  *              When the operation is completed, the callback function will be called with ESP_SPP_UNINIT_EVT.
293  *              This function should be called after esp_spp_init()/esp_spp_enhanced_init() completes successfully.
294  *
295  * @return
296  *              - ESP_OK: success
297  *              - other: failed
298  */
299 esp_err_t esp_spp_deinit(void);
300 
301 
302 /**
303  * @brief       This function is called to performs service discovery for the services provided by the given peer device.
304  *              When the operation is completed, the callback function will be called with ESP_SPP_DISCOVERY_COMP_EVT.
305  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
306  *
307  * @param[in]   bd_addr:   Remote device bluetooth device address.
308  *
309  * @return
310  *              - ESP_OK: success
311  *              - other: failed
312  */
313 esp_err_t esp_spp_start_discovery(esp_bd_addr_t bd_addr);
314 
315 /**
316  * @brief       This function makes an SPP connection to a remote BD Address.
317  *              When the connection is initiated or failed to initiate, the callback is called with ESP_SPP_CL_INIT_EVT.
318  *              When the connection is established or failed, the callback is called with ESP_SPP_OPEN_EVT.
319  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
320  *
321  * @param[in]   sec_mask:     Security Setting Mask. Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.
322  * @param[in]   role:         Master or slave.
323  * @param[in]   remote_scn:   Remote device bluetooth device SCN.
324  * @param[in]   peer_bd_addr: Remote device bluetooth device address.
325  *
326  * @return
327  *              - ESP_OK: success
328  *              - other: failed
329  */
330 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);
331 
332 /**
333  * @brief       This function closes an SPP connection.
334  *              When the operation is completed, the callback function will be called with ESP_SPP_CLOSE_EVT.
335  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
336  *
337  * @param[in]   handle:    The connection handle.
338  *
339  * @return
340  *              - ESP_OK: success
341  *              - other: failed
342  */
343 esp_err_t esp_spp_disconnect(uint32_t handle);
344 
345 /**
346  * @brief       This function create a SPP server and starts listening for an
347  *              SPP connection request from a remote Bluetooth device.
348  *              When the server is started successfully, the callback is called with ESP_SPP_START_EVT.
349  *              When the connection is established, the callback is called with ESP_SPP_SRV_OPEN_EVT.
350  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
351  *
352  * @param[in]   sec_mask:     Security Setting Mask. Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHORIZE or ESP_SPP_SEC_AUTHENTICATE only.
353  * @param[in]   role:         Master or slave.
354  * @param[in]   local_scn:    The specific channel you want to get.
355  *                            If channel is 0, means get any channel.
356  * @param[in]   name:         Server's name.
357  *
358  * @return
359  *              - ESP_OK: success
360  *              - other: failed
361  */
362 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);
363 
364 /**
365  * @brief       This function stops all SPP servers.
366  *              The operation will close all active SPP connection first, then the callback function will be called
367  *              with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
368  *              When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
369  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
370  *
371  * @return
372  *              - ESP_OK: success
373  *              - other: failed
374  */
375 
376 esp_err_t esp_spp_stop_srv(void);
377 
378 /**
379  * @brief       This function stops a specific SPP server.
380  *              The operation will close all active SPP connection first on the specific SPP server, then the callback function will be called
381  *              with ESP_SPP_CLOSE_EVT, and the number of ESP_SPP_CLOSE_EVT is equal to the number of connection.
382  *              When the operation is completed, the callback is called with ESP_SPP_SRV_STOP_EVT.
383  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
384  *
385  * @param[in]   scn:         Server channel number.
386  *
387  * @return
388  *              - ESP_OK: success
389  *              - other: failed
390  */
391 esp_err_t esp_spp_stop_srv_scn(uint8_t scn);
392 
393 /**
394  * @brief       This function is used to write data, only for ESP_SPP_MODE_CB.
395  *              When this function need to be called repeatedly, it is strongly recommended to call this function again after
396  *              the previous event ESP_SPP_WRITE_EVT is received and the parameter 'cong' is equal to false. If the previous event
397  *              ESP_SPP_WRITE_EVT with parameter 'cong' is equal to true, the function can only be called again when the event
398  *              ESP_SPP_CONG_EVT with parameter 'cong' equal to false is received.
399  *              This function must be called after an connection between initiator and acceptor has been established.
400  *
401  * @param[in]   handle: The connection handle.
402  * @param[in]   len:    The length of the data written.
403  * @param[in]   p_data: The data written.
404  *
405  * @return
406  *              - ESP_OK: success
407  *              - other: failed
408  */
409 esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data);
410 
411 
412 /**
413  * @brief       This function is used to register VFS.
414  *              For now, SPP only supports write, read and close.
415  *              When the operation is completed, the callback function will be called with ESP_SPP_VFS_REGISTER_EVT.
416  *              This function must be called after esp_spp_init()/esp_spp_enhanced_init() successful and before esp_spp_deinit().
417  *
418  * @return
419  *              - ESP_OK: success
420  *              - other: failed
421  */
422 esp_err_t esp_spp_vfs_register(void);
423 
424 /**
425  * @brief       This function is used to unregister VFS.
426  *              When the operation is completed, the callback function will be called with ESP_SPP_VFS_UNREGISTER_EVT.
427  *              This function must be called after esp_spp_vfs_register() successful and before esp_spp_deinit().
428  *
429  * @return
430  *              - ESP_OK: success
431  *              - other: failed
432  */
433 esp_err_t esp_spp_vfs_unregister(void);
434 
435 #ifdef __cplusplus
436 }
437 #endif
438 
439 #endif ///__ESP_SPP_API_H__
440