1 /* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
2 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <virtphy/virt_l1_sched.h>
22 #include <osmocom/core/linuxlist.h>
23 #include <virtphy/virt_l1_model.h>
24 #include <virtphy/logging.h>
29 * @brief Start scheduler thread based on current gsm time from model
31 static int virt_l1_sched_start(struct l1_model_ms
*ms
, struct gsm_time time
)
33 virt_l1_sched_sync_time(ms
, time
, 1);
38 * @brief Clear scheduler queue and completely restart scheduler.
40 int virt_l1_sched_restart(struct l1_model_ms
*ms
, struct gsm_time time
)
42 virt_l1_sched_stop(ms
);
43 return virt_l1_sched_start(ms
, time
);
47 * @brief Sync scheduler with given time.
49 void virt_l1_sched_sync_time(struct l1_model_ms
*ms
, struct gsm_time time
, uint8_t hard_reset
)
51 ms
->state
.current_time
= time
;
55 * @brief Stop the scheduler thread and cleanup mframe items queue
57 void virt_l1_sched_stop(struct l1_model_ms
*ms
)
59 struct virt_l1_sched_mframe_item
*mi_next
, *mi_tmp
;
61 /* Empty tdma and mframe sched items lists */
62 llist_for_each_entry_safe(mi_next
, mi_tmp
, &ms
->state
.sched
.mframe_items
, mframe_item_entry
) {
63 struct virt_l1_sched_tdma_item
*ti_next
, *ti_tmp
;
65 llist_for_each_entry_safe(ti_next
, ti_tmp
, &mi_next
->tdma_item_list
, tdma_item_entry
) {
66 talloc_free(ti_next
->msg
);
67 llist_del(&ti_next
->tdma_item_entry
);
69 llist_del(&mi_next
->mframe_item_entry
);
75 * @brief Handle all pending scheduled items for the current frame number.
77 void virt_l1_sched_execute(struct l1_model_ms
*ms
, uint32_t fn
)
79 struct l1_state_ms
*l1s
= &ms
->state
;
80 struct virt_l1_sched_mframe_item
*mi_next
, *mi_tmp
;
81 uint8_t hyperframe_restart
= fn
< l1s
->sched
.last_exec_fn
;
83 llist_for_each_entry_safe(mi_next
, mi_tmp
, &l1s
->sched
.mframe_items
, mframe_item_entry
) {
84 /* execute all registered handler for current mf sched item */
85 uint8_t exec_now
= mi_next
->fn
<= fn
|| (hyperframe_restart
&& mi_next
->fn
> l1s
->sched
.last_exec_fn
);
86 /* break loop, as we have an ordered list in case the hyperframe had not been reset */
87 uint8_t break_now
= mi_next
->fn
> fn
&& !hyperframe_restart
;
90 struct virt_l1_sched_tdma_item
*ti_next
, *ti_tmp
;
91 /* run through all scheduled tdma sched items for that frame number */
92 llist_for_each_entry_safe(ti_next
, ti_tmp
, &mi_next
->tdma_item_list
,
94 /* exec tdma sched item's handler callback */
95 /* TODO: we do not have a TDMA scheduler currently and execute
96 * all scheduled tdma items here at once */
97 ti_next
->handler_cb(ms
, mi_next
->fn
, ti_next
->ts
, ti_next
->msg
);
98 /* remove handled tdma sched item */
99 llist_del(&ti_next
->tdma_item_entry
);
100 talloc_free(ti_next
);
102 /* remove handled mframe sched item */
103 llist_del(&mi_next
->mframe_item_entry
);
104 talloc_free(mi_next
);
110 l1s
->sched
.last_exec_fn
= fn
;
114 * @brief Schedule a msg to the given framenumber and timeslot.
116 void virt_l1_sched_schedule(struct l1_model_ms
*ms
, struct msgb
*msg
, uint32_t fn
, uint8_t ts
,
117 virt_l1_sched_cb
*handler_cb
)
119 struct virt_l1_sched_mframe_item
*mi_next
= NULL
, *mi_tmp
= NULL
, *mi_fn
= NULL
;
120 struct virt_l1_sched_tdma_item
*ti_new
= NULL
;
122 llist_for_each_entry_safe(mi_next
, mi_tmp
, &ms
->state
.sched
.mframe_items
, mframe_item_entry
) {
123 if (mi_next
->fn
== fn
) {
126 } else if (mi_next
->fn
> fn
)
130 /* list did not contain mframe item with needed fn */
131 mi_fn
= talloc_zero(ms
, struct virt_l1_sched_mframe_item
);
133 INIT_LLIST_HEAD(&mi_fn
->tdma_item_list
);
134 llist_add_tail(&mi_fn
->mframe_item_entry
, &mi_next
->mframe_item_entry
);
137 ti_new
= talloc_zero(mi_fn
, struct virt_l1_sched_tdma_item
);
139 ti_new
->handler_cb
= handler_cb
;
141 /* simply add at end, no ordering for tdma sched items currently */
142 llist_add_tail(&ti_new
->tdma_item_entry
, &mi_fn
->tdma_item_list
);
143 /* TODO: ordered insert needed if tdma scheduler should be implemented */