• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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