• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  *****************************************************************************************
3  *
4  * @file ags.c
5  *
6  * @brief Alexa Gadget Profile 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 "ags.h"
43 #include "user_config.h"
44 #include "ble_prf_types.h"
45 #include "ble_prf_utils.h"
46 #include "utility.h"
47 #include "app_log.h"
48 #include "app_error.h"
49 #define MAX_PACKET_SIZE_OFFSET 3
50 #define INDEX_0 0
51 #define INDEX_1 1
52 #define INDEX_2 2
53 /*
54  * DEFINES
55  *****************************************************************************************
56  */
57 /**@brief The UUIDs of AGS characteristics.
58  *        The Tx channel transmits data from an Echo device to a gadget.
59  *        The Rx channel reansmits data from a gadget to an Echo device.
60  */
61 #define AGS_TX_UUID {0x76, 0x30, 0xF8, 0xDD, 0x90, 0xA3, 0x61, 0xAC, 0xA7, 0x43, 0x05, 0x30, 0x77, 0xB1, 0x4E, 0xF0}
62 #define AGS_RX_UUID {0x0B, 0x42, 0x82, 0x1F, 0x64, 0x72, 0x2F, 0x8A, 0xB4, 0x4B, 0x79, 0x18, 0x5B, 0xA0, 0xEE, 0x2B}
63 
64 /**@brief Macros for conversion of 128bit to 16bit UUID. */
65 #define ATT_128_PRIMARY_SERVICE BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
66 #define ATT_128_CHARACTERISTIC  BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
67 #define ATT_128_CLIENT_CHAR_CFG BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)
68 
69 
70 /*
71  * ENUMERATIONS
72  *****************************************************************************************
73  */
74 /**@brief Alexa Gadget Service Attributes Indexes. */
75 enum {
76     AGS_IDX_SVC,
77 
78     AGS_IDX_TX_CHAR,
79     AGS_IDX_TX_VAL,
80 
81     AGS_IDX_RX_CHAR,
82     AGS_IDX_RX_VAL,
83     AGS_IDX_RX_NTF_CFG,
84 
85     AGS_IDX_NB
86 };
87 
88 /*
89  * STRUCTURES
90  *****************************************************************************************
91  */
92 /**@brief Alexa Gadget Service environment variable. */
93 struct ags_env_t {
94     ags_init_t          ags_init;                               /**< Alexa Gadget Service initialization variables. */
95     uint16_t            start_hdl;                              /**< Alexa Gadget Service start handle. */
96     ags_stream_env_t    ags_stream_env[3];                      /**< The environment variable of gadget stream. */
97     uint16_t
98     rx_ntf_cfg[AGS_CONNECTION_MAX];         /**< The configuration of Rx Notification \
99                                             which is configured by the peer devices. */
100 };
101 
102 /**@brief Alexa Gadget stream payload. */
103 typedef struct {
104     uint8_t          p_data[USER_GADGET_TRANSACTION_BUF_SIZE];   /**< Gadget stream payload. */
105     uint16_t         length;                                     /**< Length of data. */
106     uint16_t         offset;                                     /**< Offset of data. */
107 } ags_stream_payload_t;
108 
109 /*
110  * LOCAL FUNCTION DECLARATION
111  *****************************************************************************************
112  */
113 static sdk_err_t ags_init(void);
114 static void      ags_read_att_cb(uint8_t  conn_idx, const gatts_read_req_cb_t  *p_param);
115 static void      ags_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
116 static void      ags_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
117 static void      ags_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
118 
119 static sdk_err_t ags_echo_rx_val_chunk(uint8_t conn_idx);
120 static sdk_err_t ags_stream_ack_send(uint8_t conn_idx, uint8_t stream_env_id, bool ack_flag);
121 static void      ags_echo_tx_val_decode(uint8_t conn_idx, const uint8_t *p_data, uint16_t length);
122 static void      ags_encode_ack(ags_ack_packet_t *p_ack_packet, uint8_t stream_id, uint8_t trxn_id, bool ack_flag);
123 static void      ags_encode_header(uint8_t *header, uint8_t stream_id, uint8_t trxn_type, uint8_t payload_length,
124                                    uint16_t trxn_length);
125 static void      ags_reset_stream(uint8_t stream_env_id, uint16_t total_length);
126 
127 /*
128  * LOCAL VARIABLE DEFINITIONS
129  *****************************************************************************************
130  */
131 static struct ags_env_t s_ags_env;
132 static uint8_t s_gadget_tx_buffer[244];
133 static uint8_t s_trxn_counter;
134 static uint8_t s_tx_sequ_num;
135 static ags_stream_payload_t s_ags_stream_payload;
136 
137 /**@brief Full AGS Database Description - Used to add attributes into the database. */
138 static const attm_desc_128_t ags_attr_tab[AGS_IDX_NB]  = {
139     // Alexa Gadget Service Declaration
140     [AGS_IDX_SVC]        = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
141 
142     // AGS Tx Characteristic - Declaration
143     [AGS_IDX_TX_CHAR]    = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
144     // AGS Tx Characteristic - Value
145     [AGS_IDX_TX_VAL]     = {
146         AGS_TX_UUID,
147         WRITE_REQ_PERM(UNAUTH) | WRITE_CMD_PERM(UNAUTH),
148         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
149         AGS_TX_VAL_LEN_MAX
150     },
151 
152     // AGS Tx Characteristic - Declaration
153     [AGS_IDX_RX_CHAR]    = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
154     // AGS Tx Characteristic - Value
155     [AGS_IDX_RX_VAL]     = {
156         AGS_RX_UUID,
157         NOTIFY_PERM(UNAUTH),
158         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
159         AGS_RX_VAL_LEN_MAX
160     },
161     // AGS Tx Characteristic - Client Characteristic Configuration Descriptor
162     [AGS_IDX_RX_NTF_CFG] = {
163         ATT_128_CLIENT_CHAR_CFG,
164         READ_PERM(UNAUTH) | WRITE_REQ_PERM(UNAUTH),
165         0,
166         0
167     },
168 };
169 
170 /**@brief AGS Task interface required by profile manager. */
171 static ble_prf_manager_cbs_t ags_task_cbs = {
172     (prf_init_func_t) ags_init,
173     NULL,
174     NULL,
175 };
176 
177 /**@brief AGS Task Callbacks. */
178 static gatts_prf_cbs_t ags_cb_func = {
179     ags_read_att_cb,
180     ags_write_att_cb,
181     NULL,
182     ags_ntf_ind_cb,
183     ags_cccd_set_cb
184 };
185 
186 /**@brief AGS Information. */
187 static const prf_server_info_t ags_prf_info = {
188     .max_connection_nb = AGS_CONNECTION_MAX,
189     .manager_cbs       = &ags_task_cbs,
190     .gatts_prf_cbs     = &ags_cb_func,
191 };
192 
193 /*
194  * LOCAL FUNCTION DEFINITIONS
195  *****************************************************************************************
196  */
197 /**
198  *****************************************************************************************
199  * @brief Initialize Alexa Gadget service  create db in att
200  *
201  * @return Error code to know if profile initialization succeed or not.
202  *****************************************************************************************
203  */
ags_init(void)204 static sdk_err_t ags_init(void)
205 {
206     // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
207     uint16_t          start_hdl       = PRF_INVALID_HANDLE;
208     const uint8_t     ags_svc_uuid[]  = {AGS_SERVICE_UUID};
209     sdk_err_t         error_code;
210     gatts_create_db_t gatts_db;
211 
212     error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
213     if (error_code < 0) {
214         return error_code;
215     }
216 
217     gatts_db.shdl                  = &start_hdl;
218     gatts_db.uuid                  = ags_svc_uuid;
219     gatts_db.attr_tab_cfg          = (uint8_t *)&(s_ags_env.ags_init.char_mask);
220     gatts_db.max_nb_attr           = AGS_IDX_NB;
221     gatts_db.srvc_perm             = SRVC_UUID_TYPE_SET(UUID_TYPE_128);
222     gatts_db.attr_tab_type         = SERVICE_TABLE_TYPE_128;
223     gatts_db.attr_tab.attr_tab_128 = ags_attr_tab;
224 
225     error_code = ble_gatts_srvc_db_create(&gatts_db);
226     if (SDK_SUCCESS == error_code) {
227         s_ags_env.start_hdl = *gatts_db.shdl;
228     }
229 
230     return error_code;
231 }
232 
233 /**
234  *****************************************************************************************
235  * @brief Handles reception of the attribute info request message.
236  *
237  * @param[in] conn_idx: Connection index
238  * @param[in] p_param:  The parameters of the read request.
239  *****************************************************************************************
240  */
ags_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)241 static void ags_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
242 {
243     gatts_read_cfm_t  cfm;
244     uint8_t           handle    = p_param->handle;
245     uint8_t           tab_index = prf_find_idx_by_handle(handle,
246                                                          s_ags_env.start_hdl,
247                                                          AGS_IDX_NB,
248                                                          (uint8_t *)&s_ags_env.ags_init.char_mask);
249     cfm.handle = handle;
250     cfm.status = BLE_SUCCESS;
251 
252     switch (tab_index) {
253         case AGS_IDX_RX_NTF_CFG:
254             cfm.length = sizeof(uint16_t);
255             cfm.value  = (uint8_t *)&s_ags_env.rx_ntf_cfg[conn_idx];
256             break;
257 
258         default:
259             cfm.length = 0;
260             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
261             break;
262     }
263 
264     ble_gatts_read_cfm(conn_idx, &cfm);
265 }
266 
267 /**
268  *****************************************************************************************
269  * @brief Handles reception of the write request.
270  *
271  * @param[in]: conn_idx: Connection index
272  * @param[in]: p_param:  The parameters of the write request.
273  *****************************************************************************************
274  */
ags_write_att_cb(uint8_t conn_idx,const gatts_write_req_cb_t * p_param)275 static void ags_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
276 {
277     uint16_t          handle      = p_param->handle;
278     uint16_t          tab_index   = 0;
279     uint16_t          cccd_value  = 0;
280     ags_evt_t         event;
281     gatts_write_cfm_t cfm;
282 
283     tab_index  = prf_find_idx_by_handle(handle,
284                                         s_ags_env.start_hdl,
285                                         AGS_IDX_NB,
286                                         (uint8_t *)&s_ags_env.ags_init.char_mask);
287     cfm.handle     = handle;
288     cfm.status     = BLE_SUCCESS;
289     event.evt_type = AGS_EVT_INVALID;
290     event.conn_idx = conn_idx;
291 
292     switch (tab_index) {
293         case AGS_IDX_TX_VAL:
294             ags_echo_tx_val_decode(conn_idx, p_param->value, p_param->length);
295             event.evt_type = AGS_EVT_ECHO_TX_DATA_RECEIVED;
296             break;
297 
298         case AGS_IDX_RX_NTF_CFG:
299             cccd_value     = le16toh(&p_param->value[0]);
300             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ?\
301                               AGS_EVT_ECHO_RX_NOTI_ENABLE :\
302                               AGS_EVT_ECHO_RX_NOTI_DISABLE);
303             s_ags_env.rx_ntf_cfg[conn_idx] = cccd_value;
304             break;
305 
306         default:
307             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
308             break;
309     }
310 
311     ble_gatts_write_cfm(conn_idx, &cfm);
312 
313     if (BLE_ATT_ERR_INVALID_HANDLE != cfm.status &&
314         AGS_EVT_INVALID != event.evt_type && s_ags_env.ags_init.evt_handler) {
315         s_ags_env.ags_init.evt_handler(&event);
316     }
317 }
318 
319 /**
320  *****************************************************************************************
321  * @brief Handles reception of the cccd recover request.
322  *
323  * @param[in]: conn_idx:   Connection index
324  * @param[in]: handle:     The handle of cccd attribute.
325  * @param[in]: cccd_value: The value of cccd attribute.
326  *****************************************************************************************
327  */
ags_cccd_set_cb(uint8_t conn_idx,uint16_t handle,uint16_t cccd_value)328 static void ags_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
329 {
330     uint16_t  tab_index  = 0;
331     ags_evt_t event;
332 
333     if (!prf_is_cccd_value_valid(cccd_value)) {
334         return;
335     }
336 
337     tab_index = prf_find_idx_by_handle(handle,
338                                        s_ags_env.start_hdl,
339                                        AGS_IDX_NB,
340                                        (uint8_t *)&s_ags_env.ags_init.char_mask);
341 
342     event.evt_type = AGS_EVT_INVALID;
343     event.conn_idx = conn_idx;
344 
345     switch (tab_index) {
346         case AGS_IDX_RX_NTF_CFG:
347             event.evt_type = ((PRF_CLI_START_NTF == cccd_value) ?\
348                               AGS_EVT_ECHO_RX_NOTI_ENABLE :\
349                               AGS_EVT_ECHO_RX_NOTI_DISABLE);
350             s_ags_env.rx_ntf_cfg[conn_idx] = cccd_value;
351             break;
352 
353         default:
354             break;
355     }
356 
357     if (AGS_EVT_INVALID != event.evt_type && s_ags_env.ags_init.evt_handler) {
358         s_ags_env.ags_init.evt_handler(&event);
359     }
360 }
361 
362 /**
363  *****************************************************************************************
364  * @brief Handles reception of the complete event.
365  *
366  * @param[in] conn_idx: Connection index.
367  * @param[in] status:   The status of the complete event.
368  * @param[in] p_ntf_id: Pointer to the parameters of the complete event.
369  *****************************************************************************************
370  */
ags_ntf_ind_cb(uint8_t conn_idx,uint8_t status,const ble_gatts_ntf_ind_t * p_ntf_ind)371 static void ags_ntf_ind_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
372 {
373     if (s_ags_env.ags_init.evt_handler && SDK_SUCCESS == status) {
374         if (BLE_GATT_NOTIFICATION == p_ntf_ind->type) {
375             ags_echo_rx_val_chunk(conn_idx);
376         }
377     }
378 }
379 
380 /**
381  *****************************************************************************************
382  * @brief Reset the gadget stream environment variables.
383  *
384  * @param[in] stream_env_id: The environment ID of gadget stream which is active.
385  * @param[in] total_length:  The total payload length of this stream.
386  *****************************************************************************************
387  */
ags_reset_stream(uint8_t stream_env_id,uint16_t total_length)388 static inline void ags_reset_stream(uint8_t stream_env_id, uint16_t total_length)
389 {
390     s_ags_env.ags_stream_env[stream_env_id].is_active       = true;
391     s_ags_env.ags_stream_env[stream_env_id].ack_flag        = false;
392     s_ags_env.ags_stream_env[stream_env_id].trxn_id         = 0;
393     s_ags_env.ags_stream_env[stream_env_id].total_length    = total_length;
394     s_ags_env.ags_stream_env[stream_env_id].received_length = 0;
395 }
396 
397 /**
398  *****************************************************************************************
399  * @brief Decode the data from Echo device.
400  *
401  * @param[in] conn_idx:   Connection index.
402  * @param[in] p_data:     Pointer to the data which to be decoded.
403  * @param[in] length:     Data length.
404  *****************************************************************************************
405  */
ags_echo_tx_val_decode(uint8_t conn_idx,const uint8_t * p_data,uint16_t length)406 static void ags_echo_tx_val_decode(uint8_t conn_idx, const uint8_t *p_data, uint16_t length)
407 {
408     sdk_err_t error_code;
409     uint8_t   stream_env_id;
410     uint16_t  payload_length;
411     uint16_t  payload_offset;
412 
413     if (p_data == NULL || (length < sizeof(ags_header_base_t))) {
414         APP_LOG_DEBUG("Unexcepted length: %d", length);
415         return;
416     }
417 
418     ags_header_base_t *p_header_base = (ags_header_base_t *)p_data;
419 
420     for (uint8_t i = 0; i < ARRAY_SIZE(s_ags_env.ags_stream_env); i++) {
421         if (s_ags_env.ags_stream_env[i].stream_id == p_header_base->stream_id) {
422             stream_env_id = i;
423         }
424     }
425 
426     if (s_ags_env.ags_stream_env[stream_env_id].is_active) {
427         if (p_header_base->length_ext) {
428             ags_header_subs_ext_t *p_header_subs_ext = (ags_header_subs_ext_t *)p_data;
429 
430             payload_length = be16toh(p_header_subs_ext->payload_length);
431             payload_offset = sizeof(ags_header_subs_ext_t);
432         } else {
433             ags_header_subs_t *p_header_subs = (ags_header_subs_t *)p_data;
434 
435             payload_length = p_header_subs->payload_length;
436             payload_offset = sizeof(ags_header_subs_t);
437         }
438     } else {
439         uint16_t total_length;
440 
441         if (p_header_base->length_ext) {
442             ags_header_first_ext_t *p_header_first_ext = (ags_header_first_ext_t *)p_data;
443 
444             total_length = be16toh(p_header_first_ext->total_trxn_length);
445             payload_length = be16toh(p_header_first_ext->payload_length);
446             payload_offset = sizeof(ags_header_first_ext_t);
447         } else {
448             ags_header_first_t *p_header_first = (ags_header_first_t *)p_data;
449 
450             total_length = be16toh(p_header_first->total_trxn_length);
451             payload_length = p_header_first->payload_length;
452             payload_offset = sizeof(ags_header_first_t);
453         }
454 
455         ags_reset_stream(stream_env_id, total_length);
456     }
457 
458     if (p_header_base->ack_flag) {
459         s_ags_env.ags_stream_env[stream_env_id].ack_flag = p_header_base->ack_flag;
460         s_ags_env.ags_stream_env[stream_env_id].trxn_id  = p_header_base->trxn_id;
461     }
462 
463     s_ags_env.ags_stream_env[stream_env_id].received_length += payload_length;
464 
465     if (s_ags_env.ags_stream_env[stream_env_id].received_length == \
466         s_ags_env.ags_stream_env[stream_env_id].total_length) {
467         s_ags_env.ags_stream_env[stream_env_id].is_active = 0;
468     } else if (s_ags_env.ags_stream_env[stream_env_id].received_length >
469                s_ags_env.ags_stream_env[stream_env_id].total_length) {
470         s_ags_env.ags_stream_env[stream_env_id].is_active = 0;
471         APP_LOG_DEBUG("Stream Overrun: %d %d.", s_ags_env.ags_stream_env[stream_env_id].received_length,
472                       s_ags_env.ags_stream_env[stream_env_id].total_length);
473     }
474 
475     bool ack_flag = false;
476 
477     switch (p_header_base->stream_id) {
478         case AGS_CONTROL_STREAM_ID:
479             ack_flag = s_ags_env.ags_init.ags_control_stream_cb(conn_idx, &((uint8_t *)p_data)[payload_offset], \
480                 payload_length, s_ags_env.ags_stream_env[stream_env_id].is_active);
481             break;
482 
483         case AGS_ALEXA_STREAM_ID:
484             ack_flag = s_ags_env.ags_init.ags_alexa_stream_cb(conn_idx, &((uint8_t *)p_data)[payload_offset], \
485                 payload_length, s_ags_env.ags_stream_env[stream_env_id].is_active);
486             break;
487 
488         default:
489             APP_LOG_DEBUG("Unknown Stream ID: %d", p_header_base->stream_id);
490             break;
491     }
492 
493     error_code = ags_stream_ack_send(conn_idx, stream_env_id, ack_flag);
494     APP_ERROR_CHECK(error_code);
495     return;
496 }
497 
498 /**
499  *****************************************************************************************
500  * @brief Send ACK packet.
501  *        If the Echo device request the ACK packet, the gadget must send the Echo device
502  *        an ACK packet in response to the last packet of the transaction.
503  * @param[in] conn_idx:       Connection index.
504  * @param[in] stream_env_id:  The environment ID of gadget stream which is active.
505  * @param[in] ack_flag:       The ack flag of the ACK packet.
506  *
507  * @return the result of sending ACK packet.
508  *****************************************************************************************
509  */
ags_stream_ack_send(uint8_t conn_idx,uint8_t stream_env_id,bool ack_flag)510 static sdk_err_t ags_stream_ack_send(uint8_t conn_idx, uint8_t stream_env_id, bool ack_flag)
511 {
512     sdk_err_t error_code = SDK_SUCCESS;
513     ags_evt_t ags_evt;
514 
515     if (!s_ags_env.ags_stream_env[stream_env_id].is_active && (s_ags_env.ags_stream_env[stream_env_id].ack_flag)) {
516         ags_ack_packet_t ack_packet;
517 
518         ags_encode_ack(&ack_packet, s_ags_env.ags_stream_env[stream_env_id].stream_id, \
519                        s_ags_env.ags_stream_env[stream_env_id].trxn_id, ack_flag);
520 
521         gatts_noti_ind_t ags_rx_val_noti;
522 
523         ags_rx_val_noti.type   = BLE_GATT_NOTIFICATION;
524         ags_rx_val_noti.handle = prf_find_handle_by_idx(AGS_IDX_RX_VAL,
525                                                         s_ags_env.start_hdl,
526                                                         (uint8_t *)&s_ags_env.ags_init.char_mask);
527         ags_rx_val_noti.length = sizeof(ack_packet);
528         ags_rx_val_noti.value  = (uint8_t *)&ack_packet;
529 
530         error_code = ble_gatts_noti_ind(conn_idx, &ags_rx_val_noti);
531 
532         ags_evt.evt_type = AGS_EVT_ECHO_RX_DATA_SENT;
533         ags_evt.conn_idx = conn_idx;
534         ags_evt.p_data   = (uint8_t *)&ack_packet;
535         ags_evt.length   = sizeof(ack_packet);
536         s_ags_env.ags_init.evt_handler(&ags_evt);
537     }
538     return error_code;
539 }
540 
541 /**
542  *****************************************************************************************
543  * @brief Send the data to RX Characteristic chunk by chunk.
544  *
545  * @param[in] conn_idx:   Connection index.
546  *
547  * @return the result of sending operation.
548  *****************************************************************************************
549  */
ags_echo_rx_val_chunk(uint8_t conn_idx)550 static sdk_err_t ags_echo_rx_val_chunk(uint8_t conn_idx)
551 {
552     sdk_err_t error_code;
553     ags_evt_t ags_evt;
554 
555     if (s_ags_stream_payload.length) {
556         uint8_t          header_size = sizeof(ags_header_subs_t);
557         uint16_t         max_packet_size;
558         uint16_t         payload_size;
559         uint8_t          stream_id;
560         uint8_t          trxn_type;
561         gatts_noti_ind_t ags_rx_val_noti;
562 
563         ble_gatt_mtu_get(conn_idx, &max_packet_size);
564         max_packet_size -= MAX_PACKET_SIZE_OFFSET;
565 
566         if (max_packet_size < (header_size + s_ags_stream_payload.length)) {
567             payload_size = max_packet_size - header_size;
568             s_ags_stream_payload.length -= payload_size;
569         } else {
570             payload_size = s_ags_stream_payload.length;
571             s_ags_stream_payload.length = 0;
572         }
573 
574         // Get stream ID from prededing transmit.
575         stream_id = ((ags_header_base_t *)s_gadget_tx_buffer)->stream_id;
576         if (s_ags_stream_payload.length) {
577             trxn_type = AGS_TRANSACTION_TYPE_CONT;
578         } else {
579             trxn_type = AGS_TRANSACTION_TYPE_LAST;
580         }
581 
582         ags_encode_header(&s_gadget_tx_buffer[0], stream_id, trxn_type, payload_size, 0);
583         error_code = memcpy_s(&s_gadget_tx_buffer[header_size], payload_size,
584                               &s_ags_stream_payload.p_data[s_ags_stream_payload.offset], payload_size);
585         s_ags_stream_payload.offset += payload_size;
586 
587         ags_rx_val_noti.type   = BLE_GATT_NOTIFICATION;
588         ags_rx_val_noti.handle = prf_find_handle_by_idx(AGS_IDX_RX_VAL,
589                                                         s_ags_env.start_hdl,
590                                                         (uint8_t *)&s_ags_env.ags_init.char_mask);
591         ags_rx_val_noti.length = header_size + payload_size;
592         ags_rx_val_noti.value  = s_gadget_tx_buffer;
593 
594         error_code = ble_gatts_noti_ind(conn_idx, &ags_rx_val_noti);
595     } else {
596         error_code = memset_s(&s_ags_stream_payload, sizeof(ags_stream_payload_t), 0, sizeof(ags_stream_payload_t));
597         if (error_code < 0) {
598             return error_code;
599         }
600         s_ags_stream_payload.length = 0;
601         s_ags_stream_payload.offset = 0;
602 
603         ags_evt.evt_type = AGS_EVT_ECHO_RX_DATA_SENT;
604         ags_evt.conn_idx = conn_idx;
605         ags_evt.p_data   = s_ags_stream_payload.p_data;
606         s_ags_env.ags_init.evt_handler(&ags_evt);
607 
608         error_code = SDK_SUCCESS;
609     }
610     return error_code;
611 }
612 
613 /**
614  *****************************************************************************************
615  * @brief Enocde the ACK packet header.
616  *
617  * @param[in] p_ack_packet: Pointer to the ACK packet.
618  * @param[in] stream_id:    The stream ID of the packet that requested the acknowledgement.
619  * @param[in] trxn_id:      The tracsaction ID of the packet that requested the acknowledgement.
620  * @param[in] ack_flag:     The ack flag of the ACK packet.
621  *****************************************************************************************
622  */
ags_encode_ack(ags_ack_packet_t * p_ack_packet,uint8_t stream_id,uint8_t trxn_id,bool ack_flag)623 static void ags_encode_ack(ags_ack_packet_t *p_ack_packet, uint8_t stream_id, uint8_t trxn_id, bool ack_flag)
624 {
625     p_ack_packet->header_base.stream_id  = stream_id;
626     p_ack_packet->header_base.trxn_id    = trxn_id;
627     p_ack_packet->header_base.sequ_num   = 0;  // This can be any value.
628     p_ack_packet->header_base.trxn_type  = AGS_TRANSACTION_TYPE_CTRL;
629     p_ack_packet->header_base.ack_flag   = ack_flag ? AGS_ACK_ACK : AGS_ACK_NACK;
630     p_ack_packet->header_base.length_ext = AGS_LEN_EXT_NO_EXT;
631     p_ack_packet->reserved_1             = AGS_HEADER_ACK_RES_1;
632     p_ack_packet->payload_length         = AGS_HEADER_ACK_PAYLOAD_LEN;
633     p_ack_packet->reserved_2             = AGS_HEADER_ACK_RES_2;
634     p_ack_packet->result_code            = ack_flag ? AGS_RES_CODE_SUCCESS : AGS_RES_CODE_UNSUPPORTED;
635 }
636 
637 /**
638  *****************************************************************************************
639  * @brief Enocde the header of other type packet.
640  *
641  * @param[in] p_header:       Pointer to the header.
642  * @param[in] stream_id:      The stream ID, @ref ags_header_stream_id_t.
643  * @param[in] trxn_type:      The transaction type, @ref ags_header_trxn_type_t.
644  * @param[in] payload_length: Payload length.
645  * @param[in] trxn_length:    Total transaction length.
646  *****************************************************************************************
647  */
ags_encode_header(uint8_t * header,uint8_t stream_id,uint8_t trxn_type,uint8_t payload_length,uint16_t trxn_length)648 static void ags_encode_header(uint8_t *header, uint8_t stream_id, uint8_t trxn_type, uint8_t payload_length,
649                               uint16_t trxn_length)
650 {
651     ags_header_base_t *p_header_base = header;
652 
653     p_header_base->stream_id  = stream_id;
654     p_header_base->sequ_num   = s_tx_sequ_num++;
655     p_header_base->trxn_type  = trxn_type;
656     p_header_base->ack_flag   = AGS_ACK_NACK;
657     p_header_base->length_ext = AGS_LEN_EXT_NO_EXT;
658 
659     if (AGS_TRANSACTION_TYPE_FIRST == trxn_type) {
660         ags_header_first_t *p_header_first = header;
661 
662         s_trxn_counter++;
663         p_header_base->trxn_id         = s_trxn_counter;
664         p_header_first->reserved       = AGS_HEADER_FIRST_RES;
665         p_header_first->payload_length = payload_length;
666 
667         htobe16(&(p_header_first->total_trxn_length), trxn_length);
668     } else {
669         ags_header_subs_t *p_header_subs = header;
670 
671         p_header_base->trxn_id = s_trxn_counter;
672         p_header_subs->payload_length = payload_length;
673     }
674 }
675 
676 /*
677  * GLOBAL FUNCTION DEFINITIONS
678  ****************************************************************************************
679  */
ags_stream_send(uint8_t conn_idx,uint8_t stream_id,uint8_t * p_data,uint16_t length)680 sdk_err_t ags_stream_send(uint8_t conn_idx, uint8_t stream_id, uint8_t *p_data, uint16_t length)
681 {
682     sdk_err_t        error_code = SDK_ERR_NTF_DISABLED;
683     uint16_t         max_packet_size;
684     uint16_t         payload_size;
685     uint16_t         header_size;
686     gatts_noti_ind_t ags_rx_val_noti;
687 
688     error_code = memset_s(&s_ags_stream_payload, sizeof(s_ags_stream_payload),
689                           0, sizeof(s_ags_stream_payload));
690     if (error_code < 0) {
691         return error_code;
692     }
693     s_tx_sequ_num = 0;
694     s_ags_stream_payload.length = 0;
695 
696     ble_gatt_mtu_get(conn_idx, &max_packet_size);
697     max_packet_size -= MAX_PACKET_SIZE_OFFSET;
698 
699     error_code = memcpy_s(s_ags_stream_payload.p_data, length, (uint8_t *)p_data, length);
700     if (error_code < 0) {
701         return error_code;
702     }
703 
704     header_size = sizeof(ags_header_first_t);
705 
706     if (max_packet_size < (header_size + length)) {
707         s_ags_stream_payload.length = header_size + length - max_packet_size;
708     } else {
709         s_ags_stream_payload.length = 0;
710     }
711 
712     payload_size = length - s_ags_stream_payload.length;
713     s_ags_stream_payload.offset = payload_size;
714 
715     ags_encode_header(&s_gadget_tx_buffer[0], stream_id, AGS_TRANSACTION_TYPE_FIRST, payload_size, length);
716     error_code = memcpy_s(&s_gadget_tx_buffer[header_size], payload_size, p_data, payload_size);
717     if (error_code < 0) {
718         return error_code;
719     }
720 
721     ags_rx_val_noti.type   = BLE_GATT_NOTIFICATION;
722     ags_rx_val_noti.handle = prf_find_handle_by_idx(AGS_IDX_RX_VAL,
723                                                     s_ags_env.start_hdl,
724                                                     (uint8_t *)&s_ags_env.ags_init.char_mask);
725     ags_rx_val_noti.length = header_size + payload_size;
726     ags_rx_val_noti.value  = s_gadget_tx_buffer;
727 
728     error_code = ble_gatts_noti_ind(conn_idx, &ags_rx_val_noti);
729     return error_code;
730 }
731 
ags_non_stream_send(uint8_t conn_idx,uint8_t * p_data,uint16_t length)732 sdk_err_t ags_non_stream_send(uint8_t conn_idx, uint8_t *p_data, uint16_t length)
733 {
734     sdk_err_t        error_code = SDK_ERR_NTF_DISABLED;
735     gatts_noti_ind_t ags_rx_val_noti;
736     ags_evt_t        ags_evt;
737 
738     ags_rx_val_noti.type   = BLE_GATT_NOTIFICATION;
739     ags_rx_val_noti.handle = prf_find_handle_by_idx(AGS_IDX_RX_VAL,
740                                                     s_ags_env.start_hdl,
741                                                     (uint8_t *)&s_ags_env.ags_init.char_mask);
742     ags_rx_val_noti.length = length;
743     ags_rx_val_noti.value  = (uint8_t *)p_data;
744 
745     error_code = ble_gatts_noti_ind(conn_idx, &ags_rx_val_noti);
746 
747     ags_evt.evt_type = AGS_EVT_ECHO_RX_DATA_SENT;
748     ags_evt.conn_idx = conn_idx;
749     ags_evt.p_data   = (uint8_t *)p_data;
750     ags_evt.length   = length;
751     s_ags_env.ags_init.evt_handler(&ags_evt);
752 
753     return error_code;
754 }
755 
ags_service_init(ags_init_t * p_ags_init)756 sdk_err_t ags_service_init(ags_init_t *p_ags_init)
757 {
758     sdk_err_t  ret;
759     if (p_ags_init == NULL) {
760         return SDK_ERR_POINTER_NULL;
761     }
762 
763     s_ags_env.ags_stream_env[INDEX_0].stream_id = AGS_CONTROL_STREAM_ID;
764     s_ags_env.ags_stream_env[INDEX_0].is_active = false;
765     s_ags_env.ags_stream_env[INDEX_1].stream_id = AGS_ALEXA_STREAM_ID;
766     s_ags_env.ags_stream_env[INDEX_1].is_active = false;
767     s_ags_env.ags_stream_env[INDEX_2].stream_id = AGS_OTA_STREAM_ID;
768     s_ags_env.ags_stream_env[INDEX_2].is_active = false;
769 
770     ret = memcpy_s(&s_ags_env.ags_init, sizeof(ags_init_t), p_ags_init, sizeof(ags_init_t));
771     if (ret < 0) {
772         return ret;
773     }
774     return ble_server_prf_add(&ags_prf_info);
775 }
776