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(&param->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