1 /*
2  * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <string.h>
8 
9 #include "esp_bt_main.h"
10 #include "btc/btc_manage.h"
11 
12 #include "btc_spp.h"
13 #include "esp_spp_api.h"
14 #include "common/bt_target.h"
15 
16 #if (defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE)
17 
18 static const uint8_t UUID_SPP[16] = {0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
19                                     0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB
20                                     };
21 static tSDP_UUID sdp_uuid;
22 
esp_spp_register_callback(esp_spp_cb_t callback)23 esp_err_t esp_spp_register_callback(esp_spp_cb_t callback)
24 {
25     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
26 
27     if (callback == NULL) {
28         return ESP_FAIL;
29     }
30 
31     btc_profile_cb_set(BTC_PID_SPP, callback);
32     return ESP_OK;
33 }
34 
35 
esp_spp_init(esp_spp_mode_t mode)36 esp_err_t esp_spp_init(esp_spp_mode_t mode)
37 {
38     esp_spp_cfg_t bt_spp_cfg = {
39         .mode = mode,
40         .enable_l2cap_ertm = true,
41         .tx_buffer_size = ESP_SPP_MAX_TX_BUFFER_SIZE,
42     };
43 
44     return esp_spp_enhanced_init(&bt_spp_cfg);
45 }
46 
esp_spp_enhanced_init(const esp_spp_cfg_t * cfg)47 esp_err_t esp_spp_enhanced_init(const esp_spp_cfg_t *cfg)
48 {
49     btc_msg_t msg;
50     btc_spp_args_t arg;
51     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
52 
53     if (cfg->mode == ESP_SPP_MODE_VFS && (cfg->tx_buffer_size < ESP_SPP_MIN_TX_BUFFER_SIZE ||
54             cfg->tx_buffer_size > ESP_SPP_MAX_TX_BUFFER_SIZE)) {
55         LOG_WARN("Invalid tx buffer size");
56         return ESP_ERR_INVALID_ARG;
57     }
58 
59     msg.sig = BTC_SIG_API_CALL;
60     msg.pid = BTC_PID_SPP;
61     msg.act = BTC_SPP_ACT_INIT;
62 
63     arg.init.mode = cfg->mode;
64     arg.init.enable_l2cap_ertm = cfg->enable_l2cap_ertm;
65     arg.init.tx_buffer_size = cfg->tx_buffer_size;
66 
67     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
68 }
69 
esp_spp_deinit(void)70 esp_err_t esp_spp_deinit(void)
71 {
72     btc_msg_t msg;
73     btc_spp_args_t arg;
74     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
75 
76     msg.sig = BTC_SIG_API_CALL;
77     msg.pid = BTC_PID_SPP;
78     msg.act = BTC_SPP_ACT_UNINIT;
79 
80     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
81 }
82 
83 
esp_spp_start_discovery(esp_bd_addr_t bd_addr)84 esp_err_t esp_spp_start_discovery(esp_bd_addr_t bd_addr)
85 {
86     sdp_uuid.len = 16;
87     memcpy(sdp_uuid.uu.uuid128, UUID_SPP, sizeof(sdp_uuid.uu.uuid128));
88 
89     btc_msg_t msg;
90     btc_spp_args_t arg;
91     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
92 
93     msg.sig = BTC_SIG_API_CALL;
94     msg.pid = BTC_PID_SPP;
95     msg.act = BTC_SPP_ACT_START_DISCOVERY;
96 
97     memcpy(arg.start_discovery.bd_addr, bd_addr, ESP_BD_ADDR_LEN);
98     arg.start_discovery.num_uuid = 1;
99     arg.start_discovery.p_uuid_list = &sdp_uuid;
100 
101     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t),
102                 btc_spp_arg_deep_copy, btc_spp_arg_deep_free) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
103 }
104 
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)105 esp_err_t esp_spp_connect(esp_spp_sec_t sec_mask,
106                           esp_spp_role_t role, uint8_t remote_scn, esp_bd_addr_t peer_bd_addr)
107 {
108     btc_msg_t msg;
109     btc_spp_args_t arg;
110     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
111 
112     if (sec_mask != ESP_SPP_SEC_NONE &&
113         sec_mask != ESP_SPP_SEC_AUTHENTICATE &&
114         sec_mask != (ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)) {
115         LOG_WARN("Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHENTICATE"
116                  "or (ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT) only\n");
117     }
118 
119     msg.sig = BTC_SIG_API_CALL;
120     msg.pid = BTC_PID_SPP;
121     msg.act = BTC_SPP_ACT_CONNECT;
122 
123     arg.connect.sec_mask = sec_mask;
124     arg.connect.role = role;
125     arg.connect.remote_scn = remote_scn;
126     memcpy(arg.connect.peer_bd_addr, peer_bd_addr, ESP_BD_ADDR_LEN);
127 
128     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
129 }
130 
esp_spp_disconnect(uint32_t handle)131 esp_err_t esp_spp_disconnect(uint32_t handle)
132 {
133     btc_msg_t msg;
134     btc_spp_args_t arg;
135     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
136 
137     msg.sig = BTC_SIG_API_CALL;
138     msg.pid = BTC_PID_SPP;
139     msg.act = BTC_SPP_ACT_DISCONNECT;
140 
141     arg.disconnect.handle = handle;
142 
143     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
144 }
145 
esp_spp_start_srv(esp_spp_sec_t sec_mask,esp_spp_role_t role,uint8_t local_scn,const char * name)146 esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask,
147                             esp_spp_role_t role, uint8_t local_scn, const char *name)
148 {
149     btc_msg_t msg;
150     btc_spp_args_t arg;
151     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
152 
153     if (name == NULL || strlen(name) > ESP_SPP_SERVER_NAME_MAX) {
154         LOG_ERROR("Invalid server name!\n");
155         return ESP_ERR_INVALID_ARG;
156     }
157 
158     if (sec_mask != ESP_SPP_SEC_NONE &&
159         sec_mask != ESP_SPP_SEC_AUTHENTICATE &&
160         sec_mask != (ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT) &&
161         sec_mask != ESP_SPP_SEC_IN_16_DIGITS &&
162         sec_mask != (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE) &&
163         sec_mask != (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT)) {
164         LOG_WARN("Suggest to use ESP_SPP_SEC_NONE, ESP_SPP_SEC_AUTHENTICATE,"
165                  "(ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT),"
166                  "ESP_SPP_SEC_IN_16_DIGITS, (ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE), or"
167                  "(ESP_SPP_SEC_IN_16_DIGITS | ESP_SPP_SEC_AUTHENTICATE | ESP_SPP_SEC_ENCRYPT) only\n");
168     }
169 
170     msg.sig = BTC_SIG_API_CALL;
171     msg.pid = BTC_PID_SPP;
172     msg.act = BTC_SPP_ACT_START_SRV;
173 
174     arg.start_srv.sec_mask = sec_mask;
175     arg.start_srv.role = role;
176     arg.start_srv.local_scn = local_scn;
177     arg.start_srv.max_session = ESP_SPP_MAX_SESSION;
178     strcpy(arg.start_srv.name, name);
179 
180     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
181 }
182 
esp_spp_stop_srv(void)183 esp_err_t esp_spp_stop_srv(void)
184 {
185     btc_msg_t msg;
186     btc_spp_args_t arg;
187     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
188 
189     msg.sig = BTC_SIG_API_CALL;
190     msg.pid = BTC_PID_SPP;
191     msg.act = BTC_SPP_ACT_STOP_SRV;
192     arg.stop_srv.scn = BTC_SPP_INVALID_SCN;
193 
194     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
195 }
196 
esp_spp_stop_srv_scn(uint8_t scn)197 esp_err_t esp_spp_stop_srv_scn(uint8_t scn)
198 {
199     btc_msg_t msg;
200     btc_spp_args_t arg;
201     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
202 
203     if ((scn == 0) || (scn >= PORT_MAX_RFC_PORTS)) {
204         LOG_ERROR("Invalid SCN!\n");
205         return ESP_ERR_INVALID_ARG;
206     }
207 
208     msg.sig = BTC_SIG_API_CALL;
209     msg.pid = BTC_PID_SPP;
210     msg.act = BTC_SPP_ACT_STOP_SRV;
211     arg.stop_srv.scn = scn;
212 
213     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
214 }
215 
216 
esp_spp_write(uint32_t handle,int len,uint8_t * p_data)217 esp_err_t esp_spp_write(uint32_t handle, int len, uint8_t *p_data)
218 {
219     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
220 
221     if (len <= 0 || p_data == NULL) {
222         LOG_ERROR("Invalid data or len!\n");
223         return ESP_ERR_INVALID_ARG;
224     }
225 
226     return spp_send_data_to_btc(handle, len, p_data, ESP_SPP_MODE_CB);
227 }
228 
esp_spp_vfs_register(void)229 esp_err_t esp_spp_vfs_register(void)
230 {
231     btc_msg_t msg;
232     btc_spp_args_t arg;
233     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
234 
235     msg.sig = BTC_SIG_API_CALL;
236     msg.pid = BTC_PID_SPP;
237     msg.act = BTC_SPP_ACT_VFS_REGISTER;
238 
239     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
240 }
241 
esp_spp_vfs_unregister(void)242 esp_err_t esp_spp_vfs_unregister(void)
243 {
244     btc_msg_t msg;
245     btc_spp_args_t arg;
246     ESP_BLUEDROID_STATUS_CHECK(ESP_BLUEDROID_STATUS_ENABLED);
247 
248     msg.sig = BTC_SIG_API_CALL;
249     msg.pid = BTC_PID_SPP;
250     msg.act = BTC_SPP_ACT_VFS_UNREGISTER;
251 
252     return (btc_transfer_context(&msg, &arg, sizeof(btc_spp_args_t), NULL, NULL) == BT_STATUS_SUCCESS ? ESP_OK : ESP_FAIL);
253 }
254 
255 #endif ///defined BTC_SPP_INCLUDED && BTC_SPP_INCLUDED == TRUE
256