1 | /** @file wlan_mac_ltg.c |
---|
2 | * @brief Local Traffic Generator |
---|
3 | * |
---|
4 | * This contains code for scheduling local traffic directly from the |
---|
5 | * board. |
---|
6 | * |
---|
7 | * @copyright Copyright 2013-2019, Mango Communications. All rights reserved. |
---|
8 | * Distributed under the Mango Communications Reference Design License |
---|
9 | * See LICENSE.txt included in the design archive or |
---|
10 | * at http://mangocomm.com/802.11/license |
---|
11 | * |
---|
12 | * This file is part of the Mango 802.11 Reference Design (https://mangocomm.com/802.11) |
---|
13 | */ |
---|
14 | |
---|
15 | /***************************** Include Files *********************************/ |
---|
16 | #include "wlan_mac_high_sw_config.h" |
---|
17 | |
---|
18 | #include "xil_types.h" |
---|
19 | #include "stdlib.h" |
---|
20 | #include "stdio.h" |
---|
21 | #include "string.h" |
---|
22 | #include "wlan_mac_dl_list.h" |
---|
23 | |
---|
24 | #include "wlan_exp_common.h" |
---|
25 | |
---|
26 | #include "wlan_mac_common.h" |
---|
27 | #include "wlan_mac_802_11_defs.h" |
---|
28 | #include "wlan_mac_eth_util.h" |
---|
29 | #include "wlan_mac_high.h" |
---|
30 | #include "wlan_mac_ltg.h" |
---|
31 | #include "wlan_mac_schedule.h" |
---|
32 | #include "wlan_platform_common.h" |
---|
33 | #include "wlan_platform_high.h" |
---|
34 | #include "wlan_mac_packet_types.h" |
---|
35 | #include "wlan_platform_intc.h" |
---|
36 | |
---|
37 | #if WLAN_SW_CONFIG_ENABLE_LTG |
---|
38 | |
---|
39 | /*************************** Constant Definitions ****************************/ |
---|
40 | |
---|
41 | platform_high_dev_info_t platform_high_dev_info; |
---|
42 | |
---|
43 | /*************************** Variable Definitions ****************************/ |
---|
44 | |
---|
45 | static dl_list tg_list; |
---|
46 | static function_ptr_t ltg_callback; |
---|
47 | static volatile u64 num_ltg_checks; |
---|
48 | static volatile u32 schedule_id; |
---|
49 | static volatile u8 schedule_running; |
---|
50 | |
---|
51 | |
---|
52 | /*************************** Functions Prototypes ****************************/ |
---|
53 | |
---|
54 | void ltg_sched_check(); |
---|
55 | int ltg_sched_start_l(dl_entry* curr_tg_dl_entry); |
---|
56 | int ltg_sched_stop_l(dl_entry* curr_tg_dl_entry); |
---|
57 | dl_entry* ltg_sched_create_l(); |
---|
58 | void ltg_sched_destroy_l(dl_entry* tg_dl_entry); |
---|
59 | void ltg_sched_destroy_params(tg_schedule* tg); |
---|
60 | |
---|
61 | |
---|
62 | /******************************** Functions **********************************/ |
---|
63 | |
---|
64 | /*****************************************************************************/ |
---|
65 | /** |
---|
66 | * @brief Initialize the LTG Framework |
---|
67 | * |
---|
68 | * This function is called by the High Framework when first starting up |
---|
69 | * @return None |
---|
70 | */ |
---|
71 | int wlan_mac_ltg_sched_init(){ |
---|
72 | |
---|
73 | platform_high_dev_info = wlan_platform_high_get_dev_info(); |
---|
74 | |
---|
75 | int return_value = 0; |
---|
76 | |
---|
77 | schedule_running = 0; |
---|
78 | schedule_id = SCHEDULE_FAILURE; |
---|
79 | num_ltg_checks = 0; |
---|
80 | ltg_sched_remove(LTG_REMOVE_ALL); |
---|
81 | dl_list_init(&tg_list); |
---|
82 | ltg_callback = (function_ptr_t)wlan_null_callback; |
---|
83 | |
---|
84 | return return_value; |
---|
85 | } |
---|
86 | |
---|
87 | /*****************************************************************************/ |
---|
88 | /** |
---|
89 | * @brief Set LTG event callback |
---|
90 | * |
---|
91 | * This function should be called by user application to configure a callback |
---|
92 | * that will be called according to an LTG schedule. |
---|
93 | * |
---|
94 | * @param callback - function pointer |
---|
95 | * @return None |
---|
96 | */ |
---|
97 | void wlan_mac_ltg_sched_set_callback(void(*callback)()){ |
---|
98 | ltg_callback = (function_ptr_t)callback; |
---|
99 | } |
---|
100 | |
---|
101 | /*****************************************************************************/ |
---|
102 | /** |
---|
103 | * @brief Create an LTG schedule |
---|
104 | * |
---|
105 | * This function will set up (but not start) an LTG. |
---|
106 | * |
---|
107 | * @param type - LTG_SCHED_TYPE_PERIODIC or LTG_SCHED_TYPE_UNIFORM_RAND |
---|
108 | * @param params - pointer to ltg_sched_periodic_params_t or ltg_sched_uniform_rand_params_t |
---|
109 | * @param callback_arg - pointer to ltg_pyld_fixed_t, ltg_pyld_all_assoc_fixed_t, or ltg_pyld_uniform_rand_t |
---|
110 | * @param cleanup_callback - optional function pointer to be called upon destruction of LTG. NULL if not needed. |
---|
111 | * @return ltg_id - ID of LTG that is created. Used as argument to stop, stop, and remove functions |
---|
112 | */ |
---|
113 | u32 ltg_sched_create(u32 type, void* params, void* callback_arg, void(*cleanup_callback)()){ |
---|
114 | |
---|
115 | static u32 id = 0; |
---|
116 | u32 return_value; |
---|
117 | |
---|
118 | tg_schedule* curr_tg; |
---|
119 | dl_entry* curr_tg_dl_entry; |
---|
120 | |
---|
121 | //Create a new tg for this id |
---|
122 | curr_tg_dl_entry = ltg_sched_create_l(); |
---|
123 | |
---|
124 | if(curr_tg_dl_entry == NULL){ |
---|
125 | return_value = LTG_ID_INVALID; |
---|
126 | return return_value; |
---|
127 | } |
---|
128 | |
---|
129 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
130 | |
---|
131 | curr_tg->id = id; |
---|
132 | return_value = id; |
---|
133 | |
---|
134 | // Increment LTG ID so that it is unique per LTG |
---|
135 | id++; |
---|
136 | if(id == LTG_ID_INVALID){ id++; } |
---|
137 | |
---|
138 | curr_tg->type = type; |
---|
139 | curr_tg->cleanup_callback = (function_ptr_t)cleanup_callback; |
---|
140 | |
---|
141 | switch(type){ |
---|
142 | case LTG_SCHED_TYPE_PERIODIC: |
---|
143 | curr_tg->params = wlan_mac_high_malloc(sizeof(ltg_sched_periodic_params_t)); |
---|
144 | curr_tg->state = wlan_mac_high_malloc(sizeof(ltg_sched_periodic_state_t)); |
---|
145 | |
---|
146 | if(curr_tg->params != NULL && curr_tg->state != NULL){ |
---|
147 | bzero(curr_tg->state, sizeof(ltg_sched_periodic_state_t)); |
---|
148 | memcpy(curr_tg->params, params, sizeof(ltg_sched_periodic_params_t)); |
---|
149 | curr_tg->callback_arg = callback_arg; |
---|
150 | } else { |
---|
151 | xil_printf("LTG: ERROR: Failed to initialize LTG structs\n"); |
---|
152 | ltg_sched_destroy_l(curr_tg_dl_entry); |
---|
153 | return LTG_ID_INVALID; |
---|
154 | } |
---|
155 | break; |
---|
156 | |
---|
157 | case LTG_SCHED_TYPE_UNIFORM_RAND: |
---|
158 | curr_tg->params = wlan_mac_high_malloc(sizeof(ltg_sched_uniform_rand_params_t)); |
---|
159 | curr_tg->state = wlan_mac_high_malloc(sizeof(ltg_sched_uniform_rand_state_t)); |
---|
160 | |
---|
161 | if(curr_tg->params != NULL && curr_tg->state != NULL){ |
---|
162 | bzero(curr_tg->state, sizeof(ltg_sched_uniform_rand_state_t)); |
---|
163 | memcpy(curr_tg->params, params, sizeof(ltg_sched_uniform_rand_params_t)); |
---|
164 | curr_tg->callback_arg = callback_arg; |
---|
165 | } else { |
---|
166 | xil_printf("LTG: ERROR: Failed to initialize LTG structs\n"); |
---|
167 | ltg_sched_destroy_l(curr_tg_dl_entry); |
---|
168 | return LTG_ID_INVALID; |
---|
169 | } |
---|
170 | break; |
---|
171 | |
---|
172 | default: |
---|
173 | xil_printf("LTG: ERROR: Unknown type %d\n", type); |
---|
174 | ltg_sched_destroy_l(curr_tg_dl_entry); |
---|
175 | return LTG_ID_INVALID; |
---|
176 | break; |
---|
177 | } |
---|
178 | |
---|
179 | dl_entry_insertEnd(&tg_list,curr_tg_dl_entry); |
---|
180 | |
---|
181 | return return_value; |
---|
182 | } |
---|
183 | |
---|
184 | /*****************************************************************************/ |
---|
185 | /** |
---|
186 | * @brief Create an LTG schedule (low-level) |
---|
187 | * |
---|
188 | * Internal function. Not intended to be called by user code. |
---|
189 | * |
---|
190 | */ |
---|
191 | dl_entry* ltg_sched_create_l(){ |
---|
192 | dl_entry* curr_tg_dl_entry; |
---|
193 | tg_schedule* curr_tg; |
---|
194 | |
---|
195 | curr_tg_dl_entry = (dl_entry*)wlan_mac_high_malloc(sizeof(dl_entry)); |
---|
196 | |
---|
197 | if(curr_tg_dl_entry == NULL){ |
---|
198 | return NULL; |
---|
199 | } |
---|
200 | |
---|
201 | curr_tg = (tg_schedule*)wlan_mac_high_malloc(sizeof(tg_schedule)); |
---|
202 | |
---|
203 | if(curr_tg == NULL){ |
---|
204 | wlan_mac_high_free(curr_tg_dl_entry); |
---|
205 | return NULL; |
---|
206 | } |
---|
207 | |
---|
208 | curr_tg_dl_entry->data = (void*)curr_tg; |
---|
209 | |
---|
210 | return curr_tg_dl_entry; |
---|
211 | } |
---|
212 | |
---|
213 | /*****************************************************************************/ |
---|
214 | /** |
---|
215 | * @brief Start an existing LTG (low-lever) |
---|
216 | * |
---|
217 | * Internal function. Not intended to be called by user code. |
---|
218 | * |
---|
219 | */ |
---|
220 | int ltg_sched_start(u32 id){ |
---|
221 | dl_entry* curr_tg_dl_entry; |
---|
222 | |
---|
223 | if (id == LTG_START_ALL) { |
---|
224 | return ltg_sched_start_all(); |
---|
225 | } else { |
---|
226 | // Single ID case |
---|
227 | curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); |
---|
228 | |
---|
229 | if(curr_tg_dl_entry != NULL){ |
---|
230 | return ltg_sched_start_l(curr_tg_dl_entry); |
---|
231 | } else { |
---|
232 | xil_printf("LTG: ERROR: Failed to start: %d. Please ensure LTG is configured before starting\n", id); |
---|
233 | return WLAN_FAILURE; |
---|
234 | } |
---|
235 | } |
---|
236 | } |
---|
237 | |
---|
238 | /*****************************************************************************/ |
---|
239 | /** |
---|
240 | * @brief Start all existing LTGs |
---|
241 | * This function will start all previously created schedules that have no been removed |
---|
242 | * |
---|
243 | * @return 0 if success, -1 if error |
---|
244 | */ |
---|
245 | int ltg_sched_start_all(){ |
---|
246 | |
---|
247 | int ret_val = 0; |
---|
248 | tg_schedule* curr_tg; |
---|
249 | dl_entry* next_tg_dl_entry; |
---|
250 | dl_entry* curr_tg_dl_entry; |
---|
251 | |
---|
252 | next_tg_dl_entry = tg_list.first; |
---|
253 | interrupt_state_t prev_interrupt_state; |
---|
254 | |
---|
255 | prev_interrupt_state = wlan_platform_intc_stop(); |
---|
256 | |
---|
257 | while(next_tg_dl_entry != NULL){ |
---|
258 | curr_tg_dl_entry = next_tg_dl_entry; |
---|
259 | next_tg_dl_entry = dl_entry_next(next_tg_dl_entry); |
---|
260 | |
---|
261 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
262 | |
---|
263 | if(ltg_sched_start_l(curr_tg_dl_entry) == -1) { |
---|
264 | xil_printf("LTG: ERROR: Failed to start: %d. Please ensure LTG is configured before starting\n", (curr_tg->id)); |
---|
265 | ret_val = -1; |
---|
266 | } |
---|
267 | } |
---|
268 | |
---|
269 | wlan_platform_intc_set_state(prev_interrupt_state); |
---|
270 | |
---|
271 | return ret_val; |
---|
272 | } |
---|
273 | |
---|
274 | /*****************************************************************************/ |
---|
275 | /** |
---|
276 | * @brief Start an existing LTG |
---|
277 | * |
---|
278 | * Internal function, not intended to be called by user code. |
---|
279 | * |
---|
280 | */ |
---|
281 | int ltg_sched_start_l(dl_entry* curr_tg_dl_entry){ |
---|
282 | tg_schedule* curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
283 | u64 timestamp = get_system_time_usec(); |
---|
284 | u64 random_timestamp; |
---|
285 | |
---|
286 | switch(curr_tg->type){ |
---|
287 | case LTG_SCHED_TYPE_PERIODIC: |
---|
288 | |
---|
289 | curr_tg->target = num_ltg_checks + (((ltg_sched_periodic_params_t*)(curr_tg->params))->interval_count); |
---|
290 | |
---|
291 | if(((ltg_sched_periodic_params_t*)(curr_tg->params))->duration_count != LTG_DURATION_FOREVER){ |
---|
292 | curr_tg->stop_target = num_ltg_checks + ((ltg_sched_periodic_params_t*)(curr_tg->params))->duration_count; |
---|
293 | } else { |
---|
294 | curr_tg->stop_target = LTG_DURATION_FOREVER; |
---|
295 | } |
---|
296 | |
---|
297 | ((ltg_sched_state_hdr_t*)(curr_tg->state))->start_timestamp = timestamp; |
---|
298 | ((ltg_sched_state_hdr_t*)(curr_tg->state))->enabled = 1; |
---|
299 | break; |
---|
300 | |
---|
301 | case LTG_SCHED_TYPE_UNIFORM_RAND: |
---|
302 | random_timestamp = (rand()%(((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->max_interval_count - ((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->min_interval_count))+((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->min_interval_count; |
---|
303 | curr_tg->target = num_ltg_checks + random_timestamp; |
---|
304 | |
---|
305 | if(((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->duration_count != LTG_DURATION_FOREVER){ |
---|
306 | curr_tg->stop_target = num_ltg_checks + ((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->duration_count; |
---|
307 | } else { |
---|
308 | curr_tg->stop_target = LTG_DURATION_FOREVER; |
---|
309 | } |
---|
310 | |
---|
311 | ((ltg_sched_state_hdr_t*)(curr_tg->state))->start_timestamp = timestamp; |
---|
312 | ((ltg_sched_state_hdr_t*)(curr_tg->state))->enabled = 1; |
---|
313 | break; |
---|
314 | |
---|
315 | default: |
---|
316 | xil_printf("LTG: ERROR: Unknown type %d\n", curr_tg->type); |
---|
317 | dl_entry_remove(&tg_list,curr_tg_dl_entry); |
---|
318 | ltg_sched_destroy_l(curr_tg_dl_entry); |
---|
319 | return WLAN_FAILURE; |
---|
320 | break; |
---|
321 | } |
---|
322 | |
---|
323 | if(schedule_running == 0){ |
---|
324 | schedule_running = 1; |
---|
325 | |
---|
326 | // A value of 0 here reflects that the LTG's minimum interval is whatever the scheduler's minimum interval is. |
---|
327 | // This assumption is shared among all calling contexts who set _count parameters in an LTG schedule. |
---|
328 | schedule_id = wlan_mac_schedule_add_event(SCHEDULE_ID_FINE, 0, SCHEDULE_REPEAT_FOREVER, (void*)ltg_sched_check); |
---|
329 | } |
---|
330 | |
---|
331 | //u64 start_time = ((ltg_sched_state_hdr_t*)(curr_tg->state))->start_timestamp; |
---|
332 | //xil_printf("LTG Start @ 0x%08x 0x%08x\n", (u32)(start_time >> 32), (u32)start_time ); |
---|
333 | |
---|
334 | return WLAN_SUCCESS; |
---|
335 | } |
---|
336 | |
---|
337 | /*****************************************************************************/ |
---|
338 | /** |
---|
339 | * @brief Start an existing LTG |
---|
340 | * |
---|
341 | * Internal function. Not intended to be called by user code. |
---|
342 | * |
---|
343 | */ |
---|
344 | void ltg_sched_check(){ |
---|
345 | tg_schedule* curr_tg; |
---|
346 | dl_entry* curr_tg_dl_entry; |
---|
347 | u64 random_timestamp; |
---|
348 | |
---|
349 | num_ltg_checks++; |
---|
350 | if(tg_list.length > 0){ |
---|
351 | |
---|
352 | curr_tg_dl_entry = tg_list.first; |
---|
353 | |
---|
354 | while(curr_tg_dl_entry != NULL){ |
---|
355 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
356 | |
---|
357 | if(((ltg_sched_state_hdr_t*)(curr_tg->state))->enabled){ |
---|
358 | |
---|
359 | if( num_ltg_checks >= ( curr_tg->target ) ){ |
---|
360 | switch(curr_tg->type){ |
---|
361 | case LTG_SCHED_TYPE_PERIODIC: |
---|
362 | curr_tg->target = num_ltg_checks + (((ltg_sched_periodic_params_t*)(curr_tg->params))->interval_count); |
---|
363 | break; |
---|
364 | case LTG_SCHED_TYPE_UNIFORM_RAND: |
---|
365 | random_timestamp = (rand()%(((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->max_interval_count - ((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->min_interval_count))+((ltg_sched_uniform_rand_params_t*)(curr_tg->params))->min_interval_count; |
---|
366 | curr_tg->target = num_ltg_checks + random_timestamp; |
---|
367 | break; |
---|
368 | default: |
---|
369 | ltg_sched_stop_l(curr_tg_dl_entry); |
---|
370 | return; |
---|
371 | break; |
---|
372 | } |
---|
373 | ltg_callback(curr_tg->id, curr_tg->callback_arg); |
---|
374 | } |
---|
375 | |
---|
376 | if( curr_tg->stop_target != LTG_DURATION_FOREVER && num_ltg_checks >= ( curr_tg->stop_target )){ |
---|
377 | ltg_sched_stop_l(curr_tg_dl_entry); |
---|
378 | } |
---|
379 | |
---|
380 | } |
---|
381 | |
---|
382 | curr_tg_dl_entry = dl_entry_next(curr_tg_dl_entry); |
---|
383 | } |
---|
384 | } |
---|
385 | } |
---|
386 | |
---|
387 | /*****************************************************************************/ |
---|
388 | /** |
---|
389 | * @brief Stop an existing LTG |
---|
390 | * |
---|
391 | * This function will stop executing callbacks for a currently-running LTG. |
---|
392 | * |
---|
393 | * @param id - ID of LTG event (provided by ltg_sched_create) |
---|
394 | * @return 0 if success, -1 if error |
---|
395 | */ |
---|
396 | int ltg_sched_stop(u32 id){ |
---|
397 | dl_entry* curr_tg_dl_entry; |
---|
398 | |
---|
399 | if (id == LTG_STOP_ALL) { |
---|
400 | return ltg_sched_stop_all(); |
---|
401 | } else { |
---|
402 | // Single ID case |
---|
403 | curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); |
---|
404 | |
---|
405 | if(curr_tg_dl_entry != NULL){ |
---|
406 | return ltg_sched_stop_l(curr_tg_dl_entry); |
---|
407 | } else { |
---|
408 | xil_printf("LTG: ERROR: Failed to stop: %d. Please ensure LTG is configured before stopping\n", id); |
---|
409 | return WLAN_FAILURE; |
---|
410 | } |
---|
411 | } |
---|
412 | } |
---|
413 | |
---|
414 | /*****************************************************************************/ |
---|
415 | /** |
---|
416 | * @brief Stop all existing LTGs |
---|
417 | * |
---|
418 | * This function will stop executing callbacks for all currently-running LTGs. |
---|
419 | * Note: this does not remove the LTG schedules. They can be started again. |
---|
420 | * |
---|
421 | * @return WLAN_SUCCESS or WLAN_FAILURE |
---|
422 | */ |
---|
423 | int ltg_sched_stop_all(){ |
---|
424 | dl_entry* next_tg_dl_entry; |
---|
425 | dl_entry* curr_tg_dl_entry; |
---|
426 | interrupt_state_t prev_interrupt_state; |
---|
427 | |
---|
428 | next_tg_dl_entry = tg_list.first; |
---|
429 | |
---|
430 | prev_interrupt_state = wlan_platform_intc_stop(); |
---|
431 | |
---|
432 | while(next_tg_dl_entry != NULL){ |
---|
433 | curr_tg_dl_entry = next_tg_dl_entry; |
---|
434 | next_tg_dl_entry = dl_entry_next(curr_tg_dl_entry); |
---|
435 | ltg_sched_stop_l(curr_tg_dl_entry); |
---|
436 | } |
---|
437 | |
---|
438 | wlan_platform_intc_set_state(prev_interrupt_state); |
---|
439 | |
---|
440 | return WLAN_SUCCESS; |
---|
441 | } |
---|
442 | |
---|
443 | /*****************************************************************************/ |
---|
444 | /** |
---|
445 | * @brief Stop existing LTG (low-level) |
---|
446 | * |
---|
447 | * Internal function. Not intended to be called by user code. |
---|
448 | * |
---|
449 | */ |
---|
450 | int ltg_sched_stop_l(dl_entry* curr_tg_dl_entry){ |
---|
451 | tg_schedule* curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
452 | |
---|
453 | u64 timestamp = get_system_time_usec(); |
---|
454 | |
---|
455 | if ( ((ltg_sched_state_hdr_t*)(curr_tg->state))->enabled == 1 ) { |
---|
456 | ((ltg_sched_state_hdr_t*)(curr_tg->state))->enabled = 0; |
---|
457 | ((ltg_sched_state_hdr_t*)(curr_tg->state))->stop_timestamp = timestamp; |
---|
458 | //xil_printf("LTG Stop @ 0x%08x 0x%08x\n", (u32)(timestamp >> 32), (u32)timestamp ); |
---|
459 | } |
---|
460 | |
---|
461 | if(tg_list.length == 0 && schedule_running == 1){ |
---|
462 | wlan_mac_schedule_remove_event(schedule_id); |
---|
463 | schedule_running = 0; |
---|
464 | } |
---|
465 | |
---|
466 | return WLAN_SUCCESS; |
---|
467 | } |
---|
468 | |
---|
469 | /*****************************************************************************/ |
---|
470 | /** |
---|
471 | * @brief Get the current state of an LTG |
---|
472 | * |
---|
473 | * This function will allows user code to inspect the current state of an existing LTG. This function |
---|
474 | * returns the state by filling in pointers provided by arguments. |
---|
475 | * |
---|
476 | * @param id - ID of LTG event (provided by ltg_sched_create) |
---|
477 | * @param type - pointer to a u32 that will be filled in with LTG_SCHED_TYPE_PERIODIC or LTG_SCHED_TYPE_UNIFORM_RAND |
---|
478 | * @param state - double pointer that will be filled in with a pointer to ltg_sched_periodic_state_t or ltg_sched_uniform_rand_state_t |
---|
479 | * @return WLAN_SUCCESS or WLAN_FAILURE |
---|
480 | */ |
---|
481 | int ltg_sched_get_state(u32 id, u32* type, void** state){ |
---|
482 | //This function returns the type of schedule corresponding to the id argument |
---|
483 | //It fills in the state argument with the state of the schedule |
---|
484 | |
---|
485 | tg_schedule* curr_tg; |
---|
486 | dl_entry* curr_tg_dl_entry; |
---|
487 | |
---|
488 | curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); |
---|
489 | if(curr_tg_dl_entry == NULL){ |
---|
490 | return WLAN_FAILURE; |
---|
491 | } |
---|
492 | |
---|
493 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
494 | |
---|
495 | if(type != NULL) *type = curr_tg->type; |
---|
496 | if(state != NULL) *state = curr_tg->state; |
---|
497 | |
---|
498 | switch(curr_tg->type){ |
---|
499 | case LTG_SCHED_TYPE_PERIODIC: |
---|
500 | if(num_ltg_checks < (curr_tg->target) ){ |
---|
501 | ((ltg_sched_periodic_state_t*)(curr_tg->state))->time_to_next_count = (u32)(curr_tg->target - num_ltg_checks); |
---|
502 | } else { |
---|
503 | ((ltg_sched_periodic_state_t*)(curr_tg->state))->time_to_next_count = 0; |
---|
504 | } |
---|
505 | break; |
---|
506 | |
---|
507 | case LTG_SCHED_TYPE_UNIFORM_RAND: |
---|
508 | if(num_ltg_checks < (curr_tg->target) ){ |
---|
509 | ((ltg_sched_uniform_rand_state_t*)(curr_tg->state))->time_to_next_count = (u32)(curr_tg->target - num_ltg_checks); |
---|
510 | } else { |
---|
511 | ((ltg_sched_uniform_rand_state_t*)(curr_tg->state))->time_to_next_count = 0; |
---|
512 | } |
---|
513 | break; |
---|
514 | |
---|
515 | default: |
---|
516 | xil_printf("LTG: ERROR: Unknown type %d\n", curr_tg->type); |
---|
517 | return WLAN_FAILURE; |
---|
518 | break; |
---|
519 | } |
---|
520 | |
---|
521 | return WLAN_SUCCESS; |
---|
522 | } |
---|
523 | |
---|
524 | /*****************************************************************************/ |
---|
525 | /** |
---|
526 | * @brief Get the current params of an LTG |
---|
527 | * |
---|
528 | * This function will allows user code to inspect the current parameters of an existing LTG. This function |
---|
529 | * returns the state by filling in pointers provided by arguments. |
---|
530 | * |
---|
531 | * @param id - ID of LTG event (provided by ltg_sched_create) |
---|
532 | * @param params - double pointer that will be filled in with a pointer to ltg_sched_periodic_params_t or ltg_sched_uniform_rand_params_t |
---|
533 | * @return WLAN_SUCCESS or WLAN_FAILURE |
---|
534 | */ |
---|
535 | int ltg_sched_get_params(u32 id, void** params){ |
---|
536 | //This function returns the type of the schedule corresponding to the id argument |
---|
537 | //It fills in the current parameters of the schedule into the params argument |
---|
538 | tg_schedule* curr_tg; |
---|
539 | dl_entry* curr_tg_dl_entry; |
---|
540 | |
---|
541 | curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); |
---|
542 | if(curr_tg_dl_entry == NULL){ |
---|
543 | return WLAN_FAILURE; |
---|
544 | } |
---|
545 | |
---|
546 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
547 | |
---|
548 | *params = curr_tg->params; |
---|
549 | |
---|
550 | return WLAN_SUCCESS; |
---|
551 | } |
---|
552 | |
---|
553 | /*****************************************************************************/ |
---|
554 | /** |
---|
555 | * @brief Get the current callback argument of an LTG |
---|
556 | * |
---|
557 | * This function will allows user code to inspect the current callback argument of an existing LTG. |
---|
558 | * |
---|
559 | * @param id - ID of LTG event (provided by ltg_sched_create) |
---|
560 | * @param params - double pointer that will be filled in with a function pointer that is the current callback |
---|
561 | * @return WLAN_SUCCESS |
---|
562 | */ |
---|
563 | int ltg_sched_get_callback_arg(u32 id, void** callback_arg){ |
---|
564 | tg_schedule* curr_tg; |
---|
565 | dl_entry* curr_tg_dl_entry; |
---|
566 | |
---|
567 | curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); |
---|
568 | if(curr_tg_dl_entry == NULL){ |
---|
569 | return WLAN_FAILURE; |
---|
570 | } |
---|
571 | |
---|
572 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
573 | |
---|
574 | *callback_arg = curr_tg->callback_arg; |
---|
575 | |
---|
576 | return WLAN_SUCCESS; |
---|
577 | } |
---|
578 | |
---|
579 | /*****************************************************************************/ |
---|
580 | /** |
---|
581 | * @brief Remove an existing LTG |
---|
582 | * |
---|
583 | * This function will remove an existing LTG. If that LTG is currently running, it will first be stopped. |
---|
584 | * |
---|
585 | * @param id - ID of LTG event (provided by ltg_sched_create) |
---|
586 | * @return WLAN_SUCCESS or WLAN_FAILURE |
---|
587 | */ |
---|
588 | int ltg_sched_remove(u32 id){ |
---|
589 | tg_schedule* curr_tg; |
---|
590 | dl_entry* curr_tg_dl_entry; |
---|
591 | |
---|
592 | if (id == LTG_REMOVE_ALL) { |
---|
593 | return ltg_sched_remove_all(); |
---|
594 | } else { |
---|
595 | // Single ID case |
---|
596 | curr_tg_dl_entry = ltg_sched_find_tg_schedule(id); |
---|
597 | |
---|
598 | if(curr_tg_dl_entry != NULL){ |
---|
599 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
600 | |
---|
601 | ltg_sched_stop_l(curr_tg_dl_entry); |
---|
602 | dl_entry_remove(&tg_list, curr_tg_dl_entry); |
---|
603 | if(curr_tg->cleanup_callback != NULL){ |
---|
604 | curr_tg->cleanup_callback(curr_tg->id, curr_tg->callback_arg); |
---|
605 | } |
---|
606 | ltg_sched_destroy_l(curr_tg_dl_entry); |
---|
607 | |
---|
608 | return WLAN_SUCCESS; |
---|
609 | } else { |
---|
610 | xil_printf("LTG: ERROR: Failed to remove: %d. Please ensure LTG is configured before removing\n", id); |
---|
611 | return WLAN_FAILURE; |
---|
612 | } |
---|
613 | } |
---|
614 | } |
---|
615 | |
---|
616 | /*****************************************************************************/ |
---|
617 | /** |
---|
618 | * @brief Remove all existing LTGs |
---|
619 | * |
---|
620 | * This function will remove all existing LTGs. The end result will be idential to a just-booted node where no LTG has been configured. |
---|
621 | * |
---|
622 | * @return WLAN_SUCCESS |
---|
623 | */ |
---|
624 | int ltg_sched_remove_all(){ |
---|
625 | tg_schedule* curr_tg; |
---|
626 | dl_entry* next_tg_dl_entry; |
---|
627 | dl_entry* curr_tg_dl_entry; |
---|
628 | interrupt_state_t prev_interrupt_state; |
---|
629 | |
---|
630 | next_tg_dl_entry = tg_list.first; |
---|
631 | |
---|
632 | prev_interrupt_state = wlan_platform_intc_stop(); |
---|
633 | |
---|
634 | // NOTE: Cannot use a for loop for this iteration b/c we are removing |
---|
635 | // elements from the list. |
---|
636 | while(next_tg_dl_entry != NULL){ |
---|
637 | curr_tg_dl_entry = next_tg_dl_entry; |
---|
638 | next_tg_dl_entry = dl_entry_next(curr_tg_dl_entry); |
---|
639 | |
---|
640 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
641 | |
---|
642 | ltg_sched_stop_l(curr_tg_dl_entry); |
---|
643 | dl_entry_remove(&tg_list, curr_tg_dl_entry); |
---|
644 | if(curr_tg->cleanup_callback != NULL){ |
---|
645 | curr_tg->cleanup_callback(curr_tg->id, curr_tg->callback_arg); |
---|
646 | } |
---|
647 | ltg_sched_destroy_l(curr_tg_dl_entry); |
---|
648 | } |
---|
649 | |
---|
650 | wlan_platform_intc_set_state(prev_interrupt_state); |
---|
651 | |
---|
652 | return WLAN_SUCCESS; |
---|
653 | } |
---|
654 | |
---|
655 | /*****************************************************************************/ |
---|
656 | /** |
---|
657 | * @brief Destroy LTG parameters |
---|
658 | * |
---|
659 | * Internal function. Not intended to be called by user code. |
---|
660 | * |
---|
661 | */ |
---|
662 | void ltg_sched_destroy_params(tg_schedule* tg){ |
---|
663 | switch(tg->type){ |
---|
664 | case LTG_SCHED_TYPE_PERIODIC: |
---|
665 | case LTG_SCHED_TYPE_UNIFORM_RAND: |
---|
666 | wlan_mac_high_free(tg->params); |
---|
667 | wlan_mac_high_free(tg->state); |
---|
668 | break; |
---|
669 | } |
---|
670 | } |
---|
671 | |
---|
672 | /*****************************************************************************/ |
---|
673 | /** |
---|
674 | * @brief Destroy LTG parameters (low-level) |
---|
675 | * |
---|
676 | * Internal function. Not intended to be called by user code. |
---|
677 | * |
---|
678 | */ |
---|
679 | void ltg_sched_destroy_l(dl_entry* tg_dl_entry){ |
---|
680 | tg_schedule* curr_tg; |
---|
681 | |
---|
682 | curr_tg = (tg_schedule*)(tg_dl_entry->data); |
---|
683 | |
---|
684 | ltg_sched_destroy_params(curr_tg); |
---|
685 | wlan_mac_high_free(tg_dl_entry); |
---|
686 | wlan_mac_high_free(curr_tg); |
---|
687 | return; |
---|
688 | } |
---|
689 | |
---|
690 | /*****************************************************************************/ |
---|
691 | /** |
---|
692 | * @brief Find LTG given id |
---|
693 | * |
---|
694 | * Internal function. Not intended to be called by user code. |
---|
695 | * |
---|
696 | */ |
---|
697 | dl_entry* ltg_sched_find_tg_schedule(u32 id){ |
---|
698 | dl_entry* curr_tg_dl_entry; |
---|
699 | tg_schedule* curr_tg; |
---|
700 | int iter; |
---|
701 | |
---|
702 | curr_tg_dl_entry = tg_list.first; |
---|
703 | |
---|
704 | |
---|
705 | iter = tg_list.length; |
---|
706 | |
---|
707 | while((curr_tg_dl_entry != NULL) && (iter-- > 0)){ |
---|
708 | curr_tg = (tg_schedule*)(curr_tg_dl_entry->data); |
---|
709 | if( (curr_tg->id)==id){ |
---|
710 | return curr_tg_dl_entry; |
---|
711 | } |
---|
712 | curr_tg_dl_entry = dl_entry_next(curr_tg_dl_entry); |
---|
713 | } |
---|
714 | return NULL; |
---|
715 | } |
---|
716 | |
---|
717 | /*****************************************************************************/ |
---|
718 | /** |
---|
719 | * @brief Create LTG frame |
---|
720 | * |
---|
721 | * Function is typically called in the context of the LTG event callback. It creates a complete |
---|
722 | * 802.11 data frame with the extra LTG metadata in the payload. |
---|
723 | * |
---|
724 | */ |
---|
725 | |
---|
726 | int wlan_create_ltg_frame(u8* pkt, |
---|
727 | u8* addr1, |
---|
728 | u8* addr2, |
---|
729 | u8* addr3, |
---|
730 | u8 frame_control_2, |
---|
731 | u32 ltg_id){ |
---|
732 | u32 tx_length; |
---|
733 | ltg_packet_id_t* pkt_id; |
---|
734 | |
---|
735 | if( pkt == NULL ) return WLAN_FAILURE; |
---|
736 | |
---|
737 | tx_length = wlan_create_data_frame_header(pkt, |
---|
738 | addr1, |
---|
739 | addr2, |
---|
740 | addr3, |
---|
741 | frame_control_2); |
---|
742 | |
---|
743 | // Prepare the MPDU LLC header |
---|
744 | pkt_id = (ltg_packet_id_t*)(pkt + sizeof(mac_header_80211)); |
---|
745 | |
---|
746 | (pkt_id->llc_hdr).dsap = LLC_SNAP; |
---|
747 | (pkt_id->llc_hdr).ssap = LLC_SNAP; |
---|
748 | (pkt_id->llc_hdr).control_field = LLC_CNTRL_UNNUMBERED; |
---|
749 | bzero((void *)((pkt_id->llc_hdr).org_code), 3); // Org Code 0x000000: Encapsulated Ethernet |
---|
750 | (pkt_id->llc_hdr).type = LLC_TYPE_WLAN_LTG; |
---|
751 | |
---|
752 | pkt_id->unique_seq = 0; //make sure this is filled in via the dequeue callback |
---|
753 | pkt_id->ltg_id = ltg_id; |
---|
754 | |
---|
755 | // LTG packets always have LLC header, LTG payload id, plus any extra payload requested by user |
---|
756 | tx_length += ((sizeof(ltg_packet_id_t))); |
---|
757 | |
---|
758 | return tx_length; |
---|
759 | } |
---|
760 | |
---|
761 | #endif //WLAN_SW_CONFIG_ENABLE_LTG |
---|