|
1 | 1 | # ArduinoProcessScheduler |
2 | | -An Arduino Object Oriented Cooperative Process Scheduler to Replace Them All |
| 2 | +An Cooperative Arduino Object Oriented Cooperative Process Scheduler to Replace Them All |
3 | 3 |
|
4 | 4 | ## Features |
5 | 5 | - Fine Grained Control Over How Often a Process Runs (Periodically, Iterations, or as Often as Possible) |
6 | | -- Exception Handling (wait what?!) |
7 | | -- Atomicity Support |
| 6 | +- Interrupt safe (add, disable, destroy, etc.. processes from interrupt routines) |
| 7 | +- Process concurrency protection (Guarantees your process to be in a valid state when performing actions on it) |
8 | 8 | - Dynamically Add/Remove and Enable/Disable Processes |
9 | | -- Automatic Process Monitoring Statistics (Automatically calculates % CPU time for service) |
10 | | -- Truly object oriented (a Process is no longer just a callback function like other libraries) |
11 | | - |
12 | | -## Basic Usage |
13 | | -There are two classes to worry about: `Scheduler` and `Process`. |
14 | | - |
15 | | -### Class `Scheduler`: |
16 | | -A `Scheduler` oversees and manages `Processes`. There should only be one `Scheduler` in your project. Inside of `void loop()`, the scheduler's `run()` method should be repeatedly called. |
17 | | - |
18 | | -### Class `Process`: |
19 | | -A service can be thought of as job or a task that needs to be run at certain times. Each Process had be scheduled to run Periodically |
20 | | -Constantly, or Periodically/Constantly with a set number of run iterations. |
21 | | - |
22 | | -Each project will have multiple services, here are some examples of `Processes`: |
23 | | - - A Process to handle user input |
24 | | - - A Process to run a basic webserver |
25 | | - - A Process to update a display |
26 | | - |
27 | | -`Process` is a base class that should be extended to handle your particular Process (such as the examples mentioned above). The scheduler's will call the following virtual function as an entry point when it is time for you service to run: |
28 | | -``` |
29 | | - virtual void service(); |
30 | | -``` |
31 | | -From here your `service()` routine is expected to be non-blocking, and return from `service()` as soon as possible (that means no long `delay()`'s). Fortunately, since your service routine is a method inside a class, you can store the state of your service in custom class attributes before returning, so you know where you left off when the scheduler calls your Process again. As soon you return from `service()`, control is transferred back to the Scheduler (it will also be transferred back if you raise an Exception--advanced). |
32 | | - |
33 | | -Additionally, each Process inherits the following virtual functions which are called by the `Scheduler` at the appropriate times. Note you are guaranteed that only one of these methods will exist in the call stack at once, even if an interrupt fires trying to modify this Process at the same time (such as with `add()`, `destroy()`, `enable()`, or `disable()`). This also includes the `service()` method mentioned above. You do not have to worry about concurrency! |
34 | | - |
35 | | -**Thanks to the magic of virtual functions, you don't have to impliment any of these unless your particular Process needs them:** |
36 | | -``` |
37 | | - virtual void setup() |
38 | | - virtual void cleanup() |
39 | | -
|
40 | | - virtual void onEnable() |
41 | | - virtual void onDisable() |
42 | | -
|
43 | | - virtual void overScheduledHandler(uint32_t behind) |
44 | | -``` |
45 | | - |
46 | | -#### `setup()` |
47 | | -This method is called by the scheduler when the Process is being added to the scheduling chain with `add()`, it is guaranteed to only be called once when a Process not part of the scheduling chain is being added (`add()`). Keep in mind it will still be called if the Process is removed from the scheduling chain with `destroy()`, then added again with `add()`. |
48 | | - |
49 | | -#### `cleanup()` |
50 | | -This is only called once when a `Process` part of the scheduling chain is being removed from the scheduling chain with `destroy()`. This method should undo whatever was done in `setup()`. You are guaranteed it will not be called unless `setup()` was called previously. |
51 | | - |
52 | | -#### `onEnable()` |
53 | | -This method is called only once when a disabled task is being enabled with `enable()`. |
54 | | - |
55 | | -#### `onDisable()` |
56 | | -This method is called only once when a enabled task is being disabled with `disable()`. You are guaranteed it will not be called unless `onEnable()` was called previously. It should undo whatever `onEnable()` did. |
57 | | - |
58 | | -#### `overScheduledHandler(uint32_t behind)` |
59 | | -This method is called if the scheduler can not meet the current set period for the Process and is falling behind. The scheduler will pass in variable `behind` containing how many milliseconds (or microseconds) behind the scheduler is with this task. Inside this method might be a good time increase the period between when this task is run, then call `resetSchedulerWarning()` to clear the warning. |
60 | | - |
61 | | - |
62 | | -## API |
63 | | -### `Scheduler` Methods: |
64 | | - |
65 | | - |
66 | | - |
67 | | -#### Constructor |
68 | | -``` |
69 | | -Scheduler() |
70 | | -``` |
71 | | -Create a Scheduler object. |
72 | | - |
73 | | -**Returns:** `Scheduler` |
74 | | -___ |
75 | | - |
76 | | -#### run() |
77 | | -``` |
78 | | -run() |
79 | | -``` |
80 | | -This method runs one pass through the scheduler. It is the heart of the scheaduler, this method should be called repeatedly inside of `void loop()` |
81 | | - |
82 | | -**Returns:** `void` |
83 | | -___ |
84 | | - |
85 | | - |
86 | | -#### getID() |
87 | | -``` |
88 | | -getID(Process &service) |
89 | | -``` |
90 | | -Get the unique id for the service. Same as `service.getID()`. |
91 | | - |
92 | | -**Returns:** `uint8_t` |
93 | | -___ |
94 | | - |
95 | | -#### isRunningProcess() |
96 | | -``` |
97 | | -isRunningProcess(Process &service) |
98 | | -``` |
99 | | -Determine if the scheduler is in the middle of running this service. Same as calling `service.isRunningProcess()` |
100 | | - |
101 | | -**Returns:** `bool` |
102 | | -___ |
103 | | - |
104 | | -#### isEnabled() |
105 | | -``` |
106 | | -isEnabled(Process &service) |
107 | | -``` |
108 | | -Determines if this service is enabled. Same as calling `service.isEnabled()` |
109 | | - |
110 | | -**Returns:** `bool` |
111 | | -___ |
112 | | - |
113 | | -#### getCurrProcess() |
114 | | -``` |
115 | | -getCurrProcess() |
116 | | -``` |
117 | | -Get pointer to the current service being run by the scheduler. Return NULL if no service being currently run. |
118 | | - |
119 | | -**Returns:** `Process*` |
120 | | -___ |
121 | | - |
122 | | -#### countProcesses() |
123 | | -``` |
124 | | -countProcesses(bool enabledOnly = true) |
125 | | -``` |
126 | | -Get number of servies in the scheduler's chain. If enabledOnly is true, only the enabled Processes will be counted. |
127 | | - |
128 | | -**Returns:** `uint8_t` |
129 | | -___ |
130 | | - |
131 | | -#### getCurrTS() |
132 | | -``` |
133 | | -getCurrTS() |
134 | | -``` |
135 | | -Returns the current internal timestamp. Either will be the same as `millis()` or `micros()` |
136 | | - |
137 | | -**Returns:** `uint32_t` |
138 | | -___ |
139 | | - |
140 | | - |
141 | | -#### add() |
142 | | -``` |
143 | | -add (Process &service)) |
144 | | -``` |
145 | | -Add the service to the scheduler, same as calling `service.add()`. Note, this will trigger the service's `setup()` method to fire. This method can only fail inside an interrupt routine, particularly when an interrupt interrupts any call to either `add()` or `remove()`. It will also fail if the service is already added. |
146 | | - |
147 | | -**Returns:** type `SchedulerAction`, `ACTION_NONE` on failure, `ACTION_SUCCESS` on success. |
148 | | -___ |
| 9 | +- Easily spawn new processes from within running processes |
| 10 | +- Automatic Process Monitoring Statistics (Automatically calculates % CPU time for process) |
| 11 | +- Truly object oriented (a Process is no longer just a callback function like other libraries, but its own object) |
| 12 | +- Exception Handling (wait what?!) |
| 13 | +- Scheduler can automatically terminate stuck processes |
149 | 14 |
|
150 | | -#### destroy() |
151 | | -``` |
152 | | -destroy (Process &service)) |
153 | | -``` |
154 | | -Remove the service from the scheduler. Same as calling `service.destroy()`. Note, this will trigger the service's `cleanup()` method to fire. If the service is not disabled, it will first call `disable()`. This method can only fail inside an interrupt routine, particularly when an interrupt interrupts any call to either `add()` or `remove()`. It will first try and QUEUE the request for later, before failing. It will also fail if the service is already destroyed. |
| 15 | +## Important Notes |
| 16 | +- This is not a preemptive scheduler! However by not being one, processes get to use the entire stack when they run. |
| 17 | +- This library was inspired from this [TaskScheduler](https://github.com/arkhipenko/TaskScheduler) library. |
155 | 18 |
|
156 | | -**Returns:** type `SchedulerAction`, `ACTION_NONE` on failure, `ACTION_QUEUED` on Queuing it, `ACTION_SUCCESS` on success. |
157 | | -___ |
| 19 | +## Supported Platfroms |
| 20 | +- AVR |
| 21 | +- ESP8266 (No exception handling or process timeouts) |
158 | 22 |
|
159 | | -#### enable() |
160 | | -``` |
161 | | -enable (Process &service)) |
162 | | -``` |
163 | | -Enable a service, same as calling `service.enable()`. Note, this will trigger the service's `onEnable()` method to fire. This method call will always succeed if it was not called on itself from a method inside of this service. If it was, the scheduler will queue the request. Also, the request will fail if the service is already enabled or is destroyed. |
164 | 23 |
|
165 | | -**Returns:** type `SchedulerAction`, `ACTION_NONE` on failure, `ACTION_QUEUED` on Queuing it, `ACTION_SUCCESS` on success. |
166 | | -___ |
| 24 | +## Usage |
| 25 | +See [Wiki](https://github.com/wizard97/ArduinoProcessScheduler/wiki) |
167 | 26 |
|
168 | | -#### disable() |
169 | | -``` |
170 | | -disable (Process &service)) |
171 | | -``` |
172 | | -Disable a service, same as calling `service.disable()`. Note, this will trigger the service's `onDisable()` method to fire. This method call will always succeed if it was not called on itself from a method inside of this service. If it was, the scheduler will queue the request. Also, the request will fail if the service is already enabled or is destroyed. |
173 | 27 |
|
174 | | -**Returns:** type `SchedulerAction`, `ACTION_NONE` on failure, `ACTION_QUEUED` on Queuing it, `ACTION_SUCCESS` on success. |
175 | | -___ |
| 28 | +## License |
| 29 | +MIT. |
0 commit comments