• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file gus_c.c
5  *
6  * @brief Goodix UART Client 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  * INCLUDE FILES
39  *****************************************************************************************
40  */
41 #include "gus_c.h"
42 #define ATTR_VALUE_LEN 2
43 #define UUID_LEN_16 16
44 
45 /*
46  * STRUCT DEFINE
47  *****************************************************************************************
48  */
49 /**@brief Goodix UART Service Client environment variable. */
50 struct gus_c_env_t {
51     gus_c_handles_t      handles;            /**< Handles of GUS characteristics which will be got for peer. */
52     gus_c_evt_handler_t  evt_handler;        /**< Handler of GUS client event  */
53     uint8_t              prf_id;             /**< GUS Client profile id. */
54 };
55 
56 /*
57  * LOCAL FUNCTION DECLARATION
58  *****************************************************************************************
59  */
60 static void gus_c_att_write_cb(uint8_t conn_idx, uint8_t status, uint16_t handle);
61 static void gus_c_att_ntf_ind_cb(uint8_t conn_idx, const ble_gattc_ntf_ind_t *p_ntf_ind);
62 static void gus_c_srvc_browse_cb(uint8_t conn_idx, uint8_t status, const ble_gattc_browse_srvc_t *p_browse_srvc);
63 
64 /*
65  * LOCAL VARIABLE DEFINITIONS
66  *****************************************************************************************
67  */
68 static struct gus_c_env_t s_gus_c_env;       /**< GUS Client environment variable. */
69 static uint8_t            s_gus_uuid[16]                = GUS_SVC_UUID;
70 static uint8_t            s_gus_rx_char_uuid[16]        = GUS_RX_CHAR_UUID;
71 static uint8_t            s_gus_tx_char_uuid[16]        = GUS_TX_CHAR_UUID;
72 static uint8_t            s_gus_flow_ctrl_char_uuid[16] = GUS_FLOW_CTRL_UUID;
73 
74 /**@brief GUS Client interface required by profile manager. */
75 static ble_prf_manager_cbs_t gus_c_mgr_cbs = {
76     NULL,
77     NULL,
78     NULL
79 };
80 
81 /**@brief GUS GATT Client Callbacks. */
82 static gattc_prf_cbs_t gus_c_gattc_cbs = {
83     NULL,
84     NULL,
85     NULL,
86     NULL,
87     NULL,
88     gus_c_att_write_cb,
89     gus_c_att_ntf_ind_cb,
90     gus_c_srvc_browse_cb,
91     NULL,
92 };
93 
94 /**@brief GUS Client Information. */
95 static const prf_client_info_t gus_c_prf_info = {
96     .max_connection_nb = GUS_C_CONNECTION_MAX,
97     .manager_cbs       = &gus_c_mgr_cbs,
98     .gattc_prf_cbs     = &gus_c_gattc_cbs
99 };
100 
101 /*
102  * LOCAL FUNCTION DEFINITIONS
103  *****************************************************************************************
104  */
105 /**
106  *****************************************************************************************
107  * @brief Excute GUS Service Client event handler.
108  *
109  * @param[in] p_evt: Pointer to GUS Service Client event structure.
110  *****************************************************************************************
111  */
gus_c_evt_handler_excute(gus_c_evt_t * p_evt)112 static void gus_c_evt_handler_excute(gus_c_evt_t *p_evt)
113 {
114     if (s_gus_c_env.evt_handler != NULL && GUS_C_EVT_INVALID != p_evt->evt_type) {
115         s_gus_c_env.evt_handler(p_evt);
116     }
117 }
118 
119 /**
120  *****************************************************************************************
121  * @brief This callback function will be called when receiving read response.
122  *
123  * @param[in] conn_idx:   The connection index.
124  * @param[in] status:     The status of GATTC operation.
125  * @param[in] handle:     The handle of attribute.
126  *****************************************************************************************
127  */
gus_c_att_write_cb(uint8_t conn_idx,uint8_t status,uint16_t handle)128 static void gus_c_att_write_cb(uint8_t conn_idx, uint8_t status, uint16_t handle)
129 {
130     gus_c_evt_t gus_c_evt;
131 
132     gus_c_evt.conn_idx = conn_idx;
133     gus_c_evt.evt_type = GUS_C_EVT_INVALID;
134 
135     if (handle == s_gus_c_env.handles.gus_tx_cccd_handle) {
136         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
137                              GUS_C_EVT_TX_NTF_SET_SUCCESS : \
138                              GUS_C_EVT_WRITE_OP_ERR;
139     } else if (handle == s_gus_c_env.handles.gus_flow_ctrl_cccd_handle) {
140         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
141                              GUS_C_EVT_FLOW_CTRL_NTF_SET_SUCCESS : \
142                              GUS_C_EVT_WRITE_OP_ERR;
143     } else if (handle == s_gus_c_env.handles.gus_rx_handle) {
144         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
145                              GUS_C_EVT_TX_CPLT : \
146                              GUS_C_EVT_WRITE_OP_ERR;
147     } else if (handle == s_gus_c_env.handles.gus_flow_ctrl_handle) {
148         gus_c_evt.evt_type = (BLE_SUCCESS == status) ? \
149                              GUS_C_EVT_RX_FLOW_UPDATE_CPLT : \
150                              GUS_C_EVT_WRITE_OP_ERR;
151     }
152 
153     gus_c_evt_handler_excute(&gus_c_evt);
154 }
155 
156 /**
157  *****************************************************************************************
158  * @brief This callback function will be called when receiving notification or indication.
159  *
160  * @param[in] conn_idx:  The connection index.
161  * @param[in] status:    The status of GATTC operation.
162  * @param[in] p_ntf_ind: The information of notification or indication.
163  *****************************************************************************************
164  */
gus_c_att_ntf_ind_cb(uint8_t conn_idx,const ble_gattc_ntf_ind_t * p_ntf_ind)165 static void gus_c_att_ntf_ind_cb(uint8_t conn_idx, const ble_gattc_ntf_ind_t *p_ntf_ind)
166 {
167     gus_c_evt_t gus_c_evt;
168 
169     gus_c_evt.conn_idx = conn_idx;
170     gus_c_evt.evt_type = GUS_C_EVT_INVALID;
171 
172     if (p_ntf_ind->handle == s_gus_c_env.handles.gus_flow_ctrl_handle) {
173         if (FLOW_ON == p_ntf_ind->p_value[0]) {
174             gus_c_evt.evt_type = GUS_C_EVT_TX_FLOW_ON;
175         } else if (FLOW_OFF == p_ntf_ind->p_value[0]) {
176             gus_c_evt.evt_type = GUS_C_EVT_TX_FLOW_OFF;
177         }
178     } else if (p_ntf_ind->handle == s_gus_c_env.handles.gus_tx_handle) {
179         gus_c_evt.evt_type = GUS_C_EVT_PEER_DATA_RECEIVE;
180         gus_c_evt.p_data   = p_ntf_ind->p_value;
181         gus_c_evt.length   = p_ntf_ind->length;
182     }
183 
184     gus_c_evt_handler_excute(&gus_c_evt);
185 }
186 
187 /**
188  *****************************************************************************************
189  * @brief This callback function will be called when receiving browse service indication.
190  *
191  * @param[in] conn_idx:      The connection index.
192  * @param[in] status:        The status of GATTC operation.
193  * @param[in] p_browse_srvc: The information of service browse.
194  *****************************************************************************************
195  */
gus_c_srvc_browse_cb(uint8_t conn_idx,uint8_t status,const ble_gattc_browse_srvc_t * p_browse_srvc)196 static void gus_c_srvc_browse_cb(uint8_t conn_idx, uint8_t status, const ble_gattc_browse_srvc_t *p_browse_srvc)
197 {
198     gus_c_evt_t  gus_c_evt;
199     uint16_t     handle_disc;
200 
201     gus_c_evt.conn_idx = conn_idx;
202     gus_c_evt.evt_type = GUS_C_EVT_DISCOVERY_FAIL;
203 
204     if (BLE_GATT_ERR_BROWSE_NO_ANY_MORE == status) {
205         return;
206     }
207 
208     if (status != BLE_SUCCESS) {
209         return;
210     }
211 
212     if (p_browse_srvc->uuid_len == UUID_LEN_16 && memcmp(p_browse_srvc->uuid, s_gus_uuid, UUID_LEN_16) == 0) {
213         s_gus_c_env.handles.gus_srvc_start_handle = p_browse_srvc->start_hdl;
214         s_gus_c_env.handles.gus_srvc_end_handle   = p_browse_srvc->end_hdl;
215 
216         for (uint32_t i = 0; i < (p_browse_srvc->end_hdl - p_browse_srvc->start_hdl); i++) {
217             handle_disc = p_browse_srvc->start_hdl + i + 1;
218 
219             if (BLE_GATTC_BROWSE_ATTR_VAL == p_browse_srvc->info[i].attr_type) {
220                 if (memcmp(p_browse_srvc->info[i].attr.uuid, s_gus_rx_char_uuid, UUID_LEN_16) == 0) {
221                     s_gus_c_env.handles.gus_rx_handle = handle_disc;
222                 } else if (memcmp(p_browse_srvc->info[i].attr.uuid, s_gus_tx_char_uuid, UUID_LEN_16) == 0) {
223                     s_gus_c_env.handles.gus_tx_handle      = handle_disc;
224                     s_gus_c_env.handles.gus_tx_cccd_handle = handle_disc + 1;
225                 } else if (memcmp(p_browse_srvc->info[i].attr.uuid, s_gus_flow_ctrl_char_uuid, UUID_LEN_16) == 0) {
226                     s_gus_c_env.handles.gus_flow_ctrl_handle      = handle_disc;
227                     s_gus_c_env.handles.gus_flow_ctrl_cccd_handle = handle_disc + 1;
228                 }
229             }
230 
231             if (p_browse_srvc->info[i].attr_type == BLE_GATTC_BROWSE_NONE) {
232                 break;
233             }
234         }
235 
236         gus_c_evt.evt_type = GUS_C_EVT_DISCOVERY_COMPLETE;
237     }
238 
239     gus_c_evt_handler_excute(&gus_c_evt);
240 }
241 
242 /*
243  * GLOBAL FUNCTION DEFINITIONS
244  *****************************************************************************************
245  */
gus_client_init(gus_c_evt_handler_t evt_handler)246 sdk_err_t gus_client_init(gus_c_evt_handler_t evt_handler)
247 {
248     sdk_err_t ret;
249     if (evt_handler == NULL) {
250         return SDK_ERR_POINTER_NULL;
251     }
252 
253     ret = memset_s(&s_gus_c_env, sizeof(s_gus_c_env), 0, sizeof(s_gus_c_env));
254     if (ret < 0) {
255         return ret;
256     }
257     s_gus_c_env.evt_handler = evt_handler;
258 
259     return ble_client_prf_add(&gus_c_prf_info, &s_gus_c_env.prf_id);
260 }
261 
gus_c_disc_srvc_start(uint8_t conn_idx)262 sdk_err_t gus_c_disc_srvc_start(uint8_t conn_idx)
263 {
264     const ble_uuid_t gus_uuid = {
265         .uuid_len = 16,
266         .uuid     = s_gus_uuid,
267     };
268 
269     return ble_gattc_prf_services_browse(s_gus_c_env.prf_id, conn_idx, &gus_uuid);
270 }
271 
gus_c_tx_notify_set(uint8_t conn_idx,bool is_enable)272 sdk_err_t gus_c_tx_notify_set(uint8_t conn_idx, bool is_enable)
273 {
274     gattc_write_attr_value_t write_attr_value;
275     uint16_t ntf_value = is_enable ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND;
276 
277     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_tx_cccd_handle) {
278         return SDK_ERR_INVALID_HANDLE;
279     }
280 
281     write_attr_value.handle  = s_gus_c_env.handles.gus_tx_cccd_handle;
282     write_attr_value.offset  = 0;
283     write_attr_value.length  = ATTR_VALUE_LEN;
284     write_attr_value.p_value = (uint8_t *)&ntf_value;
285 
286     return ble_gattc_prf_write(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
287 }
288 
gus_c_flow_ctrl_notify_set(uint8_t conn_idx,bool is_enable)289 sdk_err_t gus_c_flow_ctrl_notify_set(uint8_t conn_idx, bool is_enable)
290 {
291     gattc_write_attr_value_t write_attr_value;
292     uint16_t ntf_value = is_enable ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND;
293 
294     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_flow_ctrl_cccd_handle) {
295         return SDK_ERR_INVALID_HANDLE;
296     }
297 
298     write_attr_value.handle  = s_gus_c_env.handles.gus_flow_ctrl_cccd_handle;
299     write_attr_value.offset  = 0;
300     write_attr_value.length  = ATTR_VALUE_LEN;
301     write_attr_value.p_value = (uint8_t *)&ntf_value;
302 
303     return ble_gattc_prf_write(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
304 }
305 
gus_c_tx_data_send(uint8_t conn_idx,uint8_t * p_data,uint16_t length)306 sdk_err_t gus_c_tx_data_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
307 {
308     gattc_write_no_resp_t write_attr_value;
309 
310     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_rx_handle) {
311         return SDK_ERR_INVALID_HANDLE;
312     }
313 
314     if (p_data == NULL) {
315         return SDK_ERR_POINTER_NULL;
316     }
317 
318     write_attr_value.signed_write  = false;
319     write_attr_value.handle        = s_gus_c_env.handles.gus_rx_handle;
320     write_attr_value.length        = length;
321     write_attr_value.p_value       = p_data;
322 
323     return ble_gattc_prf_write_no_resp(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
324 }
325 
gus_c_rx_flow_ctrl_set(uint8_t conn_idx,uint8_t flow_ctrl)326 sdk_err_t gus_c_rx_flow_ctrl_set(uint8_t conn_idx, uint8_t flow_ctrl)
327 {
328     gattc_write_attr_value_t write_attr_value;
329 
330     if (BLE_ATT_INVALID_HDL == s_gus_c_env.handles.gus_flow_ctrl_handle) {
331         return SDK_ERR_INVALID_HANDLE;
332     }
333 
334     write_attr_value.handle  = s_gus_c_env.handles.gus_flow_ctrl_handle;
335     write_attr_value.offset  = 0;
336     write_attr_value.length  = 1;
337     write_attr_value.p_value = &flow_ctrl;
338 
339     return ble_gattc_prf_write(s_gus_c_env.prf_id, conn_idx, &write_attr_value);
340 }
341