This framework employs a simple and tiny
cyclic executive, non-preemtive, cooperative scheduler
to manage task execution.
The following loosely lists requirements, constraints, features and goals.
- Cyclic executive, cooperative (non-preemptive/run-to-completion), monotonic (fixed priorities) scheduling of multiple tasks in embedded systems for real-time applications
- Preemption can be achieved through hardware interrupts
- Provides an optional facility (separate module) to handle nested critical sections
- Timing of tasks (via task lists) is predefined at compile time
- Switch between multiple task lists at run time
- Tasks within a task list can individually be enabled and disabled at run time
- Timers can be created with one-shot tasks whos time stamp of last task run is updated when enbling (starting) them
- Each task can individually be scheduled by its period and its offset to other tasks
- Task deadline overrun detection/indication with (single) counter
- Optional task deadline overrun (recovery) action with custom hook
- Deadline of each task can individually be defined at compile time
- Disabled tasks are not run but their last run indication is still updated to maintain schedulability
- To eliminate drift in task invocation over time, tasks update their last run to the "ideal" invocation time (that is, the beginning of their period/time slot)
- If a task--for whatever reason--is not executed within its period, it will run "normally" within its next period (without impact on the schedule of other tasks)
- Works flawlessly on rollover of its relative system time tick source with unsigned integer type that it is connected to
- Framework design
- Deployment in embedded systems
- Code implementation in the C programming language ("C99", ISO/IEC 9899:1999)
- Interfaces with the application software through task lists and with the MCU hardware (for the relative system time tick) through a pointer to function--both user-provided
- "Design by Contract" approach via "dynamic" assertions (
assert(...)
) - Low impact on technical budgets
- Low CPU utilization
- Small memory footprint in ROM (text, data) and RAM (data, heap, stack)
- Runs (also) well on "small" MCUs (e.g., AVR ATmega328P/Arduino Uno)
- Quality model
- "Simple" (low complexity of software architecture and detailed design, essential features only)
- Modular
- Re-usable
- Portable
- Unit tested with 100 % coverage (LOC executed, branches taken, functions called)
- Defined quality metrics (see table below)
- MISRA-C:2012 compliant
- Static code analysis pass
- No dynamic memory allocation (via
malloc()
or similar) - SCM via Git with Semantic Versioning
- Well documented (from requirements over architecture to detailed design), using Doxygen, Markdown, custom diagrams, UML
- Traceability from requirements specification to implementation by transitivity
Quality metrics:
Metric | Target |
---|---|
No. of parameters/arguments (per func.) | <= 6 |
No. of instructions (per func.) | <= 60 |
No. of nested control structures (per func.) | <= 5 |
Cyclomatic complexity number (per func.) | <= 10 |
Comment rate (per file) | >= 20 % |
Unit test (decision) coverage | = 100 % |
Timers can be created by using a one-shot task that deactives itself at the end of its execution. Its period then defines the timer’s timing. When enabling such a task (i.e., starting the timer), its time stamp of last task run must be updated.
This project aims to adhere to the following guidelines (with exceptions):
- The Power of Ten - Rules for Developing Safety Critical Code (NASA/JPL; G. J. Holzmann)
- MISRA C:2012 - Guidelines for the use of the C language in critical systems
If necessary, deviations from the guidelines are allowed but must be justified and documented by means of inline comments.
Furthermore, the style is only loosely defined:
New added code should use the same style (i.e. "look similar") as the already existing code base.
Some remarks on the non-obvious points of this style convention:
- Files are divided into an "attributes" and "operations" section (just like classes in a UML class diagram)
#include
s are placed in a module’s implementation (*.c
) file(s), except when they include header files external to the project (e.g. libc) or if a module already uses another project-internal API in its own API (in both exceptional cases those#include
s are then placed in the module’s header file)- Multiple instructions (ending with
;
) within a macro are enclosed in ado {...} while (false)
loop - The limit for line breaks is 80 characters (slight overshoots are acceptable if it increases readability and if used sparingly)
- Whitespace is inserted after control flow structure keywords (e.g.
if/for/while/switch/return (...)
) - Comments
- ... can be placed above one or multiple line(s) (code block), addressing all following line(s) until the next empty line or lesser indentation level
- ... can be placed at the end of a line, addressing this line only
- ... can be placed below a long line with one additional indentation level to address this one long line in a code block where a comment does not fit at the end of the line
- Far away closing brackets/keywords of control structures are commented to
indicate to what they belong (e.g.
#endif /* MODULENAME_H */
) - API functions/macros/variables ("globals") etc. are prefixed with their
module’s (abbreviated) name +
_
;
if the project is intended to be included in another project (e.g. the project is a library or framework), the prefix also starts with up to 3 characters that abbreviate the project name - Private, file-scope (
static
) variables are prefixed withpv_
- Pointers are prefixed with
p_
- Types are suffixed with
_t
- In object-oriented code, the pointer argument to an object of a class’
function is named
me
This project uses a simple topic branch Git workflow. The only permanently existing branches are "develop" (development status; unstable) and "master" (release status; stable). New development efforts are done in separate topic branches, which are then merged into develop once ready. For releases, the "develop" branch is then merged into "master". Fast-forward merges are preferred, if possible.