This repo provides a driver to receive from IR (infra red) remote controls and
a driver for IR "blaster" apps. The device drivers are nonblocking. They do not
-require `uasyncio` but are compatible with it.
+require `uasyncio` but are compatible with it, and are designed for standard
+firmware builds.
+
+The receiver is cross platform and has been tested on Pyboard, ESP8266, ESP32
+and Raspberry Pi Pico.
+
+In a typical use case the receiver is employed at the REPL to sniff the address
+and data values associated with buttons on a remote control. The transmitter is
+then used in an application to send those codes, emulating the remote control.
+
+Other use cases involve running the receiver in an application. This enables an
+IR remote to control a device such as a robot. This may be problematic on some
+platforms. Please see [section 4](./README.md#4-receiver-limitations).
+
+## Raspberry Pi Pico note
+
+Early firmware has [this issue](https://github.com/micropython/micropython/issues/6866)
+affecting USB communication with some PC's. This is now fixed. Please ensure
+you are using up to date firmware.
+
+#### [Receiver docs](./RECEIVER.md)
+
+The transmitter driver is compatible with Pyboard (1.x and D series) and ESP32.
+ESP8266 is unsupported; it seems incapable of generating the required signals.
+
+#### [Transmitter docs](./TRANSMITTER.md)
# 1. IR communication
IR communication uses a carrier frequency to pulse the IR source. Modulation
takes the form of OOK (on-off keying). There are multiple protocols and at
-least three options for carrier frequency, namely 36KHz, 38KHz and 40KHz.
+least three options for carrier frequency: 36, 38 and 40KHz.
+
+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 purchased for the correct frequency. The receiver device driver sees
+the demodulated signal and is hence carrier frequency agnostic.
+
+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.
-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
-device driver sees the demodulated signal and is hence carrier frequency
-agnostic.
+# 2. Supported protocols
+
+The drivers support NEC and Sony protocols plus two Philips protocols, namely
+RC-5 and RC-6 mode 0. There is also support for the OrtekMCE protocol used on
+VRC-1100 remotes. These originally supported Microsoft Media Center but can be
+used to control Kodi and (with a suitable receiver) to emulate a PC keyboard.
+The Samsung protocol (NEC variant) is also supported.
Examining waveforms from various remote controls it is evident that numerous
protocols exist. Some are doubtless proprietary and undocumented. The supported
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
+is for the NEC version. It has conservative timing and good provision 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.
+# 3. Hardware Requirements
-# 2. Hardware Requirements
+These are discussed in detail in the relevant docs; the following provides an
+overview.
The receiver is cross-platform. It requires an IR receiver chip to demodulate
the carrier. The chip must be selected for the frequency in use by the remote.
For 38KHz devices a receiver chip such as the Vishay TSOP4838 or the
[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.
+microcontroller.
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 transmitter requires a Pyboard 1.x (not Lite), a Pyboard D, an ESP32 or
+Raspberry Pico (RP2). Output is via an IR LED which will need a transistor to
+provide sufficient current.
-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.
-Typically these need 50-100mA of drive to achieve reasonable range and data
-integrity. A suitable LED is [this one](https://www.adafruit.com/product/387).
+## 3.1 Carrier frequencies
-The transmitter test script assumes pin X1 for IR output. It can be changed,
-but it must support Timer 2 channel 1. Pins for pushbutton inputs are
-arbitrary: X3 and X4 are used.
-
-# 3. Installation
-
-On import, demos print an explanation of how to run them.
-
-## 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.
-
-There are no dependencies.
+These are as follows. The Panasonic remote appears to use a proprietary
+protocol and is not supported by these drivers.
-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.
-
-## 3.2 Transmitter
-
-Copy the following files to the Pyboard filesystem:
- 1. `ir_tx.py` The transmitter device driver.
- 2. `ir_tx_test.py` Demo of a 2-button remote controller.
-
-The device driver has no dependencies. The test program requires `uasyncio`
-from the official library and `aswitch.py` from
-[this repo](https://github.com/peterhinch/micropython-async).
+| Protocol | F KHz | How found | Support |
+|:---------:|:-----:|:-------------:|:-------:|
+| NEC | 38 | Measured | Y |
+| RC-5 RC-6 | 36 | Spec/measured | Y |
+| Sony | 40 | Spec/measured | Y |
+| MCE | 38 | Measured | Y |
+| Samsung | 38 | Measured | Y |
+| Panasonic | 36.3 | Measured | N |
-# 4. Receiver
+# 4. Receiver limitations
-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.
+The receiver uses a pin interrupt and depends on a quick response to a state
+change on the pin. This is guaranteed on platforms which support hard IRQ's
+such as the Pyboard and the RP4 Pico. The ESP32 and ESP8266 only support soft
+IRQ's. This means that, if code such as WiFi communication is running
+concurrently, reliable reception may be problematic.
-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`
-
-Args (all protocols):
- 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.
- Choosing a value matching your remote improves the timing and reduces the
- likelihood of errors when handling repeats: the SIRC timing when a button is
- held down is tight in 20 bit mode.
-
-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.
- 4. Any args passed to the constructor.
-
-Class variable:
- 1. `verbose=False` If `True` emits debug output.
-
-# 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).
-
-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.
-
-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.
-
-`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
-200µs pulses on occasion, especially when using the ESP8266.
-`BADBLOCK` A normal data block: too few edges received. Occurs on the ESP8266
-owing to high interrupt latency.
-`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
-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.
-
-# 4.3 Principle of operation
-
-Protocol classes inherit from the abstract base class `IR_RX`. This uses a pin
-interrupt to store in an array the start and end times of pulses (in μs).
-Arrival of the first pulse triggers a software timer which runs for the
-expected duration of an IR block (`tblock`). When it times out its callback
-(`.decode`) decodes the data and calls the user callback. The use of a software
-timer ensures that `.decode` and the user callback can allocate.
-
-The size of the array and the duration of the timer are protocol dependent and
-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
-for a repeat code. Philips codes: RC-5 900μs, RC-6 mode 0 5.5ms.
-
-# 5 Transmitter
-
-This is specific to Pyboard D and Pyboard 1.x (not Lite).
-
-It implements a class for each supported protocol, namely `NEC`, `SONY`, `RC5`
-and `RC6_M0`. The application instantiates the appropriate class and calls the
-`transmit` method to send data.
-
-Constructor
-All constructors take the following args:
- 1. `pin` An initialised `pyb.Pin` instance supporting Timer 2 channel 1: `X1`
- is employed by the test script. Must be connected to the IR diode as described
- below.
- 2. `freq=default` The carrier frequency in Hz. The default for NEC is 38000,
- Sony is 40000 and Philips is 36000.
- 3. `verbose=False` If `True` emits debug output.
-
-The `SONY` constructor is of form `pin, bits=12, freq=40000, verbose=False`.
-The `bits` value may be 12, 15 or 20 to set the highest SIRC variant in use.
-Other args are as above. If `bits` is set to 20 then all variants will be
-received. Setting the value to the maximum expected improves error checking and
-timing tolerances. In particular 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.
-
-Method:
- 1. `transmit(addr, data, toggle=0)` Integer args. `addr` and `data` are
- normally 8-bit values and `toggle` is normally 0 or 1.
- In the case of NEC, if an address < 256 is passed, normal mode is assumed and
- the complementary value is appended. 16-bit values are transmitted as extended
- addresses.
- In the case of NEC the `toggle` value is ignored. For Philips protocols it
- should be toggled each time a button is pressed, and retained if the button is
- held down. The test program illustrates a way to do this.
- `SONY` ignores `toggle` unless in 20-bit mode, in which case it is transmitted
- as the `extended` value and can be any integer in range 0 to 255.
-
-The `transmit` method is synchronous with rapid return. Actual transmission
-occurs as a background process, controlled by timers 2 and 5. Execution times
-on a Pyboard 1.1 were 3.3ms for NEC, 1.5ms for RC5 and 2ms for RC6.
-
-# 5.1 Wiring
-
-I use the following circuit which delivers just under 40mA to the diode. R2 may
-be reduced for higher current.
-
-
-This alternative delivers a constant current of about 53mA if a higher voltage
-than 5V is available. R4 determines the current value and may be reduced to
-increase power.
-
-
-The transistor type is not critical.
-
-These circuits assume 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.
-
-# 5.2 Principle of operation
-
-The classes inherit from the abstract base class `IR`. This has an array `.arr`
-to contain the duration (in μs) of each carrier on or off period. The
-`transmit` method calls a `tx` method of the subclass which populates this
-array. On completion `transmit` appends a special `STOP` value and initiates
-physical transmission which occurs in an interrupt context.
-
-This is performed by two hardware timers initiated in the constructor. Timer 2,
-channel 1 is used to configure the output pin as a PWM channel. Its frequency
-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%.
-
-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
-and re-initialises T5 for the new duration.
-
-The `IR.append` enables times to be added to the array, keeping track of the
-notional carrier on/off state for biphase generation. The `IR.add` method
-facilitates lengthening a pulse as required in the biphase sequences used in
-Philips protocols.
-
-# 6. References
-
-The NEC protocol is described in these references:
-[altium](http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol)
-[circuitvalley](http://www.circuitvalley.com/2013/09/nec-protocol-ir-infrared-remote-control.html)
+# 5. References
-The Philips protocols may be found in these refs:
-[RC5](https://en.wikipedia.org/wiki/RC-5)
-[RC6](https://www.sbprojects.net/knowledge/ir/rc6.php)
+Sources of information about IR protocols. The `sbprojects.net` site is an
+excellent resource.
+[General information about IR](https://www.sbprojects.net/knowledge/ir/)
-Sony protocol (future use):
-[SIRC](https://www.sbprojects.net/knowledge/ir/sirc.php)
+Also [IRMP](https://www.mikrocontroller.net/articles/IRMP_-_english)
-# Appendix 1 NEC Protocol description
+The NEC protocol:
+[altium](http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol)
+[circuitvalley](http://www.circuitvalley.com/2013/09/nec-protocol-ir-infrared-remote-control.html)
+[sbprojects.net](https://www.sbprojects.net/knowledge/ir/nec.php)
-A normal burst comprises exactly 68 edges, the exception being a repeat code
-which has 4. An incorrect number of edges is treated as an error. All bursts
-begin with a 9ms pulse. In a normal code this is followed by a 4.5ms space; a
-repeat code is identified by a 2.25ms space. A data burst lasts for 67.5ms.
+The Samsung protocol:
+[Rustic Engineering](https://rusticengineering.wordpress.com/2011/02/09/infrared-room-control-with-samsung-ir-protocol/)
+[TechDesign Electronics](https://www.techdesign.be/projects/011/011_waves.htm) Waveforms of various protocols.
-Data bits comprise a 562.5µs mark followed by a space whose length determines
-the bit value. 562.5µs denotes 0 and 1.6875ms denotes 1.
-In 8 bit address mode the complement of the address and data values is sent to
-provide error checking. This also ensures that the number of 1's and 0's in a
-burst is constant, giving a constant burst length of 67.5ms. In extended
-address mode this constancy is lost. The burst length can (by my calculations)
-run to 76.5ms.
+Philips protocols:
+[RC5 Wikipedia](https://en.wikipedia.org/wiki/RC-5)
+[RC5 sbprojects.net](https://www.sbprojects.net/knowledge/ir/rc5.php)
+[RC6 sbprojects.net](https://www.sbprojects.net/knowledge/ir/rc6.php)
-A pin interrupt records the time of every state change (in µs). The first
-interrupt in a burst sets an event, passing the time of the state change. A
-coroutine waits on the event, yields for the duration of a data burst, then
-decodes the stored data before calling the user-specified callback.
+Sony protocol:
+[SIRC sbprojects.net](https://www.sbprojects.net/knowledge/ir/sirc.php)
-Passing the time to the `Event` instance enables the coro to compensate for
-any asyncio latency when setting its delay period.
+MCE protocol:
+[OrtekMCE](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE)
-The algorithm promotes interrupt handler speed over RAM use: the 276 bytes used
-for the data array could be reduced to 69 bytes by computing and saving deltas
-in the interrupt service routine.
+IR decoders (C sourcecode):
+[in the Linux kernel](https://github.com/torvalds/linux/tree/master/drivers/media/rc)