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