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 fine 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         continue;
58       }
59     }
60   }
61 }
62 
63 /**
64  * Add a function for dev_nbr to the queue and reorder it
65  */
fq_add(bs_time_t time,f_index_t index,uint32_t dev_nbr)66 void fq_add(bs_time_t time, f_index_t index, uint32_t dev_nbr) {
67   fq_element_t *el = &f_queue[dev_nbr];
68   el->time = time;
69   el->f_index = index;
70 }
71 
72 /**
73  * Remove an element from the queue and reorder it
74  */
fq_remove(uint32_t d)75 void fq_remove(uint32_t d){
76   f_queue[d].f_index = State_None;
77   f_queue[d].time = TIME_NEVER;
78 }
79 
80 /**
81  * Call the next function in the queue
82  * Note: The function itself is left in the queue.
83  */
fq_call_next()84 void fq_call_next(){
85   fptrs[f_queue[next_d].f_index](next_d);
86 }
87 
88 /**
89  * Get the time of the next element of the queue
90  */
fq_get_next_time()91 bs_time_t fq_get_next_time(){
92   return f_queue[next_d].time;
93 }
94 
fq_free()95 void fq_free(){
96   if ( f_queue != NULL )
97     free(f_queue);
98 }
99