1 /**
2 *****************************************************************************************
3 *
4 * @file gus.c
5 *
6 * @brief Goodix UART Service Implementation.
7 *
8 *****************************************************************************************
9 * @attention
10 #####Copyright (c) 2019 GOODIX
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 * Neither the name of GOODIX nor the names of its contributors may be used
21 to endorse or promote products derived from this software without
22 specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
28 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 POSSIBILITY OF SUCH DAMAGE.
35 *****************************************************************************************
36 */
37
38 /*
39 * INCLUDE FILES
40 ******************************************************************************************
41 */
42 #include "gus.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46
47 /*
48 * DEFINES
49 *****************************************************************************************
50 */
51 /**@brief The UUIDs of GUS characteristics. */
52 #define GUS_SERVER_TX_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, \
53 0x46, 0x44, 0xD3, 0x02, 0x02, 0xED, 0xA6}
54 #define GUS_SERVER_RX_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, \
55 0x46, 0x44, 0xD3, 0x03, 0x02, 0xED, 0xA6}
56 #define GUS_FLOW_CTRL_UUID {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9, 0x75, 0x80, 0x0A, \
57 0x46, 0x44, 0xD3, 0x04, 0x02, 0xED, 0xA6}
58
59 /**@brief Macros for conversion of 128bit to 16bit UUID. */
60 #define ATT_128_PRIMARY_SERVICE BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
61 #define ATT_128_CHARACTERISTIC BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
62 #define ATT_128_CLIENT_CHAR_CFG BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)
63
64 /*
65 * ENUMERATIONS
66 *****************************************************************************************
67 */
68 /**@brief Goodix UART Service Attributes Indexes. */
69 enum gus_attr_idx_t {
70 GUS_IDX_SVC,
71
72 GUS_IDX_TX_CHAR,
73 GUS_IDX_TX_VAL,
74 GUS_IDX_TX_CFG,
75
76 GUS_IDX_RX_CHAR,
77 GUS_IDX_RX_VAL,
78
79 GUS_IDX_FLOW_CTRL_CHAR,
80 GUS_IDX_FLOW_CTRL_VAL,
81 GUS_IDX_FLOW_CTRL_CFG,
82
83 GUS_IDX_NB,
84 };
85
86 /*
87 * STRUCTURES
88 *****************************************************************************************
89 */
90 /**@brief Goodix UART Service environment variable. */
91 struct gus_env_t {
92 gus_init_t gus_init; /**< Goodix UART Service initialization variables. */
93 uint16_t start_hdl; /**< Start handle of services */
94 uint16_t tx_ntf_cfg[GUS_CONNECTION_MAX]; /**< TX Characteristic Notification configuration of the peers. */
95 uint16_t
96 flow_ctrl_ntf_cfg[GUS_CONNECTION_MAX]; /**< Flow Control Characteristic Notification configuration of the peers. */
97 };
98
99 /*
100 * LOCAL FUNCTION DECLARATION
101 *****************************************************************************************
102 */
103 static sdk_err_t gus_init(void);
104 static void gus_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
105 static void gus_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
106 static void gus_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
107 static void gus_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
108
109 /*
110 * LOCAL VARIABLE DEFINITIONS
111 *****************************************************************************************
112 */
113 static struct gus_env_t s_gus_env;
114 static const uint16_t s_char_mask = 0xFFFF;
115
116 /**@brief Full GUS Database Description which is used to add attributes into the ATT database. */
117 static const attm_desc_128_t gus_att_db[GUS_IDX_NB] = {
118 // GUS service
119 [GUS_IDX_SVC] = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
120
121 // GUS TX Characteristic Declaration
122 [GUS_IDX_TX_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
123 // GUS TX Characteristic Value
124 [GUS_IDX_TX_VAL] = {
125 GUS_SERVER_TX_UUID,
126 NOTIFY_PERM_UNSEC,
127 (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
128 GUS_MAX_DATA_LEN
129 },
130 // GUS TX Characteristic - Client Characteristic Configuration Descriptor
131 [GUS_IDX_TX_CFG] = {
132 ATT_128_CLIENT_CHAR_CFG,
133 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
134 0,
135 0
136 },
137
138 // GUS RX Characteristic Declaration
139 [GUS_IDX_RX_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
140 // GUS RX Characteristic Value
141 [GUS_IDX_RX_VAL] = {
142 GUS_SERVER_RX_UUID,
143 WRITE_REQ_PERM_UNSEC | WRITE_CMD_PERM_UNSEC,
144 (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
145 GUS_MAX_DATA_LEN
146 },
147
148 // GUS FLOW_CTRL Characteristic Declaration
149 [GUS_IDX_FLOW_CTRL_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
150 // GUS FLOW_CTRL Characteristic Value
151 [GUS_IDX_FLOW_CTRL_VAL] = {
152 GUS_FLOW_CTRL_UUID,
153 NOTIFY_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
154 (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
155 GUS_MAX_DATA_LEN
156 },
157 // GUS FLOW_CTRL Characteristic - Client Characteristic Configuration Descriptor
158 [GUS_IDX_FLOW_CTRL_CFG] = {
159 ATT_128_CLIENT_CHAR_CFG,
160 READ_PERM_UNSEC | WRITE_REQ_PERM_UNSEC,
161 0,
162 0
163 },
164 };
165
166 /**@brief GUS Service interface required by profile manager. */
167 static ble_prf_manager_cbs_t gus_mgr_cbs = {
168 (prf_init_func_t)gus_init,
169 NULL,
170 NULL,
171 };
172
173 /**@brief GUS GATT Server Callbacks. */
174 static gatts_prf_cbs_t gus_gatts_cbs = {
175 gus_read_att_cb,
176 gus_write_att_cb,
177 NULL,
178 gus_ntf_ind_cb,
179 gus_cccd_set_cb
180 };
181
182 /**@brief GUS Server Information. */
183 static const prf_server_info_t gus_prf_info = {
184 .max_connection_nb = GUS_CONNECTION_MAX,
185 .manager_cbs = &gus_mgr_cbs,
186 .gatts_prf_cbs = &gus_gatts_cbs
187 };
188
189 /*
190 * LOCAL FUNCTION DEFINITIONS
191 *****************************************************************************************
192 */
193 /**
194 *****************************************************************************************
195 * @brief Initialize GUS and create DB in ATT.
196 *
197 * @return Error code to know if service initialization succeed or not.
198 *****************************************************************************************
199 */
gus_init(void)200 static sdk_err_t gus_init(void)
201 {
202 const uint8_t gus_svc_uuid[] = {GUS_SERVICE_UUID};
203 uint16_t start_hdl = PRF_INVALID_HANDLE;
204 sdk_err_t error_code;
205 gatts_create_db_t gatts_db;
206
207 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
208 if (error_code < 0) {
209 return error_code;
210 }
211
212 gatts_db.shdl = &start_hdl;
213 gatts_db.uuid = gus_svc_uuid;
214 gatts_db.attr_tab_cfg = (uint8_t *)&s_char_mask;
215 gatts_db.max_nb_attr = GUS_IDX_NB;
216 gatts_db.srvc_perm = SRVC_UUID_TYPE_SET(UUID_TYPE_128);
217 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_128;
218 gatts_db.attr_tab.attr_tab_128 = gus_att_db;
219
220 error_code = ble_gatts_srvc_db_create(&gatts_db);
221 if (SDK_SUCCESS == error_code) {
222 s_gus_env.start_hdl = *gatts_db.shdl;
223 }
224
225 return error_code;
226 }
227
228 /**
229 *****************************************************************************************
230 * @brief Handles reception of the attribute info request message.
231 *
232 * @param[in] conn_idx: Index of the connection.
233 * @param[in] p_param: Pointer to the parameters of the read request.
234 *****************************************************************************************
235 */
gus_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)236 static void gus_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
237 {
238 gatts_read_cfm_t cfm;
239 uint16_t handle = p_param->handle;
240 uint8_t tab_index = 0;
241
242 tab_index = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
243 cfm.handle = handle;
244 cfm.status = BLE_SUCCESS;
245
246 switch (tab_index) {
247 case GUS_IDX_TX_CFG:
248 cfm.length = sizeof(uint16_t);
249 cfm.value = (uint8_t *)&s_gus_env.tx_ntf_cfg[conn_idx];
250 cfm.status = BLE_SUCCESS;
251 break;
252
253 case GUS_IDX_FLOW_CTRL_CFG:
254 cfm.length = sizeof(uint16_t);
255 cfm.value = (uint8_t *)&s_gus_env.flow_ctrl_ntf_cfg[conn_idx];
256 cfm.status = BLE_SUCCESS;
257 break;
258
259 default:
260 cfm.length = 0;
261 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
262 break;
263 }
264
265 ble_gatts_read_cfm(conn_idx, &cfm);
266 }
267
268 /**
269 *****************************************************************************************
270 * @brief Handles reception of the write request.
271 *
272 * @param[in] conn_idx: Index of the connection.
273 * @param[in] p_param: Point to the parameters of the write request.
274 *****************************************************************************************
275 */
gus_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)276 static void gus_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
277 {
278 uint8_t handle = p_param->handle;
279 uint8_t tab_index = 0;
280 uint16_t flow_ctrl_state;
281 uint16_t cccd_value;
282 gus_evt_t event;
283 gatts_write_cfm_t cfm;
284
285 tab_index = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
286 event.conn_idx = conn_idx;
287 cfm.handle = handle;
288 cfm.status = BLE_SUCCESS;
289
290 switch (tab_index) {
291 case GUS_IDX_RX_VAL:
292 event.evt_type = GUS_EVT_RX_DATA_RECEIVED;
293 event.p_data = (uint8_t *)p_param->value;
294 event.length = p_param->length;
295 break;
296
297 case GUS_IDX_TX_CFG:
298 cccd_value = le16toh(&p_param->value[0]);
299 event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_TX_PORT_OPENED : GUS_EVT_TX_PORT_CLOSED;
300 s_gus_env.tx_ntf_cfg[conn_idx] = cccd_value;
301 break;
302
303 case GUS_IDX_FLOW_CTRL_CFG:
304 cccd_value = le16toh(&p_param->value[0]);
305 event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_FLOW_CTRL_ENABLE : GUS_EVT_FLOW_CTRL_DISABLE;
306 s_gus_env.flow_ctrl_ntf_cfg[conn_idx] = cccd_value;
307 break;
308
309 case GUS_IDX_FLOW_CTRL_VAL:
310 flow_ctrl_state = p_param->value[0];
311
312 if (FLOW_OFF == flow_ctrl_state) {
313 event.evt_type = GUS_EVT_TX_FLOW_OFF;
314 } else if (FLOW_ON == flow_ctrl_state) {
315 event.evt_type = GUS_EVT_TX_FLOW_ON;
316 }
317 break;
318
319 default:
320 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
321 break;
322 }
323
324 if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status && GUS_EVT_INVALID != event.evt_type &&
325 s_gus_env.gus_init.evt_handler) {
326 s_gus_env.gus_init.evt_handler(&event);
327 }
328
329 ble_gatts_write_cfm(conn_idx, &cfm);
330 }
331
332 /**
333 *****************************************************************************************
334 * @brief Handles reception of the cccd recover request.
335 *
336 * @param[in]: conn_idx: Connection index
337 * @param[in]: handle: The handle of cccd attribute.
338 * @param[in]: cccd_value: The value of cccd attribute.
339 *****************************************************************************************
340 */
gus_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)341 static void gus_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
342 {
343 uint8_t tab_index = 0;
344 gus_evt_t event;
345
346 if (!prf_is_cccd_value_valid(cccd_value)) {
347 return;
348 }
349
350 tab_index = prf_find_idx_by_handle(handle, s_gus_env.start_hdl, GUS_IDX_NB, (uint8_t *)&s_char_mask);
351 event.conn_idx = conn_idx;
352 event.evt_type = GUS_EVT_INVALID;
353
354 switch (tab_index) {
355 case GUS_IDX_TX_CFG:
356 event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_TX_PORT_OPENED : GUS_EVT_TX_PORT_CLOSED;
357 s_gus_env.tx_ntf_cfg[conn_idx] = cccd_value;
358 break;
359
360 case GUS_IDX_FLOW_CTRL_CFG:
361 event.evt_type = (PRF_CLI_START_NTF == cccd_value) ? GUS_EVT_FLOW_CTRL_ENABLE : GUS_EVT_FLOW_CTRL_DISABLE;
362 s_gus_env.flow_ctrl_ntf_cfg[conn_idx] = cccd_value;
363 break;
364
365 default:
366 break;
367 }
368
369 if (GUS_EVT_INVALID != event.evt_type && s_gus_env.gus_init.evt_handler) {
370 s_gus_env.gus_init.evt_handler(&event);
371 }
372 }
373
374 /**
375 *****************************************************************************************
376 * @brief Handles reception of the complete event.
377 *
378 * @param[in] conn_idx: Connection index.
379 * @param[in] status: The status of GATTC operation.
380 * @param[in] p_ntf_ind: Pointer to the parameters of the complete event.
381 *****************************************************************************************
382 */
gus_ntf_ind_cb(uint8_t conn_idx,uint8_t status,const ble_gatts_ntf_ind_t * p_ntf_ind)383 static void gus_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
384 {
385 if (s_gus_env.gus_init.evt_handler != NULL) {
386 gus_evt_t event;
387 event.conn_idx = conn_idx;
388
389 if (BLE_SUCCESS == status && BLE_GATT_NOTIFICATION == p_ntf_ind->type) {
390 event.evt_type = GUS_EVT_TX_DATA_SENT;
391 s_gus_env.gus_init.evt_handler(&event);
392 }
393 }
394 }
395
396 /*
397 * GLOBAL FUNCTION DEFINITIONS
398 *****************************************************************************************
399 */
gus_tx_data_send(uint8_t conn_idx,uint8_t * p_data,uint16_t length)400 sdk_err_t gus_tx_data_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
401 {
402 sdk_err_t error_code = SDK_ERR_NTF_DISABLED;
403 gatts_noti_ind_t send_cmd;
404
405 if (PRF_CLI_START_NTF == s_gus_env.tx_ntf_cfg[conn_idx]) {
406 // Fill in the parameter structure
407 send_cmd.type = BLE_GATT_NOTIFICATION;
408 send_cmd.handle = prf_find_handle_by_idx(GUS_IDX_TX_VAL, s_gus_env.start_hdl, (uint8_t *)&s_char_mask);
409
410 // Pack measured value in database
411 send_cmd.length = length;
412 send_cmd.value = p_data;
413
414 // Send notification to peer device
415 error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);
416 }
417
418 return error_code;
419 }
420
gus_rx_flow_ctrl_set(uint8_t conn_idx,uint8_t flow_ctrl)421 sdk_err_t gus_rx_flow_ctrl_set(uint8_t conn_idx, uint8_t flow_ctrl)
422 {
423 sdk_err_t error_code = BLE_SUCCESS;
424 gatts_noti_ind_t send_cmd;
425
426 if (PRF_CLI_START_NTF == s_gus_env.flow_ctrl_ntf_cfg[conn_idx]) {
427 // Fill in the parameter structure
428 send_cmd.type = BLE_GATT_NOTIFICATION;
429 send_cmd.handle = prf_find_handle_by_idx(GUS_IDX_FLOW_CTRL_VAL, s_gus_env.start_hdl, (uint8_t *)&s_char_mask);
430
431 // Pack measured value in database
432 send_cmd.length = 1;
433 send_cmd.value = &flow_ctrl;
434
435 // Send notification to peer device
436 error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);
437 }
438
439 return error_code;
440 }
441
gus_service_init(gus_init_t * p_gus_init)442 sdk_err_t gus_service_init(gus_init_t *p_gus_init)
443 {
444 sdk_err_t ret;
445 if (p_gus_init == NULL) {
446 return SDK_ERR_POINTER_NULL;
447 }
448
449 ret = memcpy_s(&s_gus_env.gus_init, sizeof(gus_init_t), p_gus_init, sizeof(gus_init_t));
450 if (ret < 0) {
451 return ret;
452 }
453
454 return ble_server_prf_add(&gus_prf_info);
455 }
456