1 /*****************************************************************************
2 * Nations Microcontroller Software Support
3 * ----------------------------------------------------------------------------
4 * Copyright (c) 2017, Nations Corporation
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *
11 * - Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the disclaimer below.
13 *
14 * Nations's name may not be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
20 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 * ****************************************************************************/
28 /*****************************************************************************
29 * 文件名 :bass_task.c
30 * 功能描述:
31 * 版本:V 1.0.0
32 * 作者:
33 * 日期:
34 * ****************************************************************************/
35
36 /**
37 ****************************************************************************************
38 * @addtogroup BASSTASK
39 * @{
40 ****************************************************************************************
41 */
42
43 /*
44 * INCLUDE FILES
45 ****************************************************************************************
46 */
47
48 #include "rwip_config.h"
49
50 #if (BLE_BATT_SERVER)
51
52 #include "gap.h"
53 #include "gattc_task.h"
54
55 #include "bass.h"
56 #include "bass_task.h"
57
58 #include "prf_utils.h"
59
60 #include "co_utils.h"
61
62 /*
63 * GLOBAL FUNCTIONS DEFINITIONS
64 ****************************************************************************************
65 */
66
67
68 /**
69 ****************************************************************************************
70 * @brief Handles reception of the @ref BAPS_ENABLE_REQ message.
71 * The handler enables the Battery 'Profile' Server Role.
72 * @param[in] msgid Id of the message received (probably unused).
73 * @param[in] param Pointer to the parameters of the message.
74 * @param[in] dest_id ID of the receiving task instance (probably unused).
75 * @param[in] src_id ID of the sending task instance.
76 * @return If the message was consumed or not.
77 ****************************************************************************************
78 */
bass_enable_req_handler(ke_msg_id_t const msgid,struct bass_enable_req const * param,ke_task_id_t const dest_id,ke_task_id_t const src_id)79 static int bass_enable_req_handler(ke_msg_id_t const msgid,struct bass_enable_req const *param,ke_task_id_t const dest_id,ke_task_id_t const src_id)
80 {
81
82 int msg_status = KE_MSG_SAVED;
83 uint8_t state = ke_state_get(dest_id);
84 uint8_t conidx = KE_IDX_GET(src_id);
85 // check state of the task
86 if (state == BASS_IDLE)
87 {
88 struct bass_env_tag* bass_env = PRF_ENV_GET(BASS, bass);
89 // Check provided values
90 if ((param->conidx > BLE_CONNECTION_MAX) || (gapc_get_conhdl(param->conidx) == GAP_INVALID_CONHDL))
91 {
92 // an error occurs, trigg it.
93 struct bass_enable_rsp* rsp = KE_MSG_ALLOC(BASS_ENABLE_RSP, src_id,dest_id, bass_enable_rsp);
94 rsp->conidx = param->conidx;
95 rsp->status = (param->conidx > BLE_CONNECTION_MAX) ? GAP_ERR_INVALID_PARAM : PRF_ERR_REQ_DISALLOWED;
96 ke_msg_send(rsp);
97 msg_status = KE_MSG_CONSUMED;
98 }
99 else
100 {
101 // put task in a busy state
102 msg_status = KE_MSG_NO_FREE;
103 ke_state_set(dest_id, BASS_BUSY);
104 bass_env->batt_lvl[conidx] = param->old_batt_lvl[conidx];
105 bass_env->ntf_cfg[param->conidx] = param->ntf_cfg;
106 bass_env->operation = ke_param2msg(param);
107 bass_env->cursor = 0;
108 // trigger notification
109 bass_exe_operation();
110 }
111 }
112 return msg_status;
113 }
114
115 /**
116 ****************************************************************************************
117 * @brief Handles reception of the @ref BAPS_BATT_LEVEL_SEND_REQ message.
118 * @param[in] msgid Id of the message received (probably unused).
119 * @param[in] param Pointer to the parameters of the message.
120 * @param[in] dest_id ID of the receiving task instance (probably unused).
121 * @param[in] src_id ID of the sending task instance.
122 * @return If the message was consumed or not.
123 ****************************************************************************************
124 */
bass_batt_level_upd_req_handler(ke_msg_id_t const msgid,struct bass_batt_level_upd_req const * param,ke_task_id_t const dest_id,ke_task_id_t const src_id)125 static int bass_batt_level_upd_req_handler(ke_msg_id_t const msgid,struct bass_batt_level_upd_req const *param,ke_task_id_t const dest_id,ke_task_id_t const src_id)
126 {
127
128
129 int msg_status = KE_MSG_SAVED;
130 uint8_t state = ke_state_get(dest_id);
131 // check state of the task
132 if (state == BASS_IDLE)
133 {
134 struct bass_env_tag* bass_env = PRF_ENV_GET(BASS, bass);
135 // Check provided values
136 if ((param->bas_instance < bass_env->svc_nb) && (param->batt_level <= BAS_BATTERY_LVL_MAX))
137 {
138 // update the battery level value
139 bass_env->batt_lvl[param->bas_instance] = param->batt_level;
140 // put task in a busy state
141 msg_status = KE_MSG_NO_FREE;
142 ke_state_set(dest_id, BASS_BUSY);
143 bass_env->operation = ke_param2msg(param);
144 bass_env->cursor = 0;
145 // trigger notification
146 bass_exe_operation();
147 }
148 else
149 {
150 // an error occurs, trigg it.
151 struct bass_batt_level_upd_rsp * rsp = KE_MSG_ALLOC(BASS_BATT_LEVEL_UPD_RSP, src_id,dest_id, bass_batt_level_upd_rsp);
152 rsp->status = PRF_ERR_INVALID_PARAM;
153 ke_msg_send(rsp);
154 msg_status = KE_MSG_CONSUMED;
155 }
156 }
157 return (msg_status);
158 }
159
160 /**
161 ****************************************************************************************
162 * @brief Handles reception of the attribute info request message.
163 *
164 * @param[in] msgid Id of the message received (probably unused).
165 * @param[in] param Pointer to the parameters of the message.
166 * @param[in] dest_id ID of the receiving task instance (probably unused).
167 * @param[in] src_id ID of the sending task instance.
168 * @return If the message was consumed or not.
169 ****************************************************************************************
170 */
gattc_att_info_req_ind_handler(ke_msg_id_t const msgid,struct gattc_att_info_req_ind * param,ke_task_id_t const dest_id,ke_task_id_t const src_id)171 static int gattc_att_info_req_ind_handler(ke_msg_id_t const msgid,struct gattc_att_info_req_ind *param,ke_task_id_t const dest_id,ke_task_id_t const src_id)
172 {
173
174 struct gattc_att_info_cfm * cfm;
175 uint8_t svc_idx = 0, att_idx = 0;
176 // retrieve handle information
177 uint8_t status = bass_get_att_idx(param->handle, &svc_idx, &att_idx);
178 //Send write response
179 cfm = KE_MSG_ALLOC(GATTC_ATT_INFO_CFM, src_id, dest_id, gattc_att_info_cfm);
180 cfm->handle = param->handle;
181 if (status == GAP_ERR_NO_ERROR)
182 {
183 // check if it's a client configuration char
184 if (att_idx == BAS_IDX_BATT_LVL_NTF_CFG)
185 {
186 // CCC attribute length = 2
187 cfm->length = 2;
188 }
189 // not expected request
190 else
191 {
192 cfm->length = 0;
193 status = ATT_ERR_WRITE_NOT_PERMITTED;
194 }
195 }
196 cfm->status = status;
197 ke_msg_send(cfm);
198 return (KE_MSG_CONSUMED);
199 }
200
201
202 /**
203 ****************************************************************************************
204 * @brief Handles reception of the @ref GATTC_WRITE_REQ_IND message.
205 * @param[in] msgid Id of the message received (probably unused).
206 * @param[in] param Pointer to the parameters of the message.
207 * @param[in] dest_id ID of the receiving task instance (probably unused).
208 * @param[in] src_id ID of the sending task instance.
209 * @return If the message was consumed or not.
210 ****************************************************************************************
211 */
gattc_write_req_ind_handler(ke_msg_id_t const msgid,struct gattc_write_req_ind const * param,ke_task_id_t const dest_id,ke_task_id_t const src_id)212 static int gattc_write_req_ind_handler(ke_msg_id_t const msgid, struct gattc_write_req_ind const *param,ke_task_id_t const dest_id, ke_task_id_t const src_id)
213 {
214
215 struct gattc_write_cfm * cfm;
216 uint8_t svc_idx = 0, att_idx = 0;
217 uint8_t conidx = KE_IDX_GET(src_id);
218 // retrieve handle information
219 uint8_t status = bass_get_att_idx(param->handle, &svc_idx, &att_idx);
220 // If the attribute has been found, status is GAP_ERR_NO_ERROR
221 if (status == GAP_ERR_NO_ERROR)
222 {
223 struct bass_env_tag* bass_env = PRF_ENV_GET(BASS, bass);
224 // Extract value before check
225 uint16_t ntf_cfg = co_read16p(¶m->value[0]);
226 // Only update configuration if value for stop or notification enable
227 if ((att_idx == BAS_IDX_BATT_LVL_NTF_CFG)&& ((ntf_cfg == PRF_CLI_STOP_NTFIND) || (ntf_cfg == PRF_CLI_START_NTF)))
228 {
229 // Conserve information in environment
230 if (ntf_cfg == PRF_CLI_START_NTF)
231 {
232 // Ntf cfg bit set to 1
233 bass_env->ntf_cfg[conidx] |= (BAS_BATT_LVL_NTF_SUP << svc_idx);
234 }
235 else
236 {
237 // Ntf cfg bit set to 0
238 bass_env->ntf_cfg[conidx] &= ~(BAS_BATT_LVL_NTF_SUP << svc_idx);
239 }
240
241 // Inform APP of configuration change
242 struct bass_batt_level_ntf_cfg_ind * ind = KE_MSG_ALLOC(BASS_BATT_LEVEL_NTF_CFG_IND,prf_dst_task_get(&(bass_env->prf_env), conidx), dest_id,bass_batt_level_ntf_cfg_ind);
243 ind->conidx = conidx;
244 ind->ntf_cfg = bass_env->ntf_cfg[conidx];
245 ke_msg_send(ind);
246 }
247 else
248 {
249 status = PRF_APP_ERROR;
250 }
251 }
252 //Send write response
253 cfm = KE_MSG_ALLOC(GATTC_WRITE_CFM, src_id, dest_id, gattc_write_cfm);
254 cfm->handle = param->handle;
255 cfm->status = status;
256 ke_msg_send(cfm);
257 return (KE_MSG_CONSUMED);
258 }
259
260
261 /**
262 ****************************************************************************************
263 * @brief Handles reception of the @ref GATTC_READ_REQ_IND message.
264 * @param[in] msgid Id of the message received (probably unused).
265 * @param[in] param Pointer to the parameters of the message.
266 * @param[in] dest_id ID of the receiving task instance (probably unused).
267 * @param[in] src_id ID of the sending task instance.
268 * @return If the message was consumed or not.
269 ****************************************************************************************
270 */
gattc_read_req_ind_handler(ke_msg_id_t const msgid,struct gattc_read_req_ind const * param,ke_task_id_t const dest_id,ke_task_id_t const src_id)271 static int gattc_read_req_ind_handler(ke_msg_id_t const msgid, struct gattc_read_req_ind const *param,ke_task_id_t const dest_id, ke_task_id_t const src_id)
272 {
273
274 struct gattc_read_cfm * cfm;
275 uint8_t svc_idx = 0, att_idx = 0;
276 uint8_t conidx = KE_IDX_GET(src_id);
277 // retrieve handle information
278 uint8_t status = bass_get_att_idx(param->handle, &svc_idx, &att_idx);
279 uint16_t length = 0;
280 struct bass_env_tag* bass_env = PRF_ENV_GET(BASS, bass);
281 // If the attribute has been found, status is GAP_ERR_NO_ERROR
282 if (status == GAP_ERR_NO_ERROR)
283 {
284 // read notification information
285 if (att_idx == BAS_IDX_BATT_LVL_VAL)
286 {
287 length = sizeof(uint8_t);
288 }
289 // read notification information
290 else if (att_idx == BAS_IDX_BATT_LVL_NTF_CFG)
291 {
292 length = sizeof(uint16_t);
293 }
294 else if (att_idx == BAS_IDX_BATT_LVL_PRES_FMT)
295 {
296 length = PRF_CHAR_PRES_FMT_SIZE;
297 }
298 else
299 {
300 status = PRF_APP_ERROR;
301 }
302 }
303 //Send write response
304 cfm = KE_MSG_ALLOC_DYN(GATTC_READ_CFM, src_id, dest_id, gattc_read_cfm, length);
305 cfm->handle = param->handle;
306 cfm->status = status;
307 cfm->length = length;
308
309 if (status == GAP_ERR_NO_ERROR)
310 {
311 // read notification information
312 if (att_idx == BAS_IDX_BATT_LVL_VAL)
313 {
314 cfm->value[conidx] = bass_env->batt_lvl[svc_idx]; //read batt_lvel
315 }
316 // retrieve notification config
317 else if (att_idx == BAS_IDX_BATT_LVL_NTF_CFG)
318 {
319 uint16_t ntf_cfg = (bass_env->ntf_cfg[conidx] >> svc_idx & BAS_BATT_LVL_NTF_SUP) ? PRF_CLI_START_NTF : PRF_CLI_STOP_NTFIND;
320 co_write16p(cfm->value, ntf_cfg);
321 }
322 // retrieve battery level format
323 else if (att_idx == BAS_IDX_BATT_LVL_PRES_FMT)
324 {
325 prf_pack_char_pres_fmt(cfm->value, &(bass_env->batt_level_pres_format[svc_idx]));
326 }
327 else
328 {
329 /* Not Possible */
330 }
331 }
332 ke_msg_send(cfm);
333 return (KE_MSG_CONSUMED);
334 }
335 /**
336 ****************************************************************************************
337 * @brief Handles @ref GATTC_CMP_EVT for GATTC_NOTIFY message meaning that Measurement
338 * notification has been correctly sent to peer device (but not confirmed by peer device).
339 * *
340 * @param[in] msgid Id of the message received.
341 * @param[in] param Pointer to the parameters of the message.
342 * @param[in] dest_id ID of the receiving task instance
343 * @param[in] src_id ID of the sending task instance.
344 * @return If the message was consumed or not.
345 ****************************************************************************************
346 */
gattc_cmp_evt_handler(ke_msg_id_t const msgid,struct gattc_cmp_evt const * param,ke_task_id_t const dest_id,ke_task_id_t const src_id)347 static int gattc_cmp_evt_handler(ke_msg_id_t const msgid, struct gattc_cmp_evt const *param,ke_task_id_t const dest_id, ke_task_id_t const src_id)
348 {
349
350 if (param->operation == GATTC_NOTIFY)
351 {
352 // continue operation execution
353 bass_exe_operation();
354 }
355 return (KE_MSG_CONSUMED);
356 }
357
358 /*
359 * GLOBAL VARIABLE DEFINITIONS
360 ****************************************************************************************
361 */
362
363 /// Default State handlers definition
364 const struct ke_msg_handler bass_default_state[] =
365 {
366 {BASS_ENABLE_REQ, (ke_msg_func_t) bass_enable_req_handler},
367 {BASS_BATT_LEVEL_UPD_REQ, (ke_msg_func_t) bass_batt_level_upd_req_handler},
368 {GATTC_ATT_INFO_REQ_IND, (ke_msg_func_t) gattc_att_info_req_ind_handler},
369 {GATTC_WRITE_REQ_IND, (ke_msg_func_t) gattc_write_req_ind_handler},
370 {GATTC_READ_REQ_IND, (ke_msg_func_t) gattc_read_req_ind_handler},
371 {GATTC_CMP_EVT, (ke_msg_func_t) gattc_cmp_evt_handler},
372 };
373
374 /// Specifies the message handlers that are common to all states.
375 const struct ke_state_handler bass_default_handler = KE_STATE_HANDLER(bass_default_state);
376
377 #endif /* #if (BLE_BATT_SERVER) */
378
379 /// @} BASSTASK
380