forked from dastcvi/StratoCore
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathStratoScheduler.cpp
182 lines (149 loc) · 4.62 KB
/
StratoScheduler.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
* StratoScheduler.cpp
* Author: Alex St. Clair
* Created: June 2019
*
* This file implements a class to perform scheduling through the
* StratoCore based on GPS time from the Zephyr.
*/
#include "StratoScheduler.h"
#include "StratoGroundPort.h"
StratoScheduler::StratoScheduler()
{
schedule_size = 0;
schedule_top = NULL;
}
uint8_t StratoScheduler::CheckSchedule()
{
uint8_t action = NO_SCHEDULED_ACTION;
// if it's time for the top action, set it and remove it from the queue
if (schedule_size > 0 && schedule_top->time <= now()) {
action = schedule_top->action;
SchedulePop();
}
return action;
}
bool StratoScheduler::AddAction(uint8_t action, time_t seconds_from_now)
{
// enforce a software size limit to avoid accidentally filling memory
if (schedule_size >= MAX_SCHEDULE_SIZE) {
log_error("Schedule queue full");
return false;
}
// calculate the time_t value given the current time, place on the queue
return SchedulePush(action, now() + seconds_from_now, false);
}
bool StratoScheduler::AddAction(uint8_t action, TimeElements exact_time)
{
// enforce a software size limit to avoid accidentally filling memory
if (schedule_size >= MAX_SCHEDULE_SIZE) {
log_error("Schedule queue full");
return false;
}
// place on the queue
return SchedulePush(action, makeTime(exact_time), true);
}
void StratoScheduler::ClearSchedule()
{
while (schedule_size > 0) {
SchedulePop();
}
}
void StratoScheduler::PrintSchedule()
{
ScheduleItem_t * itr = schedule_top;
// adjust each item
while (itr != NULL) {
debug_serial->print(itr->action);
debug_serial->print(",");
debug_serial->print(itr->time);
debug_serial->print(",");
debug_serial->println(itr->time-now());
itr = itr->next;
}
}
void StratoScheduler::UpdateScheduleTime(int32_t seconds_adjustment)
{
ScheduleItem_t * itr = schedule_top;
// adjust each item
while (itr != NULL) {
// adjust only if scheduled relatively
if (!itr->exact_time) {
itr->time += seconds_adjustment;
}
itr = itr->next;
}
}
// ------- schedule queue functions -------
ScheduleItem_t * StratoScheduler::GetFreeItem()
{
// if we know the schedule is full, return NULL
if (schedule_size == MAX_SCHEDULE_SIZE) return NULL;
// iterate through and find a free item
int i = 0;
for (i = 0; i < MAX_SCHEDULE_SIZE; i++) {
if (!item_array[i].in_use) break; // found a free one
}
// make sure there wasn't some unexpected error
if (item_array[i].in_use) {
return NULL;
} else {
return &(item_array[i]);
}
}
bool StratoScheduler::SchedulePush(uint8_t action, time_t schedule_time, bool exact)
{
if (schedule_size >= MAX_SCHEDULE_SIZE) return false;
// create the new action
ScheduleItem_t * new_item = GetFreeItem();
// check that it's good
if (new_item == NULL) return false;
// set the values for the new item
new_item->action = action;
new_item->exact_time = exact;
new_item->time = schedule_time;
new_item->next = NULL;
new_item->prev = NULL;
new_item->in_use = true;
schedule_size++;
// if empty, create in place
if (schedule_top == NULL) {
schedule_top = new_item;
return true;
}
// create an iterator for moving through the queue, starting with the first element
ScheduleItem_t * cur = schedule_top;
// move through the queue until either the end is reach, or the insertion spot is found
while (new_item->time > cur->time && cur->next != NULL) {
cur = cur->next;
}
// place
if (new_item->time <= cur->time) {
if (cur->prev == NULL) {
schedule_top = new_item;
cur->prev = new_item;
new_item->next = cur;
} else {
new_item->prev = cur->prev;
cur->prev->next = new_item;
cur->prev = new_item;
new_item->next = cur;
}
} else {
cur->next = new_item;
new_item->prev = cur;
}
return true;
}
// remove and delete the first item
void StratoScheduler::SchedulePop()
{
if (schedule_size == 0) return;
ScheduleItem_t * tmp = schedule_top;
schedule_top = tmp->next;
if (NULL != schedule_top) schedule_top->prev = NULL;
tmp->in_use = false;
tmp->prev = NULL;
tmp->next = NULL;
schedule_size--;
}