|  | @@ -5,7 +5,7 @@ email: <patb@pbeirne.com>
 | 
											
												
													
														|  |  date: 2025/01/15
 |  |  date: 2025/01/15
 | 
											
												
													
														|  |  license: MIT
 |  |  license: MIT
 | 
											
												
													
														|  |  ---
 |  |  ---
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | 
 |  | +<style> h2 { border-top: solid thin #899;}   </style>
 | 
											
												
													
														|  |  # Part 1: Cooperative Multitasking
 |  |  # Part 1: Cooperative Multitasking
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  <!-- ## Introduction -->
 |  |  <!-- ## Introduction -->
 | 
											
										
											
												
													
														|  | @@ -22,7 +22,7 @@ The core of *this* technique is covered in
 | 
											
												
													
														|  |  [Part 1](#part-1-cooperative-multitasking)
 |  |  [Part 1](#part-1-cooperative-multitasking)
 | 
											
												
													
														|  |  of this paper. 
 |  |  of this paper. 
 | 
											
												
													
														|  |  If you just want to see how it all comes together, 
 |  |  If you just want to see how it all comes together, 
 | 
											
												
													
														|  | -jump to [Final Implementaion](#final-implementation). 
 |  | 
 | 
											
												
													
														|  | 
 |  | +jump to [Final Implementation](#final-implementation). 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  [Part 2](#part-2) contains enhancements and variations, 
 |  |  [Part 2](#part-2) contains enhancements and variations, 
 | 
											
												
													
														|  |  probably useful reading if you decide to adopt
 |  |  probably useful reading if you decide to adopt
 | 
											
										
											
												
													
														|  | @@ -86,7 +86,7 @@ to make this happen?
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ## First Page
 |  |  ## First Page
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -Let's look an a pseudocode overview of what we want to do:
 |  | 
 | 
											
												
													
														|  | 
 |  | +Let's look at the pseudocode overview of what we want to do:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  void initialize(void) {
 |  |  void initialize(void) {
 | 
											
										
											
												
													
														|  | @@ -137,12 +137,12 @@ In order to have a responsive system, it would make sense to use the
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  In the task described, we need to respond to a button press. 
 |  |  In the task described, we need to respond to a button press. 
 | 
											
												
													
														|  |  So let's connect the button to 
 |  |  So let's connect the button to 
 | 
											
												
													
														|  | -an input pin and enable it to repsond to a button press with interrupt code.
 |  | 
 | 
											
												
													
														|  | 
 |  | +an input pin and enable it to respond to a button press with interrupt code.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  We also need to keep track of time.....so let's hook up a system timer to another interrupt.
 |  |  We also need to keep track of time.....so let's hook up a system timer to another interrupt.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  Each interrupt causes the execution of *interrupt handler* code. For this project, it might look
 |  |  Each interrupt causes the execution of *interrupt handler* code. For this project, it might look
 | 
											
												
													
														|  | -somthing like this:
 |  | 
 | 
											
												
													
														|  | 
 |  | +something like this:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  enum {EVT_NONE, EVT_TICK, EVT_BUTTON};
 |  |  enum {EVT_NONE, EVT_TICK, EVT_BUTTON};
 | 
											
										
											
												
													
														|  | @@ -198,7 +198,7 @@ Implemented, it can be a *byte*, or an *int* or an even larger structure.
 | 
											
												
													
														|  |  But in these small microcontrollers, let's use a *byte*.
 |  |  But in these small microcontrollers, let's use a *byte*.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -volatile uint8 event;
 |  | 
 | 
											
												
													
														|  | 
 |  | +volatile uchar event;
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  These *events* will be created in interrupt level of the code, 
 |  |  These *events* will be created in interrupt level of the code, 
 | 
											
										
											
												
													
														|  | @@ -218,7 +218,7 @@ and *non-zero* to represent
 | 
											
												
													
														|  |  an event/message.
 |  |  an event/message.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -volatile uint8 event;
 |  | 
 | 
											
												
													
														|  | 
 |  | +volatile uchar event;
 | 
											
												
													
														|  |  enum {EVT_NONE, EVT_TICK, EVT_BUTTON}; // 0,1,2
 |  |  enum {EVT_NONE, EVT_TICK, EVT_BUTTON}; // 0,1,2
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -244,13 +244,13 @@ How do we send the information (events/messages) from the interrupt
 | 
											
												
													
														|  |  service routine to the 
 |  |  service routine to the 
 | 
											
												
													
														|  |  `main()` code? We used shared memory.
 |  |  `main()` code? We used shared memory.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -One way would be to have a global `volatile uint8` location into which 
 |  | 
 | 
											
												
													
														|  | 
 |  | +One way would be to have a global `volatile uchar` location into which 
 | 
											
												
													
														|  |  we drop the *event* information. But
 |  |  we drop the *event* information. But
 | 
											
												
													
														|  |  having only one socket for that would be a bit naive; 
 |  |  having only one socket for that would be a bit naive; 
 | 
											
												
													
														|  |  what happens if a timer tick and a button press
 |  |  what happens if a timer tick and a button press
 | 
											
												
													
														|  |  happen very close in time? What happens if the timer tick events start to stack up?
 |  |  happen very close in time? What happens if the timer tick events start to stack up?
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -It makes more sense to have an array: `volatile uint8 events[NUM_EVENTS]` 
 |  | 
 | 
											
												
													
														|  | 
 |  | +It makes more sense to have an array: `volatile uchar events[NUM_EVENTS]` 
 | 
											
												
													
														|  |  where NUM_EVENTS is on the order of 5..10. 
 |  |  where NUM_EVENTS is on the order of 5..10. 
 | 
											
												
													
														|  |  That would give us 50-100msec to catch up in case there's a 
 |  |  That would give us 50-100msec to catch up in case there's a 
 | 
											
												
													
														|  |  pileup of events/messages.
 |  |  pileup of events/messages.
 | 
											
										
											
												
													
														|  | @@ -263,8 +263,8 @@ The `newEvent(evt)` routine simply adds the `evt` to the array `events[]`.
 | 
											
												
													
														|  |  Something like this might work:
 |  |  Something like this might work:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void newEvent(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | -  static uint8 nextEvent;
 |  | 
 | 
											
												
													
														|  | 
 |  | +void newEvent(uchar evt) {
 | 
											
												
													
														|  | 
 |  | +  static uchar nextEvent;
 | 
											
												
													
														|  |    events[nextEvent++] = evt;
 |  |    events[nextEvent++] = evt;
 | 
											
												
													
														|  |    if (nextEvent == NUM_EVENTS)
 |  |    if (nextEvent == NUM_EVENTS)
 | 
											
												
													
														|  |      nextEvent = 0;
 |  |      nextEvent = 0;
 | 
											
										
											
												
													
														|  | @@ -283,7 +283,7 @@ Here's a more realistic version:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  void newEvent(char evt) {
 |  |  void newEvent(char evt) {
 | 
											
												
													
														|  | -  static uint8 nextEvent;   // keep track of where we are in queue
 |  | 
 | 
											
												
													
														|  | 
 |  | +  static uchar nextEvent;   // keep track of where we are in queue
 | 
											
												
													
														|  |    disable_irq();                    // critical section
 |  |    disable_irq();                    // critical section
 | 
											
												
													
														|  |    events[nextEvent++] = evt;        // insert event into queue
 |  |    events[nextEvent++] = evt;        // insert event into queue
 | 
											
												
													
														|  |    if (nextEvent == NUM_EVENTS)      // loop back to the start of queue
 |  |    if (nextEvent == NUM_EVENTS)      // loop back to the start of queue
 | 
											
										
											
												
													
														|  | @@ -312,7 +312,7 @@ To see the real code for the dispatcher, [jump ahead](#dispatcher-details).
 | 
											
												
													
														|  |  The `main()` code illustrated here calls the tasks 
 |  |  The `main()` code illustrated here calls the tasks 
 | 
											
												
													
														|  |  as subroutines, sending each one a copy of the event number. 
 |  |  as subroutines, sending each one a copy of the event number. 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -As I mentioned earlier, *events* can also be refered to as *messages*. 
 |  | 
 | 
											
												
													
														|  | 
 |  | +As I mentioned earlier, *events* can also be referred to as *messages*. 
 | 
											
												
													
														|  |  We can also refer to this process "sending
 |  |  We can also refer to this process "sending
 | 
											
												
													
														|  |  a message to the task"
 |  |  a message to the task"
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -345,11 +345,11 @@ the event, speeding up the whole system.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ## Tasks
 |  |  ## Tasks
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -In this environment, the code that impliments a *task* is simply a 
 |  | 
 | 
											
												
													
														|  | 
 |  | +In this environment, the code that implements a *task* is simply a 
 | 
											
												
													
														|  |  subroutine that accepts an *event/message*.
 |  |  subroutine that accepts an *event/message*.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void taskCode(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void taskCode(uchar event) {
 | 
											
												
													
														|  |    ... process the event information ...
 |  |    ... process the event information ...
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
										
											
												
													
														|  | @@ -382,11 +382,11 @@ The above diagram can be implemented in this code:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  enum {RTB_IDLE, RTB_ON};          // RTB_IDLE=0, RTB_ON=1
 |  |  enum {RTB_IDLE, RTB_ON};          // RTB_IDLE=0, RTB_ON=1
 | 
											
												
													
														|  | -static uint8  rtbState      = RTB_IDLE;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar  rtbState      = RTB_IDLE;
 | 
											
												
													
														|  |  static uint16 rtbTimerCount = 0;
 |  |  static uint16 rtbTimerCount = 0;
 | 
											
												
													
														|  |  const  uint16 TIMER_LIMIT   = 150;
 |  |  const  uint16 TIMER_LIMIT   = 150;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void respondToButtonTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void respondToButtonTask(uchar evt) {
 | 
											
												
													
														|  |    switch(rtbState) {
 |  |    switch(rtbState) {
 | 
											
												
													
														|  |      case RTB_IDLE:
 |  |      case RTB_IDLE:
 | 
											
												
													
														|  |        if (evt == EVT_BUTTON) {
 |  |        if (evt == EVT_BUTTON) {
 | 
											
										
											
												
													
														|  | @@ -440,12 +440,12 @@ The code for this might be:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  enum {LED_ON, LED_OFF};
 |  |  enum {LED_ON, LED_OFF};
 | 
											
												
													
														|  | -static uint8 ledState       = LED_OFF;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar ledState       = LED_OFF;
 | 
											
												
													
														|  |  static uint16 ledTimerCount = 0;
 |  |  static uint16 ledTimerCount = 0;
 | 
											
												
													
														|  |  const  uint16 LED_ON_TIME   = 100;
 |  |  const  uint16 LED_ON_TIME   = 100;
 | 
											
												
													
														|  |  const  uint16 LED_OFF_TIME  = 100;
 |  |  const  uint16 LED_OFF_TIME  = 100;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void ledTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void ledTask(uchar evt) {
 | 
											
												
													
														|  |    switch(ledState) {
 |  |    switch(ledState) {
 | 
											
												
													
														|  |      case LED_OFF:
 |  |      case LED_OFF:
 | 
											
												
													
														|  |        if (evt == EVT_TICK) {
 |  |        if (evt == EVT_TICK) {
 | 
											
										
											
												
													
														|  | @@ -569,11 +569,11 @@ Let's put all of the above together, for an SMT32F Cortex M0, in *C* code.
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  /***** declarations ****/
 |  |  /***** declarations ****/
 | 
											
												
													
														|  |  #define NUM_EVENTS 10
 |  |  #define NUM_EVENTS 10
 | 
											
												
													
														|  | -volatile uint8 events[NUM_EVENTS];
 |  | 
 | 
											
												
													
														|  | 
 |  | +volatile uchar events[NUM_EVENTS];
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void newEvent(uint8 e);
 |  | 
 | 
											
												
													
														|  | -void ledTask(uint8 evt);
 |  | 
 | 
											
												
													
														|  | -void respondToButtonTask(uint8 evt);
 |  | 
 | 
											
												
													
														|  | 
 |  | +void newEvent(uchar e);
 | 
											
												
													
														|  | 
 |  | +void ledTask(uchar evt);
 | 
											
												
													
														|  | 
 |  | +void respondToButtonTask(uchar evt);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /********** interrupts **************/
 |  |  /********** interrupts **************/
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -593,8 +593,8 @@ void button_isr(void) {
 | 
											
												
													
														|  |   * 
 |  |   * 
 | 
											
												
													
														|  |   * @param the event
 |  |   * @param the event
 | 
											
												
													
														|  |   */
 |  |   */
 | 
											
												
													
														|  | -void newEvent(uint8 e) {
 |  | 
 | 
											
												
													
														|  | -  static uint8 nextEvent;
 |  | 
 | 
											
												
													
														|  | 
 |  | +void newEvent(uchar e) {
 | 
											
												
													
														|  | 
 |  | +  static uchar nextEvent;
 | 
											
												
													
														|  |    dint(); // critical section
 |  |    dint(); // critical section
 | 
											
												
													
														|  |    events[nextEvent++] = e;
 |  |    events[nextEvent++] = e;
 | 
											
												
													
														|  |    if (nextEvent==NUM_EVENTS)
 |  |    if (nextEvent==NUM_EVENTS)
 | 
											
										
											
												
													
														|  | @@ -623,11 +623,11 @@ void main(void) {
 | 
											
												
													
														|  |  /*********** task code, with states ************/
 |  |  /*********** task code, with states ************/
 | 
											
												
													
														|  |  enum {LED_ON, LED_OFF};
 |  |  enum {LED_ON, LED_OFF};
 | 
											
												
													
														|  |  enum {RTB_IDLE, RTB_ON};    // states
 |  |  enum {RTB_IDLE, RTB_ON};    // states
 | 
											
												
													
														|  | -static uint8  rtbState      = RTB_IDLE;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar  rtbState      = RTB_IDLE;
 | 
											
												
													
														|  |  static uint16 rtbTimerCount = 0;
 |  |  static uint16 rtbTimerCount = 0;
 | 
											
												
													
														|  |  const  uint16 LED_ON_TIME   = 150;
 |  |  const  uint16 LED_ON_TIME   = 150;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void respondToButtonTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void respondToButtonTask(uchar evt) {
 | 
											
												
													
														|  |    switch(rtbState) {
 |  |    switch(rtbState) {
 | 
											
												
													
														|  |      case RTB_IDLE:
 |  |      case RTB_IDLE:
 | 
											
												
													
														|  |        if (evt == EVT_BUTTON) {
 |  |        if (evt == EVT_BUTTON) {
 | 
											
										
											
												
													
														|  | @@ -649,10 +649,10 @@ void respondToButtonTask(uint8 evt) {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  const  uint16 LED_ON_TIME   = 150;
 |  |  const  uint16 LED_ON_TIME   = 150;
 | 
											
												
													
														|  |  const  uint16 LED_OFF_TIME  = 50;
 |  |  const  uint16 LED_OFF_TIME  = 50;
 | 
											
												
													
														|  | -static uint8 ledState       = LED_OFF;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar ledState       = LED_OFF;
 | 
											
												
													
														|  |  static uint16 ledTimerCount = 0;
 |  |  static uint16 ledTimerCount = 0;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void ledTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void ledTask(uchar evt) {
 | 
											
												
													
														|  |    switch(ledState) {
 |  |    switch(ledState) {
 | 
											
												
													
														|  |      case LED_OFF:
 |  |      case LED_OFF:
 | 
											
												
													
														|  |        if (evt == EVT_TICK) {
 |  |        if (evt == EVT_TICK) {
 | 
											
										
											
												
													
														|  | @@ -714,7 +714,7 @@ LED timer on each key press:
 | 
											
												
													
														|  |  <div style="display: flex;">
 |  |  <div style="display: flex;">
 | 
											
												
													
														|  |  \ 
 |  |  \ 
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void rtbTask(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void rtbTask(uchar event) {
 | 
											
												
													
														|  |    switch(rtbState) {
 |  |    switch(rtbState) {
 | 
											
												
													
														|  |      case RTB_IDLE:
 |  |      case RTB_IDLE:
 | 
											
												
													
														|  |        if (event == EVT_BUTTON) {
 |  |        if (event == EVT_BUTTON) {
 | 
											
										
											
												
													
														|  | @@ -746,7 +746,7 @@ Or have a 2nd press of the button cause the LED to extinguish early:
 | 
											
												
													
														|  |  <div style="display: flex;">
 |  |  <div style="display: flex;">
 | 
											
												
													
														|  |  \ 
 |  |  \ 
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void rtbTask(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void rtbTask(uchar event) {
 | 
											
												
													
														|  |    switch(rtbState) {
 |  |    switch(rtbState) {
 | 
											
												
													
														|  |      case RTB_IDLE:
 |  |      case RTB_IDLE:
 | 
											
												
													
														|  |        if (event == EVT_BUTTON) {
 |  |        if (event == EVT_BUTTON) {
 | 
											
										
											
												
													
														|  | @@ -783,7 +783,7 @@ it: (see also [substates](#substates))
 | 
											
												
													
														|  |  \ 
 |  |  \ 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void rtbTask(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void rtbTask(uchar event) {
 | 
											
												
													
														|  |    switch(rtbState) {
 |  |    switch(rtbState) {
 | 
											
												
													
														|  |      case RTB_IDLE:
 |  |      case RTB_IDLE:
 | 
											
												
													
														|  |        if (event == EVT_BUTTON) {
 |  |        if (event == EVT_BUTTON) {
 | 
											
										
											
												
													
														|  | @@ -888,7 +888,7 @@ If a task occasionally runs into the 10's of msec, the event queue will
 | 
											
												
													
														|  |  handle buffering the events until they can be processed.
 |  |  handle buffering the events until they can be processed.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  Under no circumstances should a task take more than 100msec. Use a new state,
 |  |  Under no circumstances should a task take more than 100msec. Use a new state,
 | 
											
												
													
														|  | -and return from the tast. Process the new state later.
 |  | 
 | 
											
												
													
														|  | 
 |  | +and return from the task. Process the new state later.
 | 
											
												
													
														|  |  <hr>
 |  |  <hr>
 | 
											
												
													
														|  |  </details>
 |  |  </details>
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -915,9 +915,9 @@ and the code: arrows leaving a state correspond to an `if()` phrase.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  enum {WINDOW_IDLE, WINDOW_UP, WINDOW_DOWN};
 |  |  enum {WINDOW_IDLE, WINDOW_UP, WINDOW_DOWN};
 | 
											
												
													
														|  | -static uint8 windowState = WINDOW_IDLE;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar windowState = WINDOW_IDLE;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void windowTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void windowTask(uchar evt) {
 | 
											
												
													
														|  |    switch(windowState) {
 |  |    switch(windowState) {
 | 
											
												
													
														|  |      case WINDOW_IDLE:
 |  |      case WINDOW_IDLE:
 | 
											
												
													
														|  |        if (evt == EVT_BUTTON_UP) {
 |  |        if (evt == EVT_BUTTON_UP) {
 | 
											
										
											
												
													
														|  | @@ -962,7 +962,7 @@ code from the previous version.
 | 
											
												
													
														|  |  <details><summary>Reality Check</summary>
 |  |  <details><summary>Reality Check</summary>
 | 
											
												
													
														|  |  This is such a simple task, with only a few I/O pins involved. In theory, a
 |  |  This is such a simple task, with only a few I/O pins involved. In theory, a
 | 
											
												
													
														|  |  cheap microcontroller could control a dozen windows, each appearing to operate
 |  |  cheap microcontroller could control a dozen windows, each appearing to operate
 | 
											
												
													
														|  | -independantly. 
 |  | 
 | 
											
												
													
														|  | 
 |  | +independently. 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  In the code, one wouldn't need to create a dozen tasks......just create an index
 |  |  In the code, one wouldn't need to create a dozen tasks......just create an index
 | 
											
												
													
														|  |  into the same code and invoke it in a way that makes it appear as an 
 |  |  into the same code and invoke it in a way that makes it appear as an 
 | 
											
										
											
												
													
														|  | @@ -1020,7 +1020,7 @@ And here is the corresponding code.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  enum {FRIDGE_CLOSED, FRIDGE_OPEN, FRIDGE_BEEPING};
 |  |  enum {FRIDGE_CLOSED, FRIDGE_OPEN, FRIDGE_BEEPING};
 | 
											
												
													
														|  | -uint8  fridgeState;
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar  fridgeState;
 | 
											
												
													
														|  |  uint16 fridgeTimer;
 |  |  uint16 fridgeTimer;
 | 
											
												
													
														|  |  const uint16 FRIDGE_OPEN_LIMIT = 9000; // 90 seconds at 10msec tick
 |  |  const uint16 FRIDGE_OPEN_LIMIT = 9000; // 90 seconds at 10msec tick
 | 
											
												
													
														|  |  void fridgeTask(char event) {
 |  |  void fridgeTask(char event) {
 | 
											
										
											
												
													
														|  | @@ -1135,18 +1135,18 @@ Here's the state diagram:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -I use `EVT_` type events to indicate that they originate in hardware, probably
 |  | 
 | 
											
												
													
														|  | -at the interrupt level; and `MSG_` type events to indicate they come from a
 |  | 
 | 
											
												
													
														|  | -software source, perhaps a sibling task.
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  |  Suppose now that the serial number needs to be verified by a central service.
 |  |  Suppose now that the serial number needs to be verified by a central service.
 | 
											
												
													
														|  |  So when an RFID tag is detected, send a request to the master control and 
 |  |  So when an RFID tag is detected, send a request to the master control and 
 | 
											
												
													
														|  |  wait for an ACK or NAK response. In the case of an ACK, open the door solenoid
 |  |  wait for an ACK or NAK response. In the case of an ACK, open the door solenoid
 | 
											
												
													
														|  |  for 4 seconds. The rest of the problem is as stated above.
 |  |  for 4 seconds. The rest of the problem is as stated above.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | 
 |  | +I use `EVT_` type events to indicate that they originate in hardware, probably
 | 
											
												
													
														|  | 
 |  | +at the interrupt level; and `MSG_` type events to indicate they come from a
 | 
											
												
													
														|  | 
 |  | +software source, perhaps a sibling task.
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  Here's the modified state diagram:
 |  |  Here's the modified state diagram:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ### Beer Vat
 |  |  ### Beer Vat
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -1198,16 +1198,17 @@ Event e = {MSG_KEYPRESS, KEY_A};
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  In the old Windows system, *events/messages* were realized as a 16 bit number,
 |  |  In the old Windows system, *events/messages* were realized as a 16 bit number,
 | 
											
												
													
														|  | -with an extra 32 bit number glued to it for extra information. 
 |  | 
 | 
											
												
													
														|  | 
 |  | +with extra 16 and 32 bit numbers glued to it for extra information. 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  typedef struct MSG {
 |  |  typedef struct MSG {
 | 
											
												
													
														|  |    UINT   message;
 |  |    UINT   message;
 | 
											
												
													
														|  | 
 |  | +  WPARAM wParam;
 | 
											
												
													
														|  |    LPARAM lParam;
 |  |    LPARAM lParam;
 | 
											
												
													
														|  |  };    // some extra detail removed
 |  |  };    // some extra detail removed
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  For example, 
 |  |  For example, 
 | 
											
												
													
														|  | -`WM_CHAR=0x0102` indicates that a key was pressed, with the extra 32bit `lParam`
 |  | 
 | 
											
												
													
														|  | 
 |  | +`message == WM_CHAR == 0x0102` indicates that a key was pressed, with the `wParam`
 | 
											
												
													
														|  |  carrying the information about *which* key. 
 |  |  carrying the information about *which* key. 
 | 
											
												
													
														|  |  <hr>
 |  |  <hr>
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -1253,8 +1254,8 @@ and increment until it hits the desired limit (100 in this case).
 | 
											
												
													
														|  |  In a moderate sized project, timers like this will proliferate throughout the code,
 |  |  In a moderate sized project, timers like this will proliferate throughout the code,
 | 
											
												
													
														|  |  making it awkward to read. One solution to this is to centralize the timers.
 |  |  making it awkward to read. One solution to this is to centralize the timers.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -In all the above examples, the `timer_irq()` code is trivial, just `newEvent(EVT_TICK)`.
 |  | 
 | 
											
												
													
														|  | -Suppose we add code to the `timer_irq()` so that it can process timer counting on
 |  | 
 | 
											
												
													
														|  | 
 |  | +In all the above examples, the `timer_isr()` code is trivial, just `newEvent(EVT_TICK)`.
 | 
											
												
													
														|  | 
 |  | +Suppose we add code to the `timer_isr()` so that it can process timer counting on
 | 
											
												
													
														|  |  behalf of the tasks......
 |  |  behalf of the tasks......
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ### Timers as a Resource
 |  |  ### Timers as a Resource
 | 
											
										
											
												
													
														|  | @@ -1262,9 +1263,9 @@ behalf of the tasks......
 | 
											
												
													
														|  |  Let's create a centralized service called `setTimer(timer_index, timer_count)`. 
 |  |  Let's create a centralized service called `setTimer(timer_index, timer_count)`. 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  A task can call this service with a unique `timer_index` and a requested count. The
 |  |  A task can call this service with a unique `timer_index` and a requested count. The
 | 
											
												
													
														|  | -`timer_irq()` uses a pool of timer registers, and will count out the ticks 
 |  | 
 | 
											
												
													
														|  | 
 |  | +`timer_isr()` uses a pool of timer registers, and will count out the ticks 
 | 
											
												
													
														|  |  on behalf of the task, and when the tick
 |  |  on behalf of the task, and when the tick
 | 
											
												
													
														|  | -count is finished, the `timer_irq()` code can generate a unique event, perhaps
 |  | 
 | 
											
												
													
														|  | 
 |  | +count is finished, the `timer_isr()` code can generate a unique event, perhaps
 | 
											
												
													
														|  |  `EVT_TIMER_n`. 
 |  |  `EVT_TIMER_n`. 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  So the state code can then look something like this:
 |  |  So the state code can then look something like this:
 | 
											
										
											
												
													
														|  | @@ -1294,7 +1295,7 @@ void stateCode(char event) {
 | 
											
												
													
														|  |  This makes the state code simpler to read, 
 |  |  This makes the state code simpler to read, 
 | 
											
												
													
														|  |  hiding all the increments/decrements and limit testing.
 |  |  hiding all the increments/decrements and limit testing.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -The overhead for this ends up in the `timer_irq()` code, 
 |  | 
 | 
											
												
													
														|  | 
 |  | +The overhead for this ends up in the `timer_isr()` code, 
 | 
											
												
													
														|  |  and might look something like this:
 |  |  and might look something like this:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
										
											
												
													
														|  | @@ -1303,7 +1304,7 @@ static uint16 timers[NUM_TIMERS];
 | 
											
												
													
														|  |  enum {EVENT_TIMER_1=EVT_TIMER_OFFSET, EVENT_TIMER_2, EVENT_TIMER_3}; // 100, 101...
 |  |  enum {EVENT_TIMER_1=EVT_TIMER_OFFSET, EVENT_TIMER_2, EVENT_TIMER_3}; // 100, 101...
 | 
											
												
													
														|  |  enum {TIMER_1, TIMER_2, TIMER_3};   // 0,1,2,....
 |  |  enum {TIMER_1, TIMER_2, TIMER_3};   // 0,1,2,....
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void timer_irq() {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void timer_isr() {
 | 
											
												
													
														|  |    newEvent(EVT_TICK);           // the main tick, fires every time
 |  |    newEvent(EVT_TICK);           // the main tick, fires every time
 | 
											
												
													
														|  |    for (i=0; i<NUM_TIMERS) {     // the system timers, fires on completion
 |  |    for (i=0; i<NUM_TIMERS) {     // the system timers, fires on completion
 | 
											
												
													
														|  |      if (timers[i]>0) {
 |  |      if (timers[i]>0) {
 | 
											
										
											
												
													
														|  | @@ -1321,7 +1322,7 @@ void setTimer(int timerIndex, unsigned int timerCount) {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  <details><summary>Reality Check</summary>
 |  |  <details><summary>Reality Check</summary>
 | 
											
												
													
														|  |  On a typical microcontroller running at 24MHz, with 5 timers, this adds about
 |  |  On a typical microcontroller running at 24MHz, with 5 timers, this adds about
 | 
											
												
													
														|  | -2 microseconds of extra time to the `timer_irq()` code, which typically runs every 
 |  | 
 | 
											
												
													
														|  | 
 |  | +2 microseconds of extra time to the `timer_isr()` code, which typically runs every 
 | 
											
												
													
														|  |  10 or 100msec. It simplifies the task code, makes it more legible
 |  |  10 or 100msec. It simplifies the task code, makes it more legible
 | 
											
												
													
														|  |  and probably reduces bugs that may appear by duplication of code.
 |  |  and probably reduces bugs that may appear by duplication of code.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -1339,7 +1340,7 @@ INTERRUPT timer_isr(void) {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  // .... state code ...
 |  |  // .... state code ...
 | 
											
												
													
														|  |  static int targetTime;
 |  |  static int targetTime;
 | 
											
												
													
														|  | -void stateCode(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void stateCode(uchar event) {
 | 
											
												
													
														|  |    switch(state) {
 |  |    switch(state) {
 | 
											
												
													
														|  |      case STATE1:
 |  |      case STATE1:
 | 
											
												
													
														|  |        //..... set a target
 |  |        //..... set a target
 | 
											
										
											
												
													
														|  | @@ -1399,15 +1400,15 @@ void gpio_set(uint32 bitPosition, bool value) {
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  /***** events ****/
 |  |  /***** events ****/
 | 
											
												
													
														|  |  #define NUM_EVENTS 10
 |  |  #define NUM_EVENTS 10
 | 
											
												
													
														|  | -volatile uint8 events[NUM_EVENTS];
 |  | 
 | 
											
												
													
														|  | 
 |  | +volatile uchar events[NUM_EVENTS];
 | 
											
												
													
														|  |  enum { EVT_NONE,
 |  |  enum { EVT_NONE,
 | 
											
												
													
														|  |        EVT_TICK,
 |  |        EVT_TICK,
 | 
											
												
													
														|  |        EVT_BUTTON};
 |  |        EVT_BUTTON};
 | 
											
												
													
														|  | -void newEvent(uint8 e);
 |  | 
 | 
											
												
													
														|  | 
 |  | +void newEvent(uchar e);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /********** tasks ***********/
 |  |  /********** tasks ***********/
 | 
											
												
													
														|  | -void ledTask(uint8 evt);
 |  | 
 | 
											
												
													
														|  | -void respondToButtonTask(uint8 evt);
 |  | 
 | 
											
												
													
														|  | 
 |  | +void ledTask(uchar evt);
 | 
											
												
													
														|  | 
 |  | +void respondToButtonTask(uchar evt);
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  /********** interrupts **************/
 |  |  /********** interrupts **************/
 | 
											
												
													
														|  |  volatile uint32 tick;   // increasing at 100 ticks/sec
 |  |  volatile uint32 tick;   // increasing at 100 ticks/sec
 | 
											
										
											
												
													
														|  | @@ -1503,11 +1504,11 @@ void main(void) {
 | 
											
												
													
														|  |  /*********** task code, with states ************/
 |  |  /*********** task code, with states ************/
 | 
											
												
													
														|  |  enum {LED_ON, LED_OFF};
 |  |  enum {LED_ON, LED_OFF};
 | 
											
												
													
														|  |  enum {RTB_IDLE, RTB_ON};    // states
 |  |  enum {RTB_IDLE, RTB_ON};    // states
 | 
											
												
													
														|  | -static uint8 rtbState            = RTB_IDLE;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar rtbState            = RTB_IDLE;
 | 
											
												
													
														|  |  static uint16 rtbTimerCount      = 0;
 |  |  static uint16 rtbTimerCount      = 0;
 | 
											
												
													
														|  |  const  uint16 BUTTON_LED_ON_TIME = 150;
 |  |  const  uint16 BUTTON_LED_ON_TIME = 150;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void respondToButtonTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void respondToButtonTask(uchar evt) {
 | 
											
												
													
														|  |    switch(rtbState) {
 |  |    switch(rtbState) {
 | 
											
												
													
														|  |      case RTB_IDLE:
 |  |      case RTB_IDLE:
 | 
											
												
													
														|  |        if (evt == EVT_BUTTON) {
 |  |        if (evt == EVT_BUTTON) {
 | 
											
										
											
												
													
														|  | @@ -1529,10 +1530,10 @@ void respondToButtonTask(uint8 evt) {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  const int LED_ON_TIME  = 150;
 |  |  const int LED_ON_TIME  = 150;
 | 
											
												
													
														|  |  const int LED_OFF_TIME = 50;
 |  |  const int LED_OFF_TIME = 50;
 | 
											
												
													
														|  | -static uint8  ledState      = LED_OFF;
 |  | 
 | 
											
												
													
														|  | 
 |  | +static uchar  ledState      = LED_OFF;
 | 
											
												
													
														|  |  static uint16 ledTimerCount = 0;
 |  |  static uint16 ledTimerCount = 0;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -void ledTask(uint8 evt) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +void ledTask(uchar evt) {
 | 
											
												
													
														|  |    switch(ledState) {
 |  |    switch(ledState) {
 | 
											
												
													
														|  |      case LED_OFF:
 |  |      case LED_OFF:
 | 
											
												
													
														|  |        if (evt == EVT_TICK) {
 |  |        if (evt == EVT_TICK) {
 | 
											
										
											
												
													
														|  | @@ -1606,8 +1607,8 @@ simplifies:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -uint8 rtbState = RTB_IDLE;              // major state, RTB_IDLE/RTB_FLASHING
 |  | 
 | 
											
												
													
														|  | -uint8 rtbSubState = RTB_FLASH_OFF;      // minor state, toggles LED on/off
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar rtbState = RTB_IDLE;              // major state, RTB_IDLE/RTB_FLASHING
 | 
											
												
													
														|  | 
 |  | +uchar rtbSubState = RTB_FLASH_OFF;      // minor state, toggles LED on/off
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  Alternatively, you could use the *timer counter*
 |  |  Alternatively, you could use the *timer counter*
 | 
											
										
											
												
													
														|  | @@ -1620,7 +1621,7 @@ variable, and make changes at the half-way point through the count.
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  |  const uint16 FLASH_CYCLE_TIME 150;
 |  |  const uint16 FLASH_CYCLE_TIME 150;
 | 
											
												
													
														|  |  const uint16 FLASH_ON_TIME 40;
 |  |  const uint16 FLASH_ON_TIME 40;
 | 
											
												
													
														|  | -uint8 rtbState = STATE_IDLE;
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar rtbState = STATE_IDLE;
 | 
											
												
													
														|  |  void rtbTaskCode(char event) {
 |  |  void rtbTaskCode(char event) {
 | 
											
												
													
														|  |    static uint16 flashCount=0;
 |  |    static uint16 flashCount=0;
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -1677,8 +1678,8 @@ Then, in the state code, you can catch that event and set up whatever might
 | 
											
												
													
														|  |  be required
 |  |  be required
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -uint8 myState;
 |  | 
 | 
											
												
													
														|  | -void stateCode(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar myState;
 | 
											
												
													
														|  | 
 |  | +void stateCode(uchar event) {
 | 
											
												
													
														|  |    if (event==EVT_INIT) {
 |  |    if (event==EVT_INIT) {
 | 
											
												
													
														|  |      // ... do setup code
 |  |      // ... do setup code
 | 
											
												
													
														|  |      myState = FIRST_STATE;
 |  |      myState = FIRST_STATE;
 | 
											
										
											
												
													
														|  | @@ -1707,7 +1708,7 @@ only be called from interrupts.
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void postMessage(uint8 message);
 |  | 
 | 
											
												
													
														|  | 
 |  | +void postMessage(uchar message);
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  Notice that `postMessage` can't return any information, because it's not 
 |  |  Notice that `postMessage` can't return any information, because it's not 
 | 
											
										
											
												
													
														|  | @@ -1726,7 +1727,8 @@ In some cases we may want the sibling task to process the information immediatel
 | 
											
												
													
														|  |  This means:
 |  |  This means:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  - we can be assured that the sibling task has fully processed the information
 |  |  - we can be assured that the sibling task has fully processed the information
 | 
											
												
													
														|  | -- does not involve the dispatcher; but does require extra room on the stack
 |  | 
 | 
											
												
													
														|  | 
 |  | +- does not involve the dispatcher
 | 
											
												
													
														|  | 
 |  | +- requires extra room on the stack, since we're calling within a call
 | 
											
												
													
														|  |  - we *could* get a return value from the sibling task; since it's implemented as
 |  |  - we *could* get a return value from the sibling task; since it's implemented as
 | 
											
												
													
														|  |  a subroutine, it's allowed to return a value
 |  |  a subroutine, it's allowed to return a value
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -1735,15 +1737,15 @@ a subroutine, it's allowed to return a value
 | 
											
												
													
														|  |  To return a value means that the prototype for task functions would change from 
 |  |  To return a value means that the prototype for task functions would change from 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -void taskCode(uint8 event);
 |  | 
 | 
											
												
													
														|  | 
 |  | +void taskCode(uchar event);
 | 
											
												
													
														|  |  to
 |  |  to
 | 
											
												
													
														|  | -uint8 taskCode(uint8 event);
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar taskCode(uchar event);
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  The service routine to send a message like this would look like:
 |  |  The service routine to send a message like this would look like:
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  ```C
 |  |  ```C
 | 
											
												
													
														|  | -uint8 SendMessage(int8 taskPointer(uint8), uint8 message) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar SendMessage(int8 taskPointer(uchar), uchar message) {
 | 
											
												
													
														|  |    return taskPointer(message);
 |  |    return taskPointer(message);
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  ```
 |  |  ```
 | 
											
										
											
												
													
														|  | @@ -1752,7 +1754,8 @@ uint8 SendMessage(int8 taskPointer(uint8), uint8 message) {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  Why might one want to *send a message* between tasks?
 |  |  Why might one want to *send a message* between tasks?
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -Suppose you have a rotary encoder, which sends quadrant signals, which need
 |  | 
 | 
											
												
													
														|  | 
 |  | +**PostMessage()** Suppose you have a rotary encoder, which sends 
 | 
											
												
													
														|  | 
 |  | +quadrant signals, which need
 | 
											
												
													
														|  |  to be interpreted as *clockwise* and *counter clockwise*. You could have one
 |  |  to be interpreted as *clockwise* and *counter clockwise*. You could have one
 | 
											
												
													
														|  |  task devoted to determining the direction of the knob 
 |  |  task devoted to determining the direction of the knob 
 | 
											
												
													
														|  |  (and [debouncing](#debouncing)), and have it *send* (or *post*) clean 
 |  |  (and [debouncing](#debouncing)), and have it *send* (or *post*) clean 
 | 
											
										
											
												
													
														|  | @@ -1763,7 +1766,7 @@ For example, a device which has
 | 
											
												
													
														|  |  a temperature set by "up/down" buttons on a front panel could receive the same
 |  |  a temperature set by "up/down" buttons on a front panel could receive the same
 | 
											
												
													
														|  |  controls from an infra-red remote, or even a serial port (perhaps for testing).
 |  |  controls from an infra-red remote, or even a serial port (perhaps for testing).
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -And why `sendMessage()`? Perhaps you need to have a sibling task change
 |  | 
 | 
											
												
													
														|  | 
 |  | +**SendMessage()** Perhaps you need to have a sibling task change
 | 
											
												
													
														|  |  states, or process information *before* you continue in your task. Imagine
 |  |  states, or process information *before* you continue in your task. Imagine
 | 
											
												
													
														|  |  there is a slave WiFi chip that needs to be powered up *before* you send it
 |  |  there is a slave WiFi chip that needs to be powered up *before* you send it
 | 
											
												
													
														|  |  a request....you could use `sendMessage()` to activate the power, and then
 |  |  a request....you could use `sendMessage()` to activate the power, and then
 | 
											
										
											
												
													
														|  | @@ -1819,8 +1822,8 @@ uint16 radioTimer = 0;
 | 
											
												
													
														|  |  const uint16 radioTimeout = 5;  // 0.5 seconds
 |  |  const uint16 radioTimeout = 5;  // 0.5 seconds
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  enum {IDLE, FREQ_UP, FREQ_UP_FAST, FREQ_DN, FREQ_DN_FAST};
 |  |  enum {IDLE, FREQ_UP, FREQ_UP_FAST, FREQ_DN, FREQ_DN_FAST};
 | 
											
												
													
														|  | -uint8 state = IDLE;
 |  | 
 | 
											
												
													
														|  | -void radioTask(uint8 event) {
 |  | 
 | 
											
												
													
														|  | 
 |  | +uchar state = IDLE;
 | 
											
												
													
														|  | 
 |  | +void radioTask(uchar event) {
 | 
											
												
													
														|  |    switch(state) {
 |  |    switch(state) {
 | 
											
												
													
														|  |      case IDLE:
 |  |      case IDLE:
 | 
											
												
													
														|  |        if (event == EVT_UP_PRESS) {
 |  |        if (event == EVT_UP_PRESS) {
 |