1 /**
2 *****************************************************************************************
3 *
4 * @file dis.h
5 *
6 * @brief Device Information 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 "dis.h"
43 #include "ble_prf_types.h"
44 #include "ble_prf_utils.h"
45 #include "utility.h"
46 #define INDEX_0 0
47 #define INDEX_1 1
48 #define INDEX_2 2
49 #define INDEX_3 3
50 #define INDEX_4 4
51 #define INDEX_5 5
52 #define INDEX_6 6
53 /*
54 * ENUMERATIONS
55 *****************************************************************************************
56 */
57 /**@brief Device Information Service Attributes database index list. */
58 enum dis_attr_idx_t {
59 DIS_IDX_SVC,
60
61 DIS_IDX_SYSTEM_ID_CHAR,
62 DIS_IDX_SYSTEM_ID_VAL,
63
64 DIS_IDX_MODEL_NB_STR_CHAR,
65 DIS_IDX_MODEL_NB_STR_VAL,
66
67 DIS_IDX_SERIAL_NB_STR_CHAR,
68 DIS_IDX_SERIAL_NB_STR_VAL,
69
70 DIS_IDX_HARD_REV_STR_CHAR,
71 DIS_IDX_HARD_REV_STR_VAL,
72
73 DIS_IDX_FIRM_REV_STR_CHAR,
74 DIS_IDX_FIRM_REV_STR_VAL,
75
76 DIS_IDX_SW_REV_STR_CHAR,
77 DIS_IDX_SW_REV_STR_VAL,
78
79 DIS_IDX_MANUFACTURER_NAME_CHAR,
80 DIS_IDX_MANUFACTURER_NAME_VAL,
81
82 DIS_IDX_IEEE_CHAR,
83 DIS_IDX_IEEE_VAL,
84
85 DIS_IDX_PNP_ID_CHAR,
86 DIS_IDX_PNP_ID_VAL,
87
88 DIS_IDX_NB,
89 };
90
91 /*
92 * STRUCTURES
93 *****************************************************************************************
94 */
95 /**@brief Device Information Service environment variable. */
96 struct dis_env_t {
97 dis_init_t dis_init; /**< Device Information Service initialization variables. */
98 uint16_t start_hdl; /**< Device Information Service start handle. */
99 };
100
101 /*
102 * LOCAL FUNCTION DECLARATION
103 *****************************************************************************************
104 */
105 static sdk_err_t dis_init(void);
106 static void dis_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param);
107
108 /*
109 * LOCAL VARIABLE DEFINITIONS
110 *****************************************************************************************
111 */
112 static struct dis_env_t s_dis_env;
113
114 /**@brief Full DIS Database Description which is used to add attributes into the ATT database. */
115 static const attm_desc_t dis_attr_tab[DIS_IDX_NB] = {
116 // Device Information Service Declaration
117 [DIS_IDX_SVC] = {BLE_ATT_DECL_PRIMARY_SERVICE, READ_PERM_UNSEC, 0, 0},
118
119 // System ID Characteristic Declaration
120 [DIS_IDX_SYSTEM_ID_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
121 // System ID Characteristic Value
122 [DIS_IDX_SYSTEM_ID_VAL] = {BLE_ATT_CHAR_SYS_ID, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_SYS_ID_LEN},
123
124 // Model Number String Characteristic Declaration
125 [DIS_IDX_MODEL_NB_STR_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
126 // Model Number String Characteristic Value
127 [DIS_IDX_MODEL_NB_STR_VAL] = {BLE_ATT_CHAR_MODEL_NB, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_VAL_MAX_LEN},
128
129 // Serial Number String Characteristic Declaration
130 [DIS_IDX_SERIAL_NB_STR_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
131 // Serial Number String Characteristic Value
132 [DIS_IDX_SERIAL_NB_STR_VAL] = {BLE_ATT_CHAR_SERIAL_NB, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_VAL_MAX_LEN},
133
134 // Firmware Revision String Characteristic Declaration
135 [DIS_IDX_FIRM_REV_STR_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
136 // Firmware Revision String Characteristic Value
137 [DIS_IDX_FIRM_REV_STR_VAL] = {BLE_ATT_CHAR_FW_REV, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_VAL_MAX_LEN},
138
139 // Hardware Revision String Characteristic Declaration
140 [DIS_IDX_HARD_REV_STR_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
141 // Hardware Revision String Characteristic Value
142 [DIS_IDX_HARD_REV_STR_VAL] = {BLE_ATT_CHAR_HW_REV, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_VAL_MAX_LEN},
143
144 // Software Revision String Characteristic Declaration
145 [DIS_IDX_SW_REV_STR_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
146 // Software Revision String Characteristic Value
147 [DIS_IDX_SW_REV_STR_VAL] = {BLE_ATT_CHAR_SW_REV, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_VAL_MAX_LEN},
148
149 // Manufacturer Name Characteristic Declaration
150 [DIS_IDX_MANUFACTURER_NAME_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
151 // Manufacturer Name Characteristic Value
152 [DIS_IDX_MANUFACTURER_NAME_VAL] = {BLE_ATT_CHAR_MANUF_NAME, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_VAL_MAX_LEN},
153
154 // IEEE 11073-20601 Regulatory Certification Data List Characteristic Declaration
155 [DIS_IDX_IEEE_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
156 // IEEE 11073-20601 Regulatory Certification Data List Characteristic Value
157 [DIS_IDX_IEEE_VAL] = {BLE_ATT_CHAR_IEEE_CERTIF, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_SYS_ID_LEN},
158
159 // PnP ID Characteristic Declaration
160 [DIS_IDX_PNP_ID_CHAR] = {BLE_ATT_DECL_CHARACTERISTIC, READ_PERM_UNSEC, 0, 0},
161 // PnP ID Characteristic Value
162 [DIS_IDX_PNP_ID_VAL] = {BLE_ATT_CHAR_PNP_ID, READ_PERM_UNSEC, ATT_VAL_LOC_USER, DIS_PNP_ID_LEN},
163 };
164
165 /**@brief Device Information Service interface required by profile manager. */
166 static ble_prf_manager_cbs_t dis_mgr_cbs = {
167 (prf_init_func_t)dis_init,
168 NULL,
169 NULL
170 };
171
172 /**@brief Device Information GATT Server Callbacks. */
173 static gatts_prf_cbs_t dis_gatts_cbs = {
174 dis_read_att_cb,
175 NULL,
176 NULL,
177 NULL
178 };
179
180 /**@brief Device Information Service Information. */
181 static const prf_server_info_t dis_prf_info = {
182 .max_connection_nb = DIS_CONNECTION_MAX,
183 .manager_cbs = &dis_mgr_cbs,
184 .gatts_prf_cbs = &dis_gatts_cbs
185 };
186
187 /*
188 * LOCAL FUNCTION DEFINITIONS
189 *****************************************************************************************
190 */
191 /**
192 *****************************************************************************************
193 * @brief Initialize device information service and create DB in ATT.
194 *
195 * @return Error code to know if service initialization succeed or not.
196 *****************************************************************************************
197 */
dis_init(void)198 static sdk_err_t dis_init(void)
199 {
200 // The start hanlde must be set with PRF_INVALID_HANDLE to be allocated automatically by BLE Stack.
201 uint16_t start_hdl = PRF_INVALID_HANDLE;
202 const uint8_t dis_svc_uuid[] = BLE_ATT_16_TO_16_ARRAY(BLE_ATT_SVC_DEVICE_INFO);
203 sdk_err_t error_code = SDK_SUCCESS;
204 gatts_create_db_t gatts_db;
205
206 error_code = memset_s(&gatts_db, sizeof(gatts_db), 0, sizeof(gatts_db));
207 if (error_code < 0) {
208 return error_code;
209 }
210
211 gatts_db.shdl = &start_hdl;
212 gatts_db.uuid = dis_svc_uuid;
213 gatts_db.attr_tab_cfg = (uint8_t *)&s_dis_env.dis_init.char_mask;
214 gatts_db.max_nb_attr = DIS_IDX_NB;
215 gatts_db.srvc_perm = 0;
216 gatts_db.attr_tab_type = SERVICE_TABLE_TYPE_16;
217 gatts_db.attr_tab.attr_tab_16 = dis_attr_tab;
218
219 error_code = ble_gatts_srvc_db_create(&gatts_db);
220 if (SDK_SUCCESS == error_code) {
221 s_dis_env.start_hdl = *gatts_db.shdl;
222 }
223
224 return error_code;
225 }
226
227 /**
228 *****************************************************************************************
229 * @brief Handles reception of the attribute info request message.
230 *
231 * @param[in] conn_idx: Connection index
232 * @param[in] p_param: Pointer to the parameters of the read request.
233 *****************************************************************************************
234 */
dis_read_att_cb(uint8_t conn_idx,const gatts_read_req_cb_t * p_param)235 static void dis_read_att_cb(uint8_t conn_idx, const gatts_read_req_cb_t *p_param)
236 {
237 gatts_read_cfm_t cfm;
238 uint16_t handle = p_param->handle;
239 uint8_t tab_index = prf_find_idx_by_handle(handle,
240 s_dis_env.start_hdl,
241 DIS_IDX_NB,
242 (uint8_t *)&s_dis_env.dis_init.char_mask);
243 cfm.handle = handle;
244 cfm.status = BLE_SUCCESS;
245
246 uint8_t buf[DIS_PNP_ID_LEN];
247
248 switch (tab_index) {
249 case DIS_IDX_SYSTEM_ID_VAL:
250 cfm.length = DIS_SYS_ID_LEN;
251 cfm.value = (uint8_t *)s_dis_env.dis_init.p_sys_id;
252 break;
253
254 case DIS_IDX_MODEL_NB_STR_VAL:
255 cfm.length = s_dis_env.dis_init.model_num_str.length;
256 cfm.value = (uint8_t *)s_dis_env.dis_init.model_num_str.p_str;
257 break;
258
259 case DIS_IDX_SERIAL_NB_STR_VAL:
260 cfm.length = s_dis_env.dis_init.serial_num_str.length;
261 cfm.value = (uint8_t *)s_dis_env.dis_init.serial_num_str.p_str;
262 break;
263
264 case DIS_IDX_FIRM_REV_STR_VAL:
265 cfm.length = s_dis_env.dis_init.fw_rev_str.length;
266 cfm.value = (uint8_t *)s_dis_env.dis_init.fw_rev_str.p_str;
267 break;
268
269 case DIS_IDX_HARD_REV_STR_VAL:
270 cfm.length = s_dis_env.dis_init.hw_rev_str.length;
271 cfm.value = (uint8_t *)s_dis_env.dis_init.hw_rev_str.p_str;
272 break;
273
274 case DIS_IDX_SW_REV_STR_VAL:
275 cfm.length = s_dis_env.dis_init.sw_rev_str.length;
276 cfm.value = (uint8_t *)s_dis_env.dis_init.sw_rev_str.p_str;
277 break;
278
279 case DIS_IDX_MANUFACTURER_NAME_VAL:
280 cfm.length = s_dis_env.dis_init.manufact_name_str.length;
281 cfm.value = (uint8_t *)s_dis_env.dis_init.manufact_name_str.p_str;
282 break;
283
284 case DIS_IDX_IEEE_VAL:
285 cfm.length = s_dis_env.dis_init.reg_cert_data_list.list_len;
286 cfm.value = (uint8_t *)s_dis_env.dis_init.reg_cert_data_list.p_list;
287 break;
288
289 case DIS_IDX_PNP_ID_VAL: {
290 buf[INDEX_0] = s_dis_env.dis_init.p_pnp_id->vendor_id_source;
291 buf[INDEX_1] = LO_U16(s_dis_env.dis_init.p_pnp_id->vendor_id);
292 buf[INDEX_2] = HI_U16(s_dis_env.dis_init.p_pnp_id->vendor_id);
293 buf[INDEX_3] = LO_U16(s_dis_env.dis_init.p_pnp_id->product_id);
294 buf[INDEX_4] = HI_U16(s_dis_env.dis_init.p_pnp_id->product_id);
295 buf[INDEX_5] = LO_U16(s_dis_env.dis_init.p_pnp_id->product_version);
296 buf[INDEX_6] = HI_U16(s_dis_env.dis_init.p_pnp_id->product_version);
297 cfm.length = DIS_PNP_ID_LEN;
298 cfm.value = buf;
299 }
300 break;
301
302 default:
303 cfm.length = 0;
304 cfm.status = BLE_ATT_ERR_INVALID_HANDLE;
305 break;
306 }
307
308 ble_gatts_read_cfm(conn_idx, &cfm);
309 }
310
311 /*
312 * GLOBAL FUNCTION DEFINITIONS
313 *****************************************************************************************
314 */
dis_service_init(dis_init_t * p_dis_init)315 sdk_err_t dis_service_init(dis_init_t *p_dis_init)
316 {
317 sdk_err_t ret;
318 if (p_dis_init == NULL) {
319 return SDK_ERR_POINTER_NULL;
320 }
321 ret = memcpy_s(&s_dis_env.dis_init, sizeof(dis_init_t), p_dis_init, sizeof(dis_init_t));
322 if (ret < 0) {
323 return ret;
324 }
325
326 return ble_server_prf_add(&dis_prf_info);
327 }
328
329