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