1 /* USER CODE BEGIN Header */
2 /**
3   ******************************************************************************
4   * @file    adv_buff_alloc.c
5   * @author  AMS - RF Application team
6   * @brief   Module providing buffer allocation for advertising data.
7   ******************************************************************************
8   * @attention
9   *
10   * Copyright (c) 2024 STMicroelectronics.
11   * All rights reserved.
12   *
13   * This software is licensed under terms that can be found in the LICENSE file
14   * in the root directory of this software component.
15   * If no LICENSE file comes with this software, it is provided AS-IS.
16   *
17   ******************************************************************************
18   */
19 /* USER CODE END Header */
20 #include "app_common.h"
21 #include "adv_buff_alloc.h"
22 #include "dm_alloc.h"
23 
24 #define NUM_ADV_BUFF_TYPES  3
25 
26 /* Bidimensional array. First dimension for the differetn types of data:
27  * advertising data, scan response data, periodic advertsing data. */
28 struct adv_set_info_s{
29   uint8_t  handle;
30   uint8_t *old_buff_data;
31   uint8_t *curr_buff_data;
32   uint8_t *next_buff_data;
33   uint16_t next_buff_len;
34 }adv_buf_info[NUM_ADV_BUFF_TYPES][CFG_BLE_NUM_ADV_SETS];
35 
36 /**
37 * @brief  Initialize the module for buffer allocation. Mandatory before any use of the module.
38 * @retval None
39 */
adv_buff_init(void)40 void adv_buff_init(void)
41 {
42   uint8_t i, j;
43 
44   for(i = 0; i < NUM_ADV_BUFF_TYPES; i++)
45     for(j = 0; j < CFG_BLE_NUM_ADV_SETS; j++)
46     adv_buf_info[i][j].handle = 0xFF;
47 }
48 
49 /**
50 * @brief  Retrieve buffer info
51 * @param  handle Advertising handle
52 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
53 * @retval It returns the pointer to the buffer info structure
54 */
search_handle(uint8_t handle,uint8_t data_type)55 static struct adv_set_info_s *search_handle(uint8_t handle, uint8_t data_type)
56 {
57   int i;
58 
59   /* Just a check, but this should not happen. */
60   if(data_type >= NUM_ADV_BUFF_TYPES)
61     return NULL;
62 
63   for(i = 0; i < CFG_BLE_NUM_ADV_SETS; i++){
64     if(adv_buf_info[data_type][i].handle == handle)
65       return &adv_buf_info[data_type][i];
66   }
67   return NULL;
68 }
69 
70 /**
71 * @brief  Check if a new buffer is allocated with data not yet passed to the stack (i.e. buffer not yet activated).
72 * @param  handle Advertising handle
73 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
74 * @retval It returns TRUE if there is a new buffer to be activated.
75 */
new_buff_pending(uint8_t handle,uint8_t data_type)76 uint8_t new_buff_pending(uint8_t handle, uint8_t data_type)
77 {
78   struct adv_set_info_s *info;
79 
80   info = search_handle(handle, data_type);
81 
82   if(info == NULL || info->next_buff_data == NULL){
83     return FALSE;
84   }
85   else {
86     return TRUE;
87   }
88 
89 }
90 
91 /**
92 * @brief  It allocates a buffer for advertising or scan response data.
93 * @param  handle Advertising handle
94 * @param  buffer_len New length to be allocated
95 * @param  extend If 0, it allocates a new buffer for the given advertising set, after having been
96 *                freed any previously allocated buffer.
97 *                If 1, increase the size of the current block allocated for the advertising set, possibly
98 *                allocating a new block different from the previous one (in this case with a different address).
99 * @param[out] old_buff_len Size of the old buffer in case of an extension, otherwise 0.
100 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
101 * @retval It returns the pointer to the entire buffer.
102 */
adv_buff_alloc(uint8_t handle,uint16_t buffer_len,uint8_t extend,uint16_t * old_buff_len,uint8_t data_type)103 uint8_t *adv_buff_alloc(uint8_t handle, uint16_t buffer_len, uint8_t extend, uint16_t *old_buff_len, uint8_t data_type)
104 {
105   struct adv_set_info_s *info;
106 
107   *old_buff_len = 0;
108 
109   info = search_handle(handle, data_type);
110   if(info == NULL){
111     // No existing handle found. Search free locations.
112     info = search_handle(0xFF, data_type);
113     if(info){
114       info->handle = handle;
115       info->old_buff_data = NULL;
116       info->curr_buff_data = NULL;
117       info->next_buff_data = NULL;
118       info->next_buff_len = 0;
119     }
120     else {
121       // No free locations
122       return NULL;
123     }
124   }
125 
126   if(!extend){ // New allocation
127 
128     if(info->old_buff_data) // A buffer which still need to be freed. Do not allow new allocations.
129       return NULL;
130 
131     if(info->next_buff_data) // A buffer has been previously allocated
132       dm_free(info->next_buff_data);
133 
134     if(buffer_len)
135       info->next_buff_data = dm_alloc(buffer_len);
136     else
137       info->next_buff_data = NULL;
138     if(info->next_buff_data)
139       info->next_buff_len = buffer_len;
140     else
141       info->next_buff_len = 0;
142   }
143   else { // Reallocation
144     uint8_t *buffer;
145     if(!info->next_buff_data) // No buffer previously allocated
146       return NULL;
147     buffer = dm_realloc(info->next_buff_data, info->next_buff_len + buffer_len);
148     if(buffer){
149       info->next_buff_data = buffer;
150       *old_buff_len = info->next_buff_len;
151       info->next_buff_len += buffer_len;
152     }
153     else {
154       dm_free(info->next_buff_data);
155       info->next_buff_data = 0;
156       info->next_buff_len = 0;
157     }
158   }
159   return info->next_buff_data;
160 }
161 
162 /**
163 * @brief  Free the buffer that is currently active.
164 * @param  handle Advertising handle
165 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
166 * @retval None
167 */
adv_buff_free_current(uint8_t handle,uint8_t data_type)168 void adv_buff_free_current(uint8_t handle, uint8_t data_type)
169 {
170   struct adv_set_info_s *info;
171 
172   info = search_handle(handle, data_type);
173   if(info == NULL)
174     return;
175 
176   dm_free(info->curr_buff_data);
177   info->curr_buff_data = NULL;
178 }
179 
180 /**
181 * @brief  Free the buffer that is allocated to hold next data
182 * @param  handle Advertising handle
183 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
184 * @retval None
185 */
adv_buff_free_next(uint8_t handle,uint8_t data_type)186 void adv_buff_free_next(uint8_t handle, uint8_t data_type)
187 {
188   struct adv_set_info_s *info;
189 
190   info = search_handle(handle, data_type);
191   if(info == NULL)
192     return;
193 
194   dm_free(info->next_buff_data);
195   info->next_buff_data = NULL;
196   info->next_buff_len = 0;
197 }
198 
199 /**
200 * @brief  Free the old buffer, which was waiting to be abandoned by the stack
201 * @param  buff Pointer to the buffer
202 * @retval None
203 */
adv_buff_free_old(uint8_t * buff)204 void adv_buff_free_old(uint8_t *buff)
205 {
206   uint8_t i, j;
207 
208   if(buff == NULL)
209     return;
210 
211   for(j = 0; j < NUM_ADV_BUFF_TYPES; j++){
212 
213     for(i = 0; i < CFG_BLE_NUM_ADV_SETS; i++){
214       if(adv_buf_info[j][i].old_buff_data == buff){
215         dm_free(buff);
216         adv_buf_info[j][i].old_buff_data = NULL;
217         return;
218       }
219       /* Check also if it has been requested to free the current buffer.
220          This may happen if the advertising set is removed. */
221       if(adv_buf_info[j][i].curr_buff_data == buff){
222         /* Free buffers and remove info about this handle, since advertising set
223            has been removed */
224         dm_free(adv_buf_info[j][i].curr_buff_data);
225         adv_buf_info[j][i].curr_buff_data = NULL;
226         //dm_free(adv_buf_info[i].old_buff_data); This line should not be needed.
227         adv_buf_info[j][i].handle = 0xFF;
228         return;
229       }
230     }
231 
232   }
233 }
234 
235 /**
236 * @brief  Function to be called when the new allocated buffer is successfully passed
237 *         to the stack to be the new buffer. The new allocated buffer is now
238 *         considered as the current buffer in use by the stack. If needed, call
239 *         adv_buff_deactivate_current() before calling this function.
240 * @param  handle Advertising handle
241 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
242 * @retval None
243 */
adv_buff_activate_next(uint8_t handle,uint8_t data_type)244 void adv_buff_activate_next(uint8_t handle, uint8_t data_type)
245 {
246   struct adv_set_info_s *info;
247 
248   info = search_handle(handle, data_type);
249   if(info == NULL)
250     return;
251 
252   info->curr_buff_data = info->next_buff_data;
253   info->next_buff_data = NULL;
254   info->next_buff_len = 0;
255 }
256 
257 /**
258 * @brief  Function to be called after having been informed the stack that the current
259           buffer does not have to be used anymore.
260 * @param  handle Advertising handle
261 * @param  data_type Type of advertising data (see @ref ADV_DATA_TYPES)
262 * @retval None
263 */
adv_buff_deactivate_current(uint8_t handle,uint8_t data_type)264 void adv_buff_deactivate_current(uint8_t handle, uint8_t data_type)
265 {
266   struct adv_set_info_s *info;
267 
268   info = search_handle(handle, data_type);
269   if(info == NULL)
270     return;
271 
272   info->old_buff_data = info->curr_buff_data; // What is in old_buff_data has to be freed.
273   info->curr_buff_data = NULL;
274 }
275 
276