a driver for IR "blaster" apps. The device drivers are nonblocking. They do not
require `uasyncio` but are compatible with it.
+The transmitter driver is specific to the Pyboard. The receiver is cross
+platform and has been tested on Pyboard, ESP8266 and ESP32. See
+[Receiver platforms](./README.md#42-receiver-platforms) for test results and
+limitations.
+
# 1. IR communication
IR communication uses a carrier frequency to pulse the IR source. Modulation
The drivers support NEC and Sony protocols and two Philips protocols, namely
RC-5 and RC-6 mode 0. In the case of the transmitter the carrier frequency is a
runtime parameter: any value may be specified. The receiver uses a hardware
-demodulator which should be specified for the correct frequency. The receiver
+demodulator which should be purchased for the correct frequency. The receiver
device driver sees the demodulated signal and is hence carrier frequency
agnostic.
protocols are those for which I managed to locate documentation. My preference
is for the NEC version. It has conservative timing and ample scope for error
detection. RC-5 has limited error detection, and RC-6 mode 0 has rather fast
-timing: I doubt that detection can be accomplished on targets slower than a
-Pyboard.
+timing.
A remote using the NEC protocol is [this one](https://www.adafruit.com/products/389).
-Remotes normally transmit an address and a data byte. The address denotes the
-physical device being controlled. The data is associated with the button on the
-remote. Provision exists for differentiating between a button repeatedly
-pressed and one which is held down; the mechanism is protocol dependent.
+Remotes transmit an address and a data byte, plus in some cases an extra value.
+The address denotes the physical device being controlled. The data defines the
+button on the remote. Provision usually exists for differentiating between a
+button repeatedly pressed and one which is held down; the mechanism is protocol
+dependent.
# 2. Hardware Requirements
[adafruit one](https://www.adafruit.com/products/157) is required. This
demodulates the 38KHz IR pulses and passes the demodulated pulse train to the
microcontroller. The tested chip returns a 0 level on carrier detect, but the
-driver design should ensure operation regardless of sense.
+driver design ensures operation regardless of sense.
In my testing a 38KHz demodulator worked with 36KHz and 40KHz remotes, but this
-is obviously not guaranteed or optimal.
+is obviously neither guaranteed nor optimal.
-The pin used to connect the decoder chip to the target is arbitrary but the
-test programs assume pin X3 on the Pyboard, pin 13 on the ESP8266 and pin 23 on
-ESP32.
+The pin used to connect the decoder chip to the target is arbitrary. The test
+program assumes pin X3 on the Pyboard, pin 23 on ESP32 and pin 13 on ESP8266.
+On the WeMos D1 Mini the equivalent pin is D7.
The transmitter requires a Pyboard 1.x (not Lite) or a Pyboard D. Output is via
an IR LED which will normally need a transistor to provide sufficient current.
## 3.1 Receiver
-Copy the following files to the target filesystem:
- 1. `ir_rx.py` The receiver device driver.
- 2. `ir_rx_test.py` Demo of a receiver.
+This is a Python package. This minimises RAM usage: applications only import
+the device driver for the protocol in use.
+
+Copy the following to the target filesystem:
+ 1. `ir_rx` Directory and contents. Contains device drivers and test script.
There are no dependencies.
+The test script may be used to characterise remote controls. To run it issue:
+```python
+from ir_rx import test
+```
+The script will display instructions for running against the various protocols.
+If you are unsure which protocol your remote uses, try each one in turn. If
+none of the options work it may be that an unsupported protocol is in use.
+
The demo can be used to characterise IR remotes. It displays the codes returned
-by each button. This can aid in the design of receiver applications. When the
-demo runs, the REPL prompt reappears: this is because it sets up an ISR context
-and returns. Press `ctrl-d` to cancel it. A real application would run code
-after initialising reception so this behaviour would not occur.
+by each button. This can aid in the design of receiver applications. The demo
+prints "running" every 5 seconds and reports any data received from the remote.
## 3.2 Transmitter
# 4. Receiver
-This implements a class for each supported protocol, namely `NEC_IR`,
-`SONY_IR`, `RC5_IR` and `RC6_M0`. Applications should instantiate the
-appropriate class with a callback. The callback will run whenever an IR pulse
-train is received.
+This implements a class for each supported protocol. Applications should
+instantiate the appropriate class with a callback. The callback will run
+whenever an IR pulse train is received. Example running on a Pyboard:
-Constructor:
-`NEC_IR` args: `pin`, `callback`, `extended=True`, `*args`
-`SONY_IR` args: `pin`, `callback`, `bits=20`, `*args`
-`RC5_IR` and `RC6_M0`: args `pin`, `callback`, `*args`
+```python
+import time
+from machine import Pin
+from pyb import LED
+from ir_rx.nec import NEC_8 # NEC remote, 8 bit addresses
+
+red = LED(1)
+
+def callback(data, addr, ctrl):
+ if data < 0: # NEC protocol sends repeat codes.
+ print('Repeat code.')
+ else:
+ print('Data {:02x} Addr {:04x}'.format(data, addr))
+
+ir = NEC_8(Pin('X3', Pin.IN), callback)
+while True:
+ time.sleep_ms(500)
+ red.toggle()
+```
-Args (all protocols):
+#### Common to all classes
+
+Constructor:
+Args:
1. `pin` is a `machine.Pin` instance configured as an input, connected to the
IR decoder chip.
- 2. `callback` is the user supplied callback (see below).
- 4. `*args` Any further args will be passed to the callback.
-
-Protocol specific args:
- 1. `extended` is an NEC specific boolean. Remotes using the NEC protocol can
- send 8 or 16 bit addresses. If `True` 16 bit addresses are assumed - an 8 bit
- address will be correctly received. Set `False` to enable extra error checking
- for remotes that return an 8 bit address.
- 2. `bits=20` Sony specific. The SIRC protocol comes in 3 variants: 12, 15 and
- 20 bits. The default will handle bitstreams from all three types of remote. A
- value matching your remote improves the timing and reduces the likelihood of
- errors when handling repeats: in 20-bit mode SIRC timing when a button is held
- down is tight. A worst-case 20-bit block takes 39ms nominal, yet the repeat
- time is 45ms nominal.
- The Sony remote tested issues both 12 bit and 15 bit streams.
-
-The callback takes the following args:
- 1. `data` Integer value fom the remote. A negative value indicates an error
- except for the value of -1 which signifies an NEC repeat code (see below).
- 2. `addr` Address from the remote
- 3. `ctrl` 0 in the case of NEC. Philips protocols toggle this bit on repeat
- button presses. If the button is held down the bit is not toggled. The
- transmitter demo implements this behaviour.
- In the case of Sony the value will be 0 unless receiving a 20-bit stream, in
- which case it will hold the extended value.
+ 2. `callback` is the user supplied callback.
+ 3. `*args` Any further args will be passed to the callback.
+
+The user callback takes the following args:
+ 1. `data` (`int`) Value from the remote. Normally in range 0-255. A value < 0
+ signifies an NEC repeat code.
+ 2. `addr` (`int`) Address from the remote.
+ 3. `ctrl` (`int`) The meaning of this is protocol dependent:
+ NEC: 0
+ Philips: this is toggled 1/0 on repeat button presses. If the button is held
+ down it is not toggled. The transmitter demo implements this behaviour.
+ Sony: 0 unless receiving a 20-bit stream, in which case it holds the extended
+ value.
4. Any args passed to the constructor.
-Class variable:
+Bound variable:
1. `verbose=False` If `True` emits debug output.
+Method:
+ 1. `error_function` Arg: a function taking a single arg. If this is specified
+ it will be called if an error occurs. The value corresponds to the error code
+ (see below).
+
+#### NEC classes
+
+`NEC_8`, `NEC_16`
+
+```python
+from ir_rx.nec import NEC_8
+```
+
+Remotes using the NEC protocol can send 8 or 16 bit addresses. If the `NEC_16`
+class receives an 8 bit address it will get a 16 bit value comprising the
+address in bits 0-7 and its one's complement in bits 8-15.
+The `NEC_8` class enables error checking for remotes that return an 8 bit
+address: the complement is checked and the address returned as an 8-bit value.
+A 16-bit address will result in an error.
+
+#### Sony classes
+
+`SONY_12`, `SONY_15`, `SONY_20`
+
+```python
+from ir_rx.sony import SONY_15
+```
+
+The SIRC protocol comes in 3 variants: 12, 15 and 20 bits. `SONY_20` handles
+bitstreams from all three types of remote. Choosing a class matching the remote
+improves the timing reducing the likelihood of errors when handling repeats: in
+20-bit mode SIRC timing when a button is held down is tight. A worst-case 20
+bit block takes 39ms nominal, yet the repeat time is 45ms nominal.
+A single physical remote can issue more than one type of bitstream. The Sony
+remote tested issued both 12 bit and 15 bit streams.
+
+#### Philips classes
+
+`RC5_IR`, `RC6_M0`
+
+```python
+from ir_rx.philips import RC5_IR
+```
+
+These support the RC-5 and RC-6 mode 0 protocols respectively.
+
# 4.1 Errors
IR reception is inevitably subject to errors, notably if the remote is operated
near the limit of its range, if it is not pointed at the receiver or if its
-batteries are low. So applications must check for, and usually ignore, errors.
-These are flagged by data values < `REPEAT` (-1).
+batteries are low. The user callback is not called when an error occurs.
-On the ESP8266 there is a further source of errors. This results from the large
-and variable interrupt latency of the device which can exceed the pulse
-duration. This causes pulses to be missed. This tendency is slightly reduced by
-running the chip at 160MHz.
+On ESP8266 and ESP32 there is a further source of errors. This results from the
+large and variable interrupt latency of the device which can exceed the pulse
+duration. This causes pulses to be missed or their timing measured incorrectly.
+On ESP8266 some improvment may be achieved by running the chip at 160MHz.
In general applications should provide user feedback of correct reception.
Users tend to press the key again if the expected action is absent.
-Data values passed to the callback are normally positive. Negative values
-indicate a repeat code or an error.
-
-`REPEAT` A repeat code was received.
-
-Any data value < `REPEAT` denotes an error. In general applications do not
-need to decode these, but they may be of use in debugging. For completeness
-they are listed below.
+In debugging a callback can be specified for reporting errors. The value passed
+to the error function are represented by constants indicating the cause of the
+error. These are as follows:
`BADSTART` A short (<= 4ms) start pulse was received. May occur due to IR
interference, e.g. from fluorescent lights. The TSOP4838 is prone to producing
`BADREP` A repeat block: an incorrect number of edges were received.
`OVERRUN` A normal data block: too many edges received.
`BADDATA` Data did not match check byte.
-`BADADDR` Where `extended` is `False` the 8-bit address is checked
+`BADADDR` (`NEC_IR`) If `extended` is `False` the 8-bit address is checked
against the check byte. This code is returned on failure.
# 4.2 Receiver platforms
-The NEC protocol has been tested against Pyboard, ESP8266 and ESP32 targets.
-The Philips protocols - especially RC-6 - have tighter timing constraints. I
-have not yet tested these, but I anticipate problems.
+Currently the ESP8266 suffers from [this issue](https://github.com/micropython/micropython/issues/5714).
+Testing was therefore done without WiFi connectivity.
+
+Philips protocols (especially RC-6) have tight timing constraints with short
+pulses whose length must be determined with reasonable accuracy. The Sony 20
+bit protocol also has a timing issue in that the worst case bit pattern takes
+39ms nominal, yet the repeat time is 45ms nominal. These issues can lead to
+errors particularly on slower targets. As discussed above, errors are to be
+expected. It is up to the user to decide if the error rate is acceptable.
+
+Reception was tested using Pyboard D SF2W, ESP8266 and ESP32 with signals from
+remote controls (where available) and from the tranmitter in this repo. Issues
+are listed below.
+
+NEC: No issues.
+Sony 12 and 15 bit: No issues.
+Sony 20 bit: On ESP32 some errors occurred when repeats occurred.
+Philips RC-5: On ESP32 with one remote control many errors occurred, but paired
+with the transmitter in this repo it worked.
+Philips RC-6: No issues. Only tested against the transmitter in this repo.
# 4.3 Principle of operation
are set by the subclasses. The `.decode` method is provided in the subclass.
CPU times used by `.decode` (not including the user callback) were measured on
-a Pyboard D SF2W at stock frequency. They were NEC 1ms for normal data, 100μs
+a Pyboard D SF2W at stock frequency. They were: NEC 1ms for normal data, 100μs
for a repeat code. Philips codes: RC-5 900μs, RC-6 mode 0 5.5ms.
# 5 Transmitter
The transistor type is not critical.
-These circuits assume circuits as shown. Here the carrier "off" state is 0V,
+The driver assumes circuits as shown. Here the carrier "off" state is 0V,
which is the driver default. If using a circuit where "off" is required to be
3.3V, the constant `_SPACE` in `ir_tx.py` should be changed to 100.
is set in the constructor. The OOK is performed by dynamically changing the
duty ratio using the timer channel's `pulse_width_percent` method: this varies
the pulse width from 0 to a duty ratio passed to the constructor. The NEC
-protocol defaults to 50%, the Philips ones to 30%.
+protocol defaults to 50%, the Sony and Philips ones to 30%.
The duty ratio is changed by the Timer 5 callback `._cb`. This retrieves the
next duration from the array. If it is not `STOP` it toggles the duty cycle