WarpTwin
Documentation for WarpTwin models and classes.
Loading...
Searching...
No Matches
TableScheduler.hpp
Go to the documentation of this file.
1/******************************************************************************
2* Copyright (c) ATTX INC 2025. All Rights Reserved.
3*
4* This software and associated documentation (the "Software") are the
5* proprietary and confidential information of ATTX, INC. The Software is
6* furnished under a license agreement between ATTX and the user organization
7* and may be used or copied only in accordance with the terms of the agreement.
8* Refer to 'license/attx_license.adoc' for standard license terms.
9*
10* EXPORT CONTROL NOTICE: THIS SOFTWARE MAY INCLUDE CONTENT CONTROLLED UNDER THE
11* INTERNATIONAL TRAFFIC IN ARMS REGULATIONS (ITAR) OR THE EXPORT ADMINISTRATION
12* REGULATIONS (EAR99). No part of the Software may be used, reproduced, or
13* transmitted in any form or by any means, for any purpose, without the express
14* written permission of ATTX INC.
15******************************************************************************/
16/*
17Tabular scheduler header file
18
19Author: Alex Reynolds
20*/
21#ifndef SCHEDULES_TABLE_SCHEDULER_H
22#define SCHEDULES_TABLE_SCHEDULER_H
23
24#include "flight/Scheduler.h"
25#include "flight/OS.h"
28#include "flight/appmacros.h"
30
31namespace warpos {
53 template <int16 N>
54 class TableScheduler : public Scheduler {
55 public:
58 TableScheduler(OS& os);
59
61
64 virtual int16 startup() override;
65
69 virtual int16 step(const clockwerk::Time& step_val) override;
70
75 virtual int16 run() override;
76
81 virtual int16 registerApp(App& app, int16 slot) override;
82
86 virtual int16 unregisterApp(int16 slot) override;
87
90 uint8 taskFailures() {return _tlm_error.error_count;}
91
94 uint16 currentSlot() {return _current_slot;}
95
98 uint8 scheduleExceedances() {return _tlm_overrun.overrun_count;}
99
103
107
111
115 protected:
119 uint16 _getNextSlot(uint16 current_slot);
120
123
126
129
130 int16 _current_slot = 0;
131 int16 _end_slot = 0;
134
137
138 // Variables to hold telemetry and logging stuff
139 char _print_buf[200];
142 };
143
144 template<int16 N>
146 : Scheduler(), _os(os) {
147 // Assert that our schedule has 1000 or fewer slots
148 static_assert(N <= 1000, "Table scheduler cannot be broken into more than 1,000 slots");
149
150 _step_size.setTime(0, _nsec_per_slot);
151
152 // Assign nullptrs to every slot to start
153 for(uint16 i = 0; i < N; i++) {
154 _schedule_array[i] = nullptr;
155 }
156
157 // Register telemetry
158 _tlm_error.error_count = 0;
159 _tlm_overrun.overrun_count = 0;
160 }
161
162 template<int16 N>
163 int16 TableScheduler<N>::registerApp(App& app, int16 slot) {
164 // Check that our slot lies on our table
165 if(slot >= N) {
166 LOG_SCHEDULER(LOG_ERROR, "Schedule slot exceeds table length. App:")
168 return ERROR_INVALID_RANGE;
169 }
170 // And check that our slot is not already occupied
171 if(_schedule_array[slot] != nullptr) {
172 LOG_SCHEDULER(LOG_ERROR, "Schedule slot is not empty. Registering App:")
174 LOG_SCHEDULER(LOG_ERROR, "Occupied by:")
177 }
178
179 LOG_SCHEDULER(LOG_DEBUG, "Successfully registered app in table scheduler. Name:")
181
182 _schedule_array[slot] = &app;
183 return NO_ERROR;
184 }
185
186 template<int16 N>
188 if(slot >= N) {
189 return ERROR_INVALID_RANGE;
190 }
191
192 LOG_SCHEDULER(LOG_DEBUG, "Successfully unregistered app in table scheduler. Name:")
194
195 _schedule_array[slot] = nullptr;
196 return NO_ERROR;
197 }
198
199 template<int16 N>
201 for(uint16 i = 0; i < N; i++) {
202 if(_schedule_array[i] != nullptr) {
203 if(!_schedule_array[i]->isStarted()) {
204 _error = _schedule_array[i]->startup();
205
206 // Catch, log, and telemeter errors
207 if(_error) {
208 sprintf(_print_buf, "Error caught in startup on task %s / slot %i / code %i", _schedule_array[_current_slot]->name(), _current_slot, _error);
210
211 _tlm_error.app_apid = _schedule_array[i]->apid();
212 _tlm_error.error_code = _error;
213 _tlm_error.error_count++;
214 _tlm_error.schedule_slot = -1;
215 if(_exc_ptr) {
216 _exc_ptr->sendStoreTlm(_tlm_error);
217 }
218 }
219 }
220 }
221 }
222
223 return NO_ERROR;
224 }
225
226 template<int16 N>
228 // Calculate our current schedule slot
229 _current_slot = ref_time.nsec()/_nsec_per_slot;
230
231 // If the scheduler has not initialized and our current step is not 0 (i.e. start) we want to
232 // wait for slot 0 to come around so we are aligned to a second time boundary.
235 }
237
238 // Run our schedule slot if it is occupied
239 if(_schedule_array[_current_slot] == nullptr) {
240 return NO_ERROR;
241 } else {
243 }
244
245 // Catalog our error if our task failed
246 if(_error) {
247 sprintf(_print_buf, "Error caught in run on task %s / slot %i / code %i", _schedule_array[_current_slot]->name(), _current_slot, _error);
249
250 _tlm_error.app_apid = _schedule_array[_current_slot]->apid();
251 _tlm_error.error_code = _error;
252 _tlm_error.error_count++;
253 _tlm_error.schedule_slot = _current_slot;
254 if(_exc_ptr) {
255 _exc_ptr->sendStoreTlm(_tlm_error);
256 }
257 }
258
259 // And check for overrun on our step
260 _end_slot = _os.systemTime().nsec()/_nsec_per_slot;
261
262 // If our end slot is not our current slot, we need to mark
263 // our overrun
264 if(_end_slot != _current_slot) {
265 // Get the index of the slot after current
266 int idx = _current_slot;
267
268 // Loop until idx matches end slot. This is safe (cannot go infinite) because end slot must live in
269 // our slot range and we circle back, so at some point we must reach end slot
270 while(idx != _end_slot) {
271 idx++; // Increment
272 if(idx == N) {
273 idx = 0; // Loop back to 0 if we hit N
274 }
275
276 if(_schedule_array[idx] != nullptr) {
277 sprintf(_print_buf, "Detected overrun on task %s / slot %i / return slot %i", _schedule_array[_current_slot]->name(), _current_slot, _end_slot);
279
280 _tlm_overrun.app_apid = _schedule_array[_current_slot]->apid();
281 _tlm_overrun.schedule_slot = _current_slot;
282 _tlm_overrun.terminating_slot = _end_slot;
283 _tlm_overrun.overrun_count++;
284 if(_exc_ptr) {
285 _exc_ptr->sendStoreTlm(_tlm_overrun);
286 }
287 return NO_ERROR;
288 }
289 }
290 }
291
292 return NO_ERROR;
293 }
294
295 template<int16 N>
297 // Calculate our first start time. We should start on a system time rollover boundary, so here
298 // get our os time and set the next slot start to be at an increment from our current time on
299 // slot 0
300 clockwerk::Time current_time = _os.systemTime();
301 clockwerk::Time next_slot_start(current_time.sec() + 1, 0);
302
303 while(!_is_terminated) {
304 // Block until we reach our next slot time
305 while(current_time < next_slot_start) {
306 current_time = _os.systemTime();
307 }
308
309 // Step our scheduler
310 step(current_time);
311
312 // Figure out our next schedule slot start time and set us up to wait for that
313 _os.systemTime().add(_step_size, next_slot_start);
314 next_slot_start.setTime(next_slot_start.sec(),
315 _nsec_per_slot*(next_slot_start.nsec()/_nsec_per_slot));
316
317 // And OS sleep this thread until we're ready to start again. We'll still block
318 // until start, but this yields to other tasks outside the schedule which
319 // may want to run
320 _os.delayUntil(next_slot_start);
321 }
322
323 return NO_ERROR;
324 }
325
326 template<int16 N>
327 uint16 TableScheduler<N>::_getNextSlot(uint16 current_slot) {
328 int16 next = current_slot + 1;
329 if(next == N) {
330 return 0;
331 }
332 return next;
333 }
334}
335
336#endif
#define LOG_SCHEDULER(LEVEL, MESSAGE)
Definition appmacros.h:76
const char * name() const
Getter and setter for object name.
Definition GraphTreeObject.h:135
Wrapper to manage and convert time as timespce.
Definition Time.h:53
void setTime(const struct timespec &t)
Function to set the time in the time object.
Definition Time.h:67
int64 nsec() const
Get time nanoseconds.
Definition Time.h:63
int64 sec() const
Get time seconds.
Definition Time.h:61
Base app class for derived implementation.
Definition App.h:55
Holds all os-specific interfaces.
Definition OS.h:51
Scheduler()
Constructor for the scheduler.
Definition Scheduler.cpp:21
FlightExecutive * _exc_ptr
Pointer to the executive which may optionally be registered with scheduler.
Definition Scheduler.h:87
bool _is_terminated
Flag to indicate whether the scheduler is terminated.
Definition Scheduler.h:84
virtual int16 startup() override
Start the table scheduler.
Definition TableScheduler.hpp:200
uint8 scheduleExceedances()
Get the number of schedule exceedances.
Definition TableScheduler.hpp:98
uint8 taskFailures()
Get number of task failures.
Definition TableScheduler.hpp:90
char _print_buf[200]
Definition TableScheduler.hpp:139
TableScheduler(OS &os)
Constructor for the scheduler.
Definition TableScheduler.hpp:145
uint16 currentSlot()
Get the current schedule slot (executed previous step).
Definition TableScheduler.hpp:94
uint32 _nsec_per_slot
The number of nsec allocated per slot.
Definition TableScheduler.hpp:132
const App * lastAppRun()
Get handle to the last app run.
Definition TableScheduler.hpp:114
tlm_executive_schedule_overrun _tlm_overrun
Definition TableScheduler.hpp:141
virtual int16 registerApp(App &app, int16 slot) override
Register an app with the table scheduler.
Definition TableScheduler.hpp:163
int16 _end_slot
The slot where schedule run ended.
Definition TableScheduler.hpp:131
App * _schedule_array[N]
Array to hold the actual schedule slot.
Definition TableScheduler.hpp:125
uint16 _getNextSlot(uint16 current_slot)
Return schedule slot after current one.
Definition TableScheduler.hpp:327
int16 _current_slot
The current schedule slot to execute.
Definition TableScheduler.hpp:130
~TableScheduler()
Definition TableScheduler.hpp:60
clockwerk::Time _step_size
The step size as a clockwerk time.
Definition TableScheduler.hpp:133
OS & _os
Handle to the os from which we pull system time.
Definition TableScheduler.hpp:122
virtual int16 step(const clockwerk::Time &step_val) override
Function to execute a single table schedule slot.
Definition TableScheduler.hpp:227
const tlm_executive_schedule_overrun & lastExceedance()
Return the last task to exceed its slot.
Definition TableScheduler.hpp:102
const clockwerk::Time & timePerSlot()
Get the time per slot.
Definition TableScheduler.hpp:110
virtual int16 run() override
Function to run the scheduler until pre-determined end conditions identified/calculated by the schedu...
Definition TableScheduler.hpp:296
int16 _error
Variable to catch errors out of runs.
Definition TableScheduler.hpp:136
virtual int16 unregisterApp(int16 slot) override
Function to unregister a certain schedule slot.
Definition TableScheduler.hpp:187
bool _scheduler_initialized
Flag indicating whether time has been initialized.
Definition TableScheduler.hpp:128
const tlm_executive_app_error & lastTaskFailure()
Get handle to record of last failure.
Definition TableScheduler.hpp:106
tlm_executive_app_error _tlm_error
Definition TableScheduler.hpp:140
#define NO_ERROR
Error code in the case where matrix math executed successfully.
Definition clockwerkerrors.h:34
#define ERROR_TREE_NAME_EXISTS
Definition clockwerkerrors.h:74
#define ERROR_INVALID_RANGE
Definition clockwerkerrors.h:53
#define WARN_SCH_WAIT_FOR_INIT
Warning in case where sim scheduler is waiting for initialization time.
Definition flighterrors.h:150
@ LOG_ERROR
No output at all.
Definition flighterrors.h:161
@ LOG_DEBUG
Definition flighterrors.h:164
const uint32 NSEC_PER_SEC_I
Definition Time.h:41
Definition DeadReckon.cpp:20
Packet for app errors.
Definition tlm_Executive.h:49
Packet for schedule overrun.
Definition tlm_Executive.h:64