5.2.1 - Updated I2C files
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
events/equeue/README.md@1:f30bdcd2b33b, 2017-02-27 (annotated)
- Committer:
- jacobjohnson
- Date:
- Mon Feb 27 17:45:05 2017 +0000
- Revision:
- 1:f30bdcd2b33b
- Parent:
- 0:098463de4c5d
changed the inputscale from 1 to 7 in analogin_api.c. This will need to be changed later, and accessed from the main level, but for now this allows the adc to read a value from 0 to 3.7V, instead of just up to 1V.;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
group-onsemi | 0:098463de4c5d | 1 | ## The equeue library ## |
group-onsemi | 0:098463de4c5d | 2 | |
group-onsemi | 0:098463de4c5d | 3 | The equeue library is designed as a simple but powerful library for scheduling |
group-onsemi | 0:098463de4c5d | 4 | events on composable queues. |
group-onsemi | 0:098463de4c5d | 5 | |
group-onsemi | 0:098463de4c5d | 6 | ``` c |
group-onsemi | 0:098463de4c5d | 7 | #include "equeue.h" |
group-onsemi | 0:098463de4c5d | 8 | #include <stdio.h> |
group-onsemi | 0:098463de4c5d | 9 | |
group-onsemi | 0:098463de4c5d | 10 | int main() { |
group-onsemi | 0:098463de4c5d | 11 | // creates a queue with space for 32 basic events |
group-onsemi | 0:098463de4c5d | 12 | equeue_t queue; |
group-onsemi | 0:098463de4c5d | 13 | equeue_create(&queue, 32*EQUEUE_EVENT_SIZE); |
group-onsemi | 0:098463de4c5d | 14 | |
group-onsemi | 0:098463de4c5d | 15 | // events can be simple callbacks |
group-onsemi | 0:098463de4c5d | 16 | equeue_call(&queue, print, "called immediately"); |
group-onsemi | 0:098463de4c5d | 17 | equeue_call_in(&queue, 2000, print, "called in 2 seconds"); |
group-onsemi | 0:098463de4c5d | 18 | equeue_call_every(&queue, 1000, print, "called every 1 seconds"); |
group-onsemi | 0:098463de4c5d | 19 | |
group-onsemi | 0:098463de4c5d | 20 | // events are executed in equeue_dispatch |
group-onsemi | 0:098463de4c5d | 21 | equeue_dispatch(&queue, 3000); |
group-onsemi | 0:098463de4c5d | 22 | |
group-onsemi | 0:098463de4c5d | 23 | print("called after 3 seconds"); |
group-onsemi | 0:098463de4c5d | 24 | |
group-onsemi | 0:098463de4c5d | 25 | equeue_destroy(&queue); |
group-onsemi | 0:098463de4c5d | 26 | } |
group-onsemi | 0:098463de4c5d | 27 | ``` |
group-onsemi | 0:098463de4c5d | 28 | |
group-onsemi | 0:098463de4c5d | 29 | The equeue library can be used as a normal event loop, or it can be |
group-onsemi | 0:098463de4c5d | 30 | backgrounded on a single hardware timer or even another event loop. It |
group-onsemi | 0:098463de4c5d | 31 | is both thread and irq safe, and provides functions for easily composing |
group-onsemi | 0:098463de4c5d | 32 | multiple queues. |
group-onsemi | 0:098463de4c5d | 33 | |
group-onsemi | 0:098463de4c5d | 34 | The equeue library can act as a drop-in scheduler, provide synchronization |
group-onsemi | 0:098463de4c5d | 35 | between multiple threads, or just act as a mechanism for moving events |
group-onsemi | 0:098463de4c5d | 36 | out of interrupt contexts. |
group-onsemi | 0:098463de4c5d | 37 | |
group-onsemi | 0:098463de4c5d | 38 | ## Documentation ## |
group-onsemi | 0:098463de4c5d | 39 | |
group-onsemi | 0:098463de4c5d | 40 | The in-depth documentation on specific functions can be found in |
group-onsemi | 0:098463de4c5d | 41 | [equeue.h](equeue.h). |
group-onsemi | 0:098463de4c5d | 42 | |
group-onsemi | 0:098463de4c5d | 43 | The core of the equeue library is the `equeue_t` type which represents a |
group-onsemi | 0:098463de4c5d | 44 | single event queue, and the `equeue_dispatch` function which runs the equeue, |
group-onsemi | 0:098463de4c5d | 45 | providing the context for executing events. |
group-onsemi | 0:098463de4c5d | 46 | |
group-onsemi | 0:098463de4c5d | 47 | On top of this, `equeue_call`, `equeue_call_in`, and `equeue_call_every` |
group-onsemi | 0:098463de4c5d | 48 | provide easy methods for posting events to execute in the context of the |
group-onsemi | 0:098463de4c5d | 49 | `equeue_dispatch` function. |
group-onsemi | 0:098463de4c5d | 50 | |
group-onsemi | 0:098463de4c5d | 51 | ``` c |
group-onsemi | 0:098463de4c5d | 52 | #include "equeue.h" |
group-onsemi | 0:098463de4c5d | 53 | #include "game.h" |
group-onsemi | 0:098463de4c5d | 54 | |
group-onsemi | 0:098463de4c5d | 55 | equeue_t queue; |
group-onsemi | 0:098463de4c5d | 56 | struct game game; |
group-onsemi | 0:098463de4c5d | 57 | |
group-onsemi | 0:098463de4c5d | 58 | // button_isr may be in interrupt context |
group-onsemi | 0:098463de4c5d | 59 | void button_isr(void) { |
group-onsemi | 0:098463de4c5d | 60 | equeue_call(&queue, game_button_update, &game); |
group-onsemi | 0:098463de4c5d | 61 | } |
group-onsemi | 0:098463de4c5d | 62 | |
group-onsemi | 0:098463de4c5d | 63 | // a simple user-interface framework |
group-onsemi | 0:098463de4c5d | 64 | int main() { |
group-onsemi | 0:098463de4c5d | 65 | equeue_create(&queue, 4096); |
group-onsemi | 0:098463de4c5d | 66 | game_create(&game); |
group-onsemi | 0:098463de4c5d | 67 | |
group-onsemi | 0:098463de4c5d | 68 | // call game_screen_udpate at 60 Hz |
group-onsemi | 0:098463de4c5d | 69 | equeue_call_every(&queue, 1000/60, game_screen_update, &game); |
group-onsemi | 0:098463de4c5d | 70 | |
group-onsemi | 0:098463de4c5d | 71 | // dispatch forever |
group-onsemi | 0:098463de4c5d | 72 | equeue_dispatch(&queue, -1); |
group-onsemi | 0:098463de4c5d | 73 | } |
group-onsemi | 0:098463de4c5d | 74 | ``` |
group-onsemi | 0:098463de4c5d | 75 | |
group-onsemi | 0:098463de4c5d | 76 | In addition to simple callbacks, an event can be manually allocated with |
group-onsemi | 0:098463de4c5d | 77 | `equeue_alloc` and posted with `equeue_post` to allow passing an arbitrary |
group-onsemi | 0:098463de4c5d | 78 | amount of context to the execution of the event. This memory is allocated out |
group-onsemi | 0:098463de4c5d | 79 | of the equeue's buffer, and dynamic memory can be completely avoided. |
group-onsemi | 0:098463de4c5d | 80 | |
group-onsemi | 0:098463de4c5d | 81 | The equeue allocator is designed to minimize jitter in interrupt contexts as |
group-onsemi | 0:098463de4c5d | 82 | well as avoid memory fragmentation on small devices. The allocator achieves |
group-onsemi | 0:098463de4c5d | 83 | both constant-runtime and zero-fragmentation for fixed-size events, however |
group-onsemi | 0:098463de4c5d | 84 | grows linearly as the quantity of differently-sized allocations increases. |
group-onsemi | 0:098463de4c5d | 85 | |
group-onsemi | 0:098463de4c5d | 86 | ``` c |
group-onsemi | 0:098463de4c5d | 87 | #include "equeue.h" |
group-onsemi | 0:098463de4c5d | 88 | |
group-onsemi | 0:098463de4c5d | 89 | equeue_t queue; |
group-onsemi | 0:098463de4c5d | 90 | |
group-onsemi | 0:098463de4c5d | 91 | // arbitrary data can be moved to a different context |
group-onsemi | 0:098463de4c5d | 92 | int enet_consume(void *buffer, int size) { |
group-onsemi | 0:098463de4c5d | 93 | if (size > 512) { |
group-onsemi | 0:098463de4c5d | 94 | size = 512; |
group-onsemi | 0:098463de4c5d | 95 | } |
group-onsemi | 0:098463de4c5d | 96 | |
group-onsemi | 0:098463de4c5d | 97 | void *data = equeue_alloc(&queue, 512); |
group-onsemi | 0:098463de4c5d | 98 | memcpy(data, buffer, size); |
group-onsemi | 0:098463de4c5d | 99 | equeue_post(&queue, handle_data_elsewhere, data); |
group-onsemi | 0:098463de4c5d | 100 | |
group-onsemi | 0:098463de4c5d | 101 | return size; |
group-onsemi | 0:098463de4c5d | 102 | } |
group-onsemi | 0:098463de4c5d | 103 | ``` |
group-onsemi | 0:098463de4c5d | 104 | |
group-onsemi | 0:098463de4c5d | 105 | Additionally, in-flight events can be cancelled with `equeue_cancel`. Events |
group-onsemi | 0:098463de4c5d | 106 | are given unique ids on post, allowing safe cancellation of expired events. |
group-onsemi | 0:098463de4c5d | 107 | |
group-onsemi | 0:098463de4c5d | 108 | ``` c |
group-onsemi | 0:098463de4c5d | 109 | #include "equeue.h" |
group-onsemi | 0:098463de4c5d | 110 | |
group-onsemi | 0:098463de4c5d | 111 | equeue_t queue; |
group-onsemi | 0:098463de4c5d | 112 | int sonar_value; |
group-onsemi | 0:098463de4c5d | 113 | int sonar_timeout_id; |
group-onsemi | 0:098463de4c5d | 114 | |
group-onsemi | 0:098463de4c5d | 115 | void sonar_isr(int value) { |
group-onsemi | 0:098463de4c5d | 116 | equeue_cancel(&queue, sonar_timeout_id); |
group-onsemi | 0:098463de4c5d | 117 | sonar_value = value; |
group-onsemi | 0:098463de4c5d | 118 | } |
group-onsemi | 0:098463de4c5d | 119 | |
group-onsemi | 0:098463de4c5d | 120 | void sonar_timeout(void *) { |
group-onsemi | 0:098463de4c5d | 121 | sonar_value = -1; |
group-onsemi | 0:098463de4c5d | 122 | } |
group-onsemi | 0:098463de4c5d | 123 | |
group-onsemi | 0:098463de4c5d | 124 | void sonar_read(void) { |
group-onsemi | 0:098463de4c5d | 125 | sonar_timeout_id = equeue_call_in(&queue, 300, sonar_timeout, 0); |
group-onsemi | 0:098463de4c5d | 126 | sonar_start(); |
group-onsemi | 0:098463de4c5d | 127 | } |
group-onsemi | 0:098463de4c5d | 128 | ``` |
group-onsemi | 0:098463de4c5d | 129 | |
group-onsemi | 0:098463de4c5d | 130 | From an architectural standpoint, event queues easily align with module |
group-onsemi | 0:098463de4c5d | 131 | boundaries, where internal state can be implicitly synchronized through |
group-onsemi | 0:098463de4c5d | 132 | event dispatch. |
group-onsemi | 0:098463de4c5d | 133 | |
group-onsemi | 0:098463de4c5d | 134 | On platforms where multiple threads are unavailable, multiple modules |
group-onsemi | 0:098463de4c5d | 135 | can use independent event queues and still be composed through the |
group-onsemi | 0:098463de4c5d | 136 | `equeue_chain` function. |
group-onsemi | 0:098463de4c5d | 137 | |
group-onsemi | 0:098463de4c5d | 138 | ``` c |
group-onsemi | 0:098463de4c5d | 139 | #include "equeue.h" |
group-onsemi | 0:098463de4c5d | 140 | |
group-onsemi | 0:098463de4c5d | 141 | // run a simultaneous localization and mapping loop in one queue |
group-onsemi | 0:098463de4c5d | 142 | struct slam { |
group-onsemi | 0:098463de4c5d | 143 | equeue_t queue; |
group-onsemi | 0:098463de4c5d | 144 | }; |
group-onsemi | 0:098463de4c5d | 145 | |
group-onsemi | 0:098463de4c5d | 146 | void slam_create(struct slam *s, equeue_t *target) { |
group-onsemi | 0:098463de4c5d | 147 | equeue_create(&s->queue, 4096); |
group-onsemi | 0:098463de4c5d | 148 | equeue_chain(&s->queue, target); |
group-onsemi | 0:098463de4c5d | 149 | equeue_call_every(&s->queue, 100, slam_filter); |
group-onsemi | 0:098463de4c5d | 150 | } |
group-onsemi | 0:098463de4c5d | 151 | |
group-onsemi | 0:098463de4c5d | 152 | // run a sonar with it's own queue |
group-onsemi | 0:098463de4c5d | 153 | struct sonar { |
group-onsemi | 0:098463de4c5d | 154 | equeue_t equeue; |
group-onsemi | 0:098463de4c5d | 155 | struct slam *slam; |
group-onsemi | 0:098463de4c5d | 156 | }; |
group-onsemi | 0:098463de4c5d | 157 | |
group-onsemi | 0:098463de4c5d | 158 | void sonar_create(struct sonar *s, equeue_t *target) { |
group-onsemi | 0:098463de4c5d | 159 | equeue_create(&s->queue, 64); |
group-onsemi | 0:098463de4c5d | 160 | equeue_chain(&s->queue, target); |
group-onsemi | 0:098463de4c5d | 161 | equeue_call_in(&s->queue, 5, sonar_update, s); |
group-onsemi | 0:098463de4c5d | 162 | } |
group-onsemi | 0:098463de4c5d | 163 | |
group-onsemi | 0:098463de4c5d | 164 | // all of the above queues can be combined into a single thread of execution |
group-onsemi | 0:098463de4c5d | 165 | int main() { |
group-onsemi | 0:098463de4c5d | 166 | equeue_t queue; |
group-onsemi | 0:098463de4c5d | 167 | equeue_create(&queue, 1024); |
group-onsemi | 0:098463de4c5d | 168 | |
group-onsemi | 0:098463de4c5d | 169 | struct sonar s1, s2, s3; |
group-onsemi | 0:098463de4c5d | 170 | sonar_create(&s1, &queue); |
group-onsemi | 0:098463de4c5d | 171 | sonar_create(&s2, &queue); |
group-onsemi | 0:098463de4c5d | 172 | sonar_create(&s3, &queue); |
group-onsemi | 0:098463de4c5d | 173 | |
group-onsemi | 0:098463de4c5d | 174 | struct slam slam; |
group-onsemi | 0:098463de4c5d | 175 | slam_create(&slam, &queue); |
group-onsemi | 0:098463de4c5d | 176 | |
group-onsemi | 0:098463de4c5d | 177 | // dispatches events from all of the modules |
group-onsemi | 0:098463de4c5d | 178 | equeue_dispatch(&queue, -1); |
group-onsemi | 0:098463de4c5d | 179 | } |
group-onsemi | 0:098463de4c5d | 180 | ``` |
group-onsemi | 0:098463de4c5d | 181 | |
group-onsemi | 0:098463de4c5d | 182 | ## Platform ## |
group-onsemi | 0:098463de4c5d | 183 | |
group-onsemi | 0:098463de4c5d | 184 | The equeue library has a minimal porting layer that is flexible depending |
group-onsemi | 0:098463de4c5d | 185 | on the requirements of the underlying platform. Platform specific declarations |
group-onsemi | 0:098463de4c5d | 186 | and more information can be found in [equeue_platform.h](equeue_platform.h). |
group-onsemi | 0:098463de4c5d | 187 | |
group-onsemi | 0:098463de4c5d | 188 | ## Tests ## |
group-onsemi | 0:098463de4c5d | 189 | |
group-onsemi | 0:098463de4c5d | 190 | The equeue library uses a set of local tests based on the posix implementation. |
group-onsemi | 0:098463de4c5d | 191 | |
group-onsemi | 0:098463de4c5d | 192 | Runtime tests are located in [tests.c](tests/tests.c): |
group-onsemi | 0:098463de4c5d | 193 | |
group-onsemi | 0:098463de4c5d | 194 | ``` bash |
group-onsemi | 0:098463de4c5d | 195 | make test |
group-onsemi | 0:098463de4c5d | 196 | ``` |
group-onsemi | 0:098463de4c5d | 197 | |
group-onsemi | 0:098463de4c5d | 198 | Profiling tests based on rdtsc are located in [prof.c](tests/prof.c): |
group-onsemi | 0:098463de4c5d | 199 | |
group-onsemi | 0:098463de4c5d | 200 | ``` bash |
group-onsemi | 0:098463de4c5d | 201 | make prof |
group-onsemi | 0:098463de4c5d | 202 | ``` |
group-onsemi | 0:098463de4c5d | 203 | |
group-onsemi | 0:098463de4c5d | 204 | To make profiling results more tangible, the profiler also supports percentage |
group-onsemi | 0:098463de4c5d | 205 | comparison with previous runs: |
group-onsemi | 0:098463de4c5d | 206 | ``` bash |
group-onsemi | 0:098463de4c5d | 207 | make prof | tee results.txt |
group-onsemi | 0:098463de4c5d | 208 | cat results.txt | make prof |
group-onsemi | 0:098463de4c5d | 209 | ``` |
group-onsemi | 0:098463de4c5d | 210 |