|
1 | 1 | #!/usr/bin/env python3 |
2 | | - |
| 2 | +#|| |
3 | 3 | #|| Event-Driven Input/Output |
4 | 4 | #|| ========================= |
5 | 5 | #|| |
|
15 | 15 | #|| driven_: reacting as soon as the signal at the input pin changes |
16 | 16 | #|| and using timer events to decide when to blink the LED. |
17 | 17 | #|| |
18 | | -#|| An event loop is driven by a `Selector` object, which holds a |
19 | | -#|| number of _event sources_ and waits for an event to occur on one |
20 | | -#|| of them. An event-driven program creates a Selector, creates |
21 | | -#|| _event source_ objects that can signal events, adds those event |
22 | | -#|| sources to the Selector, and repeatedly waits on the Selector for |
23 | | -#|| events to occur. |
| 18 | +#|| An event-driven program uses a `Selector` object to wait for |
| 19 | +#|| events to occur on a number of _event sources_ -- for example GPIO |
| 20 | +#|| input pins, timers or network connections. The program creates a |
| 21 | +#|| Selector, creates _event source_ objects that can signal events, |
| 22 | +#|| adds the event sources to the Selector, and runs an _event loop_ |
| 23 | +#|| in which it waits on the Selector for an events to occur and then |
| 24 | +#|| handles the latest event reported by the Selector. |
24 | 25 | #|| |
25 | 26 | #|| As we are converting the button-blink example to be event-driven, |
26 | | -#|| we have two event sources: the GPIO pin connected to the button |
27 | | -#|| and a repeating timer that, when started, tells the program when |
28 | | -#|| to blink the LED. |
| 27 | +#|| we need two event sources: the GPIO pin connected to the button |
| 28 | +#|| and, because we can't put the process to sleep for half a second |
| 29 | +#|| to blink the LED, a repeating timer that tells the program when to |
| 30 | +#|| turn the LED off it is currently on and vice versa. |
29 | 31 |
|
30 | 32 | from quick2wire.gpio import pins, In, Out, Both |
31 | 33 | from quick2wire.selector import Selector, Timer |
32 | 34 |
|
| 35 | +#| [1] We create the selector that will drive our event loop |
33 | 36 | selector = Selector() |
| 37 | +#|. |
34 | 38 | button = pins.pin(0, direction=In, interrupt=Both) |
35 | 39 | led = pins.pin(1, direction=Out) |
| 40 | + |
| 41 | +#| [2] We also create a repeating Timer to trigger the blinking of the |
| 42 | +#| LED. The _interval_ parameter specifies the time, in seconds, |
| 43 | +#| between Timer events. |
36 | 44 | timer = Timer(interval=0.5) |
| 45 | +#|. |
37 | 46 |
|
| 47 | +#| [3] Like the button and led Pins, the selector and timer consume |
| 48 | +#| operating-system resources, so we add them to the with statement to |
| 49 | +#| ensure that they are closed. |
38 | 50 | with selector, button, led, timer: |
| 51 | +#|. |
| 52 | + #| [4] We have to add the button and timer to the selector before the |
| 53 | + #| selector will report their events. |
39 | 54 | selector.add(button) |
40 | 55 | selector.add(timer) |
41 | | - |
42 | | - print("ready") |
| 56 | + #|. |
43 | 57 |
|
44 | 58 | while True: |
| 59 | + #| [5] Now the program's main loop must wait for selector |
| 60 | + #| events. When the button or timer signals an event, the |
| 61 | + #| selector stores a reference to the object that is ready to |
| 62 | + #| be processed in its _ready_ property and returns from its |
| 63 | + #| `wait()` method. |
45 | 64 | selector.wait() |
| 65 | + #|. |
| 66 | + |
| 67 | + #| [6] If the timer is ready, we invert the value of the |
| 68 | + #| led pin, so that it blinks on and off. |
| 69 | + if selector.ready == timer: |
| 70 | + #| [7] The program must "consume" the latest timer event |
| 71 | + #| by waiting for it, otherwise the timer will continually |
| 72 | + #| signal that it is ready, making our program run in a |
| 73 | + #| busy-loop. |
| 74 | + timer.wait() |
| 75 | + #|. |
| 76 | + |
| 77 | + led.value = not led.value |
| 78 | + #|. |
46 | 79 |
|
47 | | - if selector.ready == button: |
48 | | - if button.value: |
| 80 | + #| [8] If the button is ready, the program reads the |
| 81 | + #| button state. If the value at the GPIO pin is one |
| 82 | + #| (voltage high), the button has been pressed; if zero |
| 83 | + #| (voltage low), it has been released. |
| 84 | + elif selector.ready == button: |
| 85 | + is_pressed = button.value |
| 86 | + |
| 87 | + #| [9] We can use the value read from the button in an if |
| 88 | + #| statement (in Python, 0 is treated as false and 1 as |
| 89 | + #| true) |
| 90 | + if is_pressed: |
| 91 | + #|. |
| 92 | + #| [10] If the button has been pressed, the program |
| 93 | + #| turns on the LED and starts the timer, so that it |
| 94 | + #| generates the events that makes the program blinks |
| 95 | + #| the LED on and off. |
49 | 96 | led.value = 1 |
50 | 97 | timer.start() |
| 98 | + #|. |
51 | 99 | else: |
| 100 | + #| [11] If the button has been released, the program |
| 101 | + #| turns of the LED and stops the timer so that timer |
| 102 | + #| events won't turn LED on again. |
52 | 103 | led.value = 0 |
53 | 104 | timer.stop() |
54 | | - |
55 | | - elif selector.ready == timer: |
56 | | - timer.wait() |
57 | | - led.value = not led.value |
| 105 | + #|. |
| 106 | + #|. |
| 107 | +#|| When you run this program you will see that it reacts promptly to |
| 108 | +#|| button presses. |
0 commit comments