1 /*
2  * Copyright 2018 Oticon A/S
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #include "p2G4_func_queue.h"
7 #include "bs_oswrap.h"
8 #include "bs_tracing.h"
9 
10 /*
11  * Array with one element per device interface
12  * Each interface can have 1 function pending
13  */
14 static fq_element_t *f_queue = NULL;
15 
16 static uint32_t next_d = 0;
17 static uint32_t n_devs = 0;
18 
19 static queable_f fptrs[N_funcs];
20 
fq_init(uint32_t n_dev)21 void fq_init(uint32_t n_dev){
22   f_queue = bs_calloc(n_dev, sizeof(fq_element_t));
23   n_devs = n_dev;
24 
25   for (int i = 0 ; i < n_devs; i ++) {
26     f_queue[i].time = TIME_NEVER;
27     f_queue[i].f_index = State_None;
28   }
29 }
30 
fq_register_func(f_index_t type,queable_f fptr)31 void fq_register_func(f_index_t type, queable_f fptr) {
32   fptrs[type] = fptr;
33 }
34 
35 /**
36  * Find the next function which should be executed,
37  * Based on the following order, from left to right:
38  *  time (lower first), function index (higher first), device number (lower first)
39  * TOOPT: The whole function queue is implemented in a simple/naive way,
40  *        which is perfectly for simulations with a few devices.
41  *        But, if there is many devices, this would be quite slow.
42  */
fq_find_next()43 void fq_find_next(){
44   bs_time_t chosen_f_time;
45   next_d = 0;
46   chosen_f_time = f_queue[0].time;
47 
48   for (int i = 1; i < n_devs; i ++) {
49     fq_element_t *el = &f_queue[i];
50     if (el->time < chosen_f_time) {
51       next_d = i;
52       chosen_f_time = el->time;
53       continue;
54     } else if (el->time == chosen_f_time) {
55       if (el->f_index > f_queue[next_d].f_index) {
56         next_d = i;
57         chosen_f_time = el->time;
58         continue;
59       }
60     }
61   }
62 }
63 
64 /**
65  * Add a function for dev_nbr to the queue and reorder it
66  */
fq_add(bs_time_t time,f_index_t index,uint32_t dev_nbr)67 void fq_add(bs_time_t time, f_index_t index, uint32_t dev_nbr) {
68   fq_element_t *el = &f_queue[dev_nbr];
69   el->time = time;
70   el->f_index = index;
71 }
72 
73 /**
74  * Remove an element from the queue and reorder it
75  */
fq_remove(uint32_t d)76 void fq_remove(uint32_t d){
77   f_queue[d].f_index = State_None;
78   f_queue[d].time = TIME_NEVER;
79 }
80 
81 /**
82  * Call the next function in the queue
83  * Note: The function itself is left in the queue.
84  */
fq_call_next()85 void fq_call_next(){
86   fptrs[f_queue[next_d].f_index](next_d);
87 }
88 
89 /**
90  * Get the time of the next element of the queue
91  */
fq_get_next_time()92 bs_time_t fq_get_next_time(){
93   return f_queue[next_d].time;
94 }
95 
fq_free()96 void fq_free(){
97   if ( f_queue != NULL )
98     free(f_queue);
99 }
100