• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  ****************************************************************************************
3  *
4  * @file otas.c
5  *
6  * @brief Over The Air Server 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 "otas.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 Proprietary UUIDs. */
52 #define OTA_SERVICE_UUID       {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9,
53                                 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x01, 0x04, 0xED, 0xA6}
54 #define OTA_SERVICE_TX_UUID    {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9,
55                                 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x02, 0x04, 0xED, 0xA6}
56 #define OTA_SERVICE_RX_UUID    {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9,
57                                 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x03, 0x04, 0xED, 0xA6}
58 #define OTA_SERVICE_CTRL_UUID  {0x1B, 0xD7, 0x90, 0xEC, 0xE8, 0xB9,
59                                 0x75, 0x80, 0x0A, 0x46, 0x44, 0xD3, 0x04, 0x04, 0xED, 0xA6}
60 
61 /**@brief Macros for conversion of 128bit to 16bit UUID. */
62 #define ATT_128_PRIMARY_SERVICE     BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_PRIMARY_SERVICE)
63 #define ATT_128_CHARACTERISTIC      BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DECL_CHARACTERISTIC)
64 #define ATT_128_CLIENT_CHAR_CFG     BLE_ATT_16_TO_128_ARRAY(BLE_ATT_DESC_CLIENT_CHAR_CFG)
65 
66 /*
67  * ENUMERATIONS
68  ****************************************************************************************
69  */
70 /**@brief OTA Service Attributes Indexes. */
71 enum otas_attr_idx_tag {
72     OTAS_IDX_SVC,
73 
74     OTAS_IDX_TX_CHAR,
75     OTAS_IDX_TX_VAL,
76     OTAS_IDX_TX_CFG,
77     OTAS_IDX_RX_CHAR,
78     OTAS_IDX_RX_VAL,
79     OTAS_IDX_CTRL_CHAR,
80     OTAS_IDX_CTRL_VAL,
81 
82     OTAS_IDX_NB,
83 };
84 
85 /*
86  * STRUCT DEFINE
87  ****************************************************************************************
88  */
89 struct otas_env_t {
90     otas_init_t otas_init;
91     uint16_t     ntf_cfg[OTAS_CONNECTION_MAX];
92     uint16_t    start_hdl;
93 };
94 
95 
96 /*
97 * LOCAL FUNCTION DECLARATION
98 ****************************************************************************************
99 */
100 static sdk_err_t   otas_init(void);
101 static void        otas_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param);
102 static void        otas_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
103 static void        otas_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value);
104 static void        otas_gatts_cmpl_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind);
105 
106 /*
107  * LOCAL VARIABLE DEFINITIONS
108  ****************************************************************************************
109  */
110 static struct otas_env_t s_otas_env;
111 static uint16_t          s_char_mask = 0xff;
112 /**@brief Full OTAS Database Description - Used to add attributes into the database. */
113 static const attm_desc_128_t otas_att_db[OTAS_IDX_NB] = {
114     // OTA service
115     [OTAS_IDX_SVC] = {ATT_128_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
116 
117     // OTA TX Characteristic Declaration
118     [OTAS_IDX_TX_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
119     // OTA TX Characteristic Value
120     [OTAS_IDX_TX_VAL]  = {
121         OTA_SERVICE_TX_UUID,
122         NOTIFY_PERM_UNSEC,
123         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
124         OTAS_MAX_DATA_LEN
125     },
126 
127     // OTA TX Characteristic - Client Characteristic Configuration Descriptor
128     [OTAS_IDX_TX_CFG]  = {
129         ATT_128_CLIENT_CHAR_CFG,
130         READ_PERM_UNSEC| WRITE_REQ_PERM_UNSEC,
131         0,
132         0
133     },
134 
135     // OTA RX Characteristic Declaration
136     [OTAS_IDX_RX_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0 },
137 
138     // OTA RX Characteristic Value
139     [OTAS_IDX_RX_VAL]  = {
140         OTA_SERVICE_RX_UUID,
141         WRITE_CMD_PERM_UNSEC,
142         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
143         OTAS_MAX_DATA_LEN
144     },
145 
146     // OTA CTRL Characteristic Declaration
147     [OTAS_IDX_CTRL_CHAR] = {ATT_128_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
148 
149     // OTA CTRL Characteristic Value
150     [OTAS_IDX_CTRL_VAL]  = {
151         OTA_SERVICE_CTRL_UUID,
152         WRITE_CMD_PERM_UNSEC,
153         (ATT_VAL_LOC_USER | ATT_UUID_TYPE_SET(UUID_TYPE_128)),
154         sizeof(uint32_t)
155     },
156 };
157 
158 /**@brief OTA Server Task interface required by profile manager. */
159 static ble_prf_manager_cbs_t otas_tack_cbs = {
160     (prf_init_func_t) otas_init,
161     NULL,
162     NULL,
163 };
164 
165 /**@brief OTA Server Task Callbacks. */
166 static gatts_prf_cbs_t otas_cb_func = {
167     otas_read_att_cb,
168     otas_write_att_cb,
169     NULL,
170     otas_gatts_cmpl_cb,
171     otas_cccd_set_cb
172 };
173 
174 /**@brief OTA Server Information. */
175 static const prf_server_info_t otas_prf_info = {
176     .max_connection_nb = OTAS_CONNECTION_MAX,
177     .manager_cbs = &otas_tack_cbs,
178     .gatts_prf_cbs =&otas_cb_func
179 };
180 
181 /*
182  * LOCAL FUNCTION DEFINITIONS
183  ****************************************************************************************
184  */
185 /**
186  *****************************************************************************************
187  * @brief Initialize OTA service  create db in att
188  *
189  * @return Error code to know if profile initialization succeed or not.
190  *****************************************************************************************
191  */
192 static sdk_err_t otas_init(void)
193 {
194     // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
195     uint16_t          start_hdl       = PRF_INVALID_HANDLE;
196     const uint8_t     otas_svc_uuid[] = OTA_SERVICE_UUID;
197     sdk_err_t         error_code      = SDK_SUCCESS;
198     gatts_create_db_t gatts_db;
199 
200     error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
201     if (error_code < 0) {
202         return error_code;
203     }
204 
205     gatts_db.shdl                  = &start_hdl;
206     gatts_db.uuid                  = otas_svc_uuid;
207     gatts_db.attr_tab_cfg          = (uint8_t*)&s_char_mask;
208     gatts_db.max_nb_attr           = OTAS_IDX_NB;
209     gatts_db.srvc_perm             = SRVC_UUID_TYPE_SET(UUID_TYPE_128);
210     gatts_db.attr_tab_type         = SERVICE_TABLE_TYPE_128;
211     gatts_db.attr_tab.attr_tab_128 = otas_att_db;
212 
213     error_code = ble_gatts_srvc_db_create(&gatts_db);
214     if (SDK_SUCCESS == error_code) {
215         s_otas_env.start_hdl = *(gatts_db.shdl);
216     }
217 
218     return error_code;
219 }
220 
221 /**
222  *****************************************************************************************
223  * @brief Handles reception of the attribute info request message.
224  *
225  * @param[in] conn_idx: Connection index
226  * @param[in] p_param:  The parameters of the read request.
227  *****************************************************************************************
228  */
229 static void otas_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
230 {
231     gatts_read_cfm_t cfm;
232     uint8_t          handle     = p_param->handle;
233     uint8_t          tab_index  = 0;
234 
235     tab_index = prf_find_idx_by_handle(handle, s_otas_env.start_hdl, OTAS_IDX_NB, (uint8_t*)&s_char_mask);
236 
237     cfm.handle = handle;
238     cfm.status = BLE_SUCCESS;
239 
240     switch (tab_index) {
241         case OTAS_IDX_TX_CFG:
242             cfm.length = sizeof(uint16_t);
243             cfm.value = (uint8_t *)(&s_otas_env.ntf_cfg[conn_idx]);
244             break;
245 
246         default:
247             cfm.length = 0;
248             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
249             break;
250     }
251 
252     ble_gatts_read_cfm(conn_idx, &cfm);
253 }
254 
255 /**
256  *****************************************************************************************
257  * @brief Handles reception of the write request.
258  *
259  * @param[in] conn_idx: of connection index
260  * @param[in] p_param: Pointer to the parameters of the write request.
261  *****************************************************************************************
262  */
263 static void otas_write_att_cb(uint8_t conn_idx, const gatts_write_req_cb_t *p_param)
264 {
265     gatts_write_cfm_t cfm;
266     uint8_t           handle     = p_param->handle;
267     uint8_t           tab_index  = 0;
268     uint16_t          cccd_value = 0;
269     otas_evt_t        event;
270 
271     tab_index = prf_find_idx_by_handle(handle, s_otas_env.start_hdl, OTAS_IDX_NB, (uint8_t*)&s_char_mask);
272 
273     cfm.handle = handle;
274     cfm.status = BLE_SUCCESS;
275 
276     switch (tab_index) {
277         case OTAS_IDX_RX_VAL:
278             if (s_otas_env.otas_init.evt_handler != NULL) {
279                 event.conn_idx = conn_idx;
280                 event.evt_type = OTAS_EVT_RX_RECEIVE_DATA;
281                 event.p_data = (uint8_t*)p_param->value;
282                 event.length = p_param->length;
283 
284                 s_otas_env.otas_init.evt_handler(&event);
285             }
286 
287             break;
288 
289         case OTAS_IDX_TX_CFG:
290             cccd_value = le16toh(&p_param->value[0]);
291             if (s_otas_env.otas_init.evt_handler != NULL) {
292                 event.conn_idx = conn_idx;
293                 event.evt_type = (cccd_value == PRF_CLI_START_NTF) ?\
294                                  OTAS_EVT_TX_NOTIFICATION_ENABLED :
295                                  OTAS_EVT_TX_NOTIFICATION_DISABLED;
296                 s_otas_env.otas_init.evt_handler(&event);
297             }
298             s_otas_env.ntf_cfg[conn_idx] = cccd_value;
299             break;
300 
301         case OTAS_IDX_CTRL_VAL:
302             if (le32toh(&p_param->value[0]) == OTAS_CTRL_ENTER_DFU) {
303                 if (s_otas_env.otas_init.evt_handler != NULL) {
304                     event.conn_idx = conn_idx;
305                     event.evt_type = OTAS_EVT_DFU_MODE_ENTER;
306                     s_otas_env.otas_init.evt_handler(&event);
307                 }
308             }
309             break;
310 
311         default:
312             cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
313             break;
314     }
315 
316     ble_gatts_write_cfm(conn_idx, &cfm);
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  */
328 static void otas_cccd_set_cb(uint8_t conn_idx, uint16_t handle, uint16_t cccd_value)
329 {
330     uint8_t           tab_index  = 0;
331     otas_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, s_otas_env.start_hdl, OTAS_IDX_NB, (uint8_t*)&s_char_mask);
338 
339     switch (tab_index) {
340         case OTAS_IDX_TX_CFG:
341             if (s_otas_env.otas_init.evt_handler != NULL) {
342                 event.conn_idx = conn_idx;
343                 event.evt_type = (cccd_value == PRF_CLI_START_NTF) ?\
344                                  OTAS_EVT_TX_NOTIFICATION_ENABLED :
345                                  OTAS_EVT_TX_NOTIFICATION_DISABLED;
346                 s_otas_env.otas_init.evt_handler(&event);
347             }
348             s_otas_env.ntf_cfg[conn_idx] = cccd_value;
349             break;
350 
351         default:
352             break;
353     }
354 }
355 
356 /**
357  *****************************************************************************************
358  * @brief Handles reception of the complete event.
359  *
360  * @param[in] conn_idx: Connection index
361  * @param[in] p_param:  Pointer to the parameters of the complete event.
362  *
363  * @return If the event was consumed or not.
364  *****************************************************************************************
365  */
366 static void otas_gatts_cmpl_cb(uint8_t conn_idx, uint8_t status, const ble_gatts_ntf_ind_t *p_ntf_ind)
367 {
368     if (s_otas_env.otas_init.evt_handler != NULL) {
369         otas_evt_t event;
370 
371         event.conn_idx = conn_idx;
372         if (status == BLE_SUCCESS) {
373             if (p_ntf_ind->type == BLE_GATT_NOTIFICATION) {
374                 event.evt_type = OTAS_EVT_NOTIFY_COMPLETE;
375                 s_otas_env.otas_init.evt_handler(&event);
376             }
377         }
378     }
379 }
380 
381 /*
382  * GLOBAL FUNCTION DEFINITIONS
383  ****************************************************************************************
384  */
385 sdk_err_t otas_notify_tx_data(uint8_t conn_idx, uint8_t* p_data, uint16_t len)
386 {
387     sdk_err_t   error_code = SDK_ERR_NTF_DISABLED;
388     gatts_noti_ind_t send_cmd;
389 
390     if (s_otas_env.ntf_cfg[conn_idx] == PRF_CLI_START_NTF) {
391         // Fill in the parameter structure
392         send_cmd.type = BLE_GATT_NOTIFICATION;
393         send_cmd.handle = prf_find_handle_by_idx(OTAS_IDX_TX_VAL, s_otas_env.start_hdl, (uint8_t*)&s_char_mask);
394         // pack measured value in database
395         send_cmd.length = len;
396         send_cmd.value  = p_data;
397         // send notification to peer device
398         error_code = ble_gatts_noti_ind(conn_idx, &send_cmd);
399     }
400     return error_code;
401 }
402 
403 
404 sdk_err_t otas_service_init(otas_init_t *p_otas_init)
405 {
406     if (p_otas_init == NULL) {
407         return SDK_ERR_POINTER_NULL;
408     }
409 
410     s_otas_env.otas_init.evt_handler = p_otas_init->evt_handler;
411 
412     return ble_server_prf_add(&otas_prf_info);
413 }
414