takes the form of OOK (on-off keying). There are multiple protocols and at
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.
+
+# 2. Supported protocols
+
The drivers support NEC and Sony protocols plus 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 purchased for the correct frequency. The receiver
-device driver sees the demodulated signal and is hence carrier frequency
-agnostic.
+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.
Examining waveforms from various remote controls it is evident that numerous
protocols exist. Some are doubtless proprietary and undocumented. The supported
A remote using the NEC protocol is [this one](https://www.adafruit.com/products/389).
-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
+# 3. Hardware Requirements
These are discussed in detail in the relevant docs; the following provides an
overview.
The transmitter requires a Pyboard 1.x (not Lite), a Pyboard D or an ESP32.
Output is via an IR LED which will need a transistor to provide sufficient
-current. The ESP32 has significant limitations as a transmitter discussed
-[here](./TRANSMITTER.md#52-esp32).
+current. The ESP32 requires an extra transistor to work as a transmitter.
+
+## 3.1 Carrier frequencies
+
+These are as follows. The Samsung and Panasonic remotes appear to use
+proprietary protocols and are not supported by these drivers.
+
+| 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 | N |
+| Panasonic | 36.3 | Measured | N |
+
+# 4. References
+
+Sources of information about IR protocols.
+[General information about IR](https://www.sbprojects.net/knowledge/ir/)
+
+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)
+
+Philips protocols:
+[RC5](https://en.wikipedia.org/wiki/RC-5)
+[RC5](https://www.sbprojects.net/knowledge/ir/rc5.php)
+[RC6](https://www.sbprojects.net/knowledge/ir/rc6.php)
+
+Sony protocol:
+[SIRC](https://www.sbprojects.net/knowledge/ir/sirc.php)
+
+MCE protocol:
+[OrtekMCE](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE)
+
+IR decoders (C sourcecode):
+[in the Linux kernel](https://github.com/torvalds/linux/tree/master/drivers/media/rc)
from ir_rx.acquire import test
test()
```
-This script is under development.
-
-It waits for a single burst from the remote and prints the timing of the pulses
-followed by its best guess at the protocol. It correctly identifies supported
-protocols, but can wrongly identify some unsupported proprietary protocols.
+This script waits for a single burst from the remote and prints the timing of
+the pulses followed by its best guess at the protocol. It correctly identifies
+supported protocols, but can wrongly identify unsupported protocols. The
+behaviour of the script exposed to an unknown protocol is unpredictable.
# 3. The driver
from ir_rx.philips import RC5_IR
```
-These support the RC-5 and RC-6 mode 0 protocols respectively.
+These support the RC-5 (including RC-5X) and RC-6 mode 0 protocols
+respectively.
+
+#### Microsoft MCE class
+
+`MCE`
+
+Typical invocation:
+```python
+from ir_rx.mce import MCE
+```
+
+I have been unable to locate a definitive specification: the protocol was
+analysed by a mixture of googling and experiment. Behaviour may change if I
+acquire new information. The protocol is known as OrtekMCE and the remote
+control is sold on eBay as VRC-1100.
+
+The remote was designed for Microsoft Media Center and is used to control Kodi
+on boxes such as the Raspberry Pi. With a suitable PC driver it can emulate a
+PC keyboard and mouse. The mouse emulation uses a different protocol: the class
+does not currently support it. Pressing mouse buttons and pad will cause the
+error function (if provided) to be called.
+
+Args passed to the callback comprise 4 bit `addr`, 6 bit `data` and 2 bit `ctrl`
+with the latter having the value 0 for the first message and 2 for the message
+sent on key release. Intermediate messages (where the key is held down) have
+value 1.
+
+There is a 4-bit checksum which is used by default. The algorithm requires an
+initial 'seed' value which my testing proved to be 4. However the only
+[documentation](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE) I
+could find stated that the value should be 3. I implemented this as a class
+variable `MCE.init_cs=4`. This enables it to be changed if some remotes use 3.
+If the value is set to -1 the check will be skipped.
# 4. Errors
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.
-# 7. References
-
-[General information about IR](https://www.sbprojects.net/knowledge/ir/)
-
-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)
-
-Philips protocols:
-[RC5](https://en.wikipedia.org/wiki/RC-5)
-[RC5](https://www.sbprojects.net/knowledge/ir/rc5.php)
-[RC6](https://www.sbprojects.net/knowledge/ir/rc6.php)
-
-Sony protocol:
-[SIRC](https://www.sbprojects.net/knowledge/ir/sirc.php)
-
# Appendix 1 NEC Protocol description
A normal burst comprises exactly 68 edges, the exception being a repeat code
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.
+
+# Appendix 2 MCE Protocol
+
+The bitstream comprises a header (2ms mark, 1ms space) followed by 16 bits of
+Manchester encoded data with a bit time of 500μs. Data are encoded
+```
+ccccddddddppaaaa
+```
+Where `aaaa` is the address, `pp` is the position (toggle) field, `dddddd` is
+data and `cccc` is a checksum. This is calculated by counting the ones in
+`ddddddppaaaa` and adding 4. Data are transmitted LSB first.
+
+The only [doc](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE) I
+could find states that the checksum seed value is 3, but this did not match the
+remote I have.
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.__init__.py` should be changed to 100.
+3.3V, the class variable `active_high` should be set `False`.
## 1.2 ESP32 Wiring
Execution times on a Pyboard 1.1 were 3.3ms for NEC, 1.5ms for RC5 and 2ms
for RC6.
+Class variable:
+ 1. `active_high=True` Normally the IR LED drive circuit turns the LED on if
+ the pin goes high. If it works with the opposite polarity the variable should
+ be set `False` before instantiating.
+
#### NEC class
+Class `NEC`. Example invocation:
+```python
+from ir_tx.nec import NEC
+```
+
This has an additional method `.repeat` (no args). This causes a repeat code to
be transmitted. Should be called every 108ms if a button is held down.
#### Sony classes
+Classes `SONY_12`, `SONY_15` and `SONY_20`. Example invocation:
+```python
+from ir_tx.sony import SONY_15
+```
+
The SIRC protocol supports three sizes, supported by the following classes:
1. 12 bit (7 data, 5 address) `SONY_12`
2. 15 bit (7 data, 8 address) `SONY_15`
#### Philips classes
+Classes `RC5` and `RC6_M0`. Example invocation:
+```python
+from ir_tx.philips import RC5
+```
+
The RC-5 protocol supports a 5 bit address and 6 or 7 bit (RC5X) data. The
driver uses the appropriate mode depending on the `data` value provided.
changes when the button is released. The application should implement this
behaviour, setting the `toggle` arg of `.transmit` to 0 or 1 as required.
+#### Microsoft MCE class
+
+Class `MCE`. Example invocation:
+```python
+from ir_tx.mce import MCE
+# MCE.init_cs = 3
+```
+There is a separate demo for the `MCE` class because of the need to send a
+message on key release. It is run by issuing:
+```python
+from ir_tx.mcetest import test
+```
+Instructions will be displayed at the REPL.
+
+I have been unable to locate a definitive specification: the protocol was
+analysed by a mixture of googling and experiment. Behaviour may change if I
+acquire new information. The protocol is known as OrtekMCE and the remote
+control is sold on eBay as VRC-1100.
+
+The remote was designed for Microsoft Media Center and is used to control Kodi
+on boxes such as the Raspberry Pi. With a suitable PC driver it can emulate a
+PC keyboard and mouse. The mouse emulation uses a different protocol: the class
+does not currently support it. Pressing mouse buttons and pad will cause the
+error function (if provided) to be called.
+
+This supports a 4 bit address, 6 bit data and 2 bit toggle. The latter should
+have a value of 0 for the first message, 1 for repeat messages, and 2 for a
+final message sent on button release.
+
+The remaining four bits are a checksum which the driver creates. The algorithm
+requires an initial 'seed' value which my testing proved to be 4. However the
+only [documentation](http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE)
+I could find stated that the value should be 3. I implemented this as a class
+variable `MCE.init_cs=4`. This enables it to be changed if some receivers
+require 3.
+
# 4. Principle of operation
## 4.1 Pyboard
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 Sony and Philips ones to 30%.
+the pulse width from 0 to a duty ratio passed to the constructor.
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
constructor converts the 0-100 duty ratio specified by the subclass to the
0-1023 range used by ESP32.
-# 5. References
-
-[General information about IR](https://www.sbprojects.net/knowledge/ir/)
-
-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)
-
-Philips protocols:
-[RC5](https://en.wikipedia.org/wiki/RC-5)
-[RC5](https://www.sbprojects.net/knowledge/ir/rc5.php)
-[RC6](https://www.sbprojects.net/knowledge/ir/rc6.php)
+## 4.3 Duty ratio
-Sony protocol:
-[SIRC](https://www.sbprojects.net/knowledge/ir/sirc.php)
+In every case where I could find a specified figure it was 30%. I measured
+that from a variety of remotes, and in every case it was close to that figure.
print('Philips RC-6 mode 0')
ok = True
- if not ok and near(burst[0], 2056) and near(burst[1], 945):
+ if not ok and near(burst[0], 2000) and near(burst[1], 1000):
if near(duration, 19000):
- print('Microsoft MCE edition protocol. Not yet supported.')
+ print('Microsoft MCE edition protocol.')
# Constant duration, variable burst length, presumably bi-phase
print('Protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration))
ok = True
irg = IR_GET(pin)
print('Waiting for IR data...')
irg.acquire()
-
-# Yamaha NEC
-# Virgin RC-5
-
-# Samsung Unknown protocol 4576 4472 67 60755
-# Panasonic Unknown protocol 3526 1679 99 54303
-# Vista MCE edition Unknown protocol 2056 945 25 18935
--- /dev/null
+# mce.py Decoder for IR remote control using synchronous code
+# Supports Microsoft MCE edition remote protocol.
+
+# Author: Peter Hinch
+# Copyright Peter Hinch 2020 Released under the MIT license
+
+# WARNING: This is experimental and subject to change.
+
+from utime import ticks_us, ticks_diff
+from ir_rx import IR_RX
+
+class MCE(IR_RX):
+ init_cs = 4 # http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE says 3
+ def __init__(self, pin, callback, *args):
+ # Block lasts ~19ms and has <= 34 edges
+ super().__init__(pin, 34, 25, callback, *args)
+
+ def decode(self, _):
+ def check(v):
+ if self.init_cs == -1:
+ return True
+ csum = v >> 12
+ cs = self.init_cs
+ for _ in range(12):
+ if v & 1:
+ cs += 1
+ v >>= 1
+ return cs == csum
+
+ try:
+ t0 = ticks_diff(self._times[1], self._times[0]) # 2000μs mark
+ t1 = ticks_diff(self._times[2], self._times[1]) # 1000μs space
+ if not ((1800 < t0 < 2200) and (800 < t1 < 1200)):
+ raise RuntimeError(self.BADSTART)
+ nedges = self.edge # No. of edges detected
+ if not 14 <= nedges <= 34:
+ raise RuntimeError(self.OVERRUN if nedges > 28 else self.BADSTART)
+ # Manchester decode
+ mask = 1
+ bit = 1
+ v = 0
+ x = 2
+ for _ in range(16):
+ # -1 convert count to index, -1 because we look ahead
+ if x > nedges - 2:
+ raise RuntimeError(self.BADBLOCK)
+ # width is 500/1000 nominal
+ width = ticks_diff(self._times[x + 1], self._times[x])
+ if not 250 < width < 1350:
+ self.verbose and print('Bad block 3 Width', width, 'x', x)
+ raise RuntimeError(self.BADBLOCK)
+ short = int(width < 750)
+ bit ^= short ^ 1
+ v |= mask if bit else 0
+ mask <<= 1
+ x += 1 + short
+
+ self.verbose and print(bin(v))
+ print(bin(v)) # TEST
+ #if not check(v):
+ #raise RuntimeError(self.BADDATA)
+ val = (v >> 6) & 0x3f
+ addr = v & 0xf # Constant for all buttons on my remote
+ ctrl = (v >> 4) & 3
+
+ except RuntimeError as e:
+ val, addr, ctrl = e.args[0], 0, 0
+ # Set up for new data burst and run user callback/error function
+ self.do_callback(val, addr, ctrl)
if not 14 <= nedges <= 28:
raise RuntimeError(self.OVERRUN if nedges > 28 else self.BADSTART)
# Regenerate bitstream
- bits = 0
+ bits = 1
bit = 1
- for x in range(1, nedges):
- width = ticks_diff(self._times[x], self._times[x - 1])
- if not 500 < width < 2000:
+ v = 1 # 14 bit bitstream, MSB always 1
+ x = 0
+ while bits < 14:
+ # -1 convert count to index, -1 because we look ahead
+ if x > nedges - 2:
+ print('Bad block 1 edges', nedges, 'x', x)
raise RuntimeError(self.BADBLOCK)
- for _ in range(1 if width < 1334 else 2):
- bits <<= 1
- bits |= bit
- bit ^= 1
- self.verbose and print(bin(bits)) # Matches inverted scope waveform
- # Decode Manchester code
- x = 30
- while not bits >> x:
- x -= 1
- m0 = 1 << x # Mask MS two bits (always 01)
- m1 = m0 << 1
- v = 0 # 14 bit bitstream
- for _ in range(14):
- v <<= 1
- b0 = (bits & m0) > 0
- b1 = (bits & m1) > 0
- if b0 == b1:
+ # width is 889/1778 nominal
+ width = ticks_diff(self._times[x + 1], self._times[x])
+ if not 500 < width < 2100:
+ self.verbose and print('Bad block 3 Width', width, 'x', x)
raise RuntimeError(self.BADBLOCK)
- v |= b0
- m0 >>= 2
- m1 >>= 2
+ short = width < 1334
+ if not short:
+ bit ^= 1
+ v <<= 1
+ v |= bit
+ bits += 1
+ x += 1 + int(short)
+ self.verbose and print(bin(v))
# Split into fields (val, addr, ctrl)
- val = (v & 0x3f) | (0x40 if ((v >> 12) & 1) else 0)
+ val = (v & 0x3f) | (0 if ((v >> 12) & 1) else 0x40) # Correct the polarity of S2
addr = (v >> 6) & 0x1f
ctrl = (v >> 11) & 1
# Set up for new data burst and run user callback
self.do_callback(val, addr, ctrl)
+
class RC6_M0(IR_RX):
# Even on Pyboard D the 444μs nominal pulses can be recorded as up to 705μs
# Scope shows 360-520 μs (-84μs +76μs relative to nominal)
# test.py Test program for IR remote control decoder
-# Supports Pyboard ESP32 and ESP8266
+# Supports Pyboard, ESP32 and ESP8266
# Author: Peter Hinch
# Copyright Peter Hinch 2020 Released under the MIT license
from ir_rx.nec import NEC_8, NEC_16
from ir_rx.sony import SONY_12, SONY_15, SONY_20
from ir_rx.philips import RC5_IR, RC6_M0
+from ir_rx.mce import MCE
# Define pin according to platform
if platform == 'pyboard':
freq(160000000)
p = Pin(13, Pin.IN)
elif platform == 'esp32' or platform == 'esp32_LoBo':
- p = Pin(23, Pin.IN) # was 27
+ p = Pin(23, Pin.IN)
# User callback
def cb(data, addr, ctrl):
print('Data {:02x} Addr {:04x} Ctrl {:02x}'.format(data, addr, ctrl))
def test(proto=0):
- classes = (NEC_8, NEC_16, SONY_12, SONY_15, SONY_20, RC5_IR, RC6_M0)
+ classes = (NEC_8, NEC_16, SONY_12, SONY_15, SONY_20, RC5_IR, RC6_M0, MCE)
ir = classes[proto](p, cb) # Instantiate receiver
ir.error_function(print_error) # Show debug information
#ir.verbose = True
# A real application would do something here...
- while True:
- print('running')
- time.sleep(5)
- gc.collect()
+ try:
+ while True:
+ print('running')
+ time.sleep(5)
+ gc.collect()
+ except KeyboardInterrupt:
+ ir.close()
# **** DISPLAY GREETING ****
s = '''Test for IR receiver. Run:
-from ir_rx import test
+from ir_rx.test import test
test() for NEC 8 bit protocol,
test(1) for NEC 16 bit,
test(2) for Sony SIRC 12 bit,
test(4) for Sony SIRC 20 bit,
test(5) for Philips RC-5 protocol,
test(6) for RC6 mode 0.
+test(7) for Microsoft Vista MCE.
Hit ctrl-c to stop, then ctrl-d to soft reset.'''
# micropython.alloc_emergency_exception_buf(100)
-# ABC and Pyboard only: ESP32 ignores this value.
-# Duty ratio in carrier off state: if driver is such that 3.3V turns the LED
-# off, set _SPACE = 100
+# Duty ratio in carrier off state.
_SPACE = const(0)
# On ESP32 gate hardware design is led_on = rmt and carrier
# carrier on or off. Physical transmission occurs in an ISR context controlled
# by timer 2 and timer 5. See README.md for details of operation.
class IR:
+ active_high = True # Hardware turns IRLED on if pin goes high.
def __init__(self, pin, cfreq, asize, duty, verbose):
+ if not IR.active_high:
+ duty = 100 - duty
if ESP32:
self._pwm = PWM(pin[0]) # Continuous 36/38/40KHz carrier
self._pwm.deinit()
self._ch = tim.channel(1, Timer.PWM, pin=pin)
self._ch.pulse_width_percent(_SPACE) # Turn off IR LED
# Pyboard: 0 <= pulse_width_percent <= 100
- self._duty = duty if not _SPACE else (100 - duty)
+ self._duty = duty
self._tim = Timer(5) # Timer 5 controls carrier on/off times
self._tcb = self._cb # Pre-allocate
self._arr = array('H', 0 for _ in range(asize)) # on/off times (μs)
--- /dev/null
+# mce.py Encoder for IR remote control using synchronous code
+# Supports Microsoft MCE edition remote protocol.
+
+# Author: Peter Hinch
+# Copyright Peter Hinch 2020 Released under the MIT license
+
+# WARNING: This is experimental and subject to change.
+
+from micropython import const
+from ir_tx import IR
+
+_TBIT = const(500) # Time (μs) for pulse of carrier
+
+
+class MCE(IR):
+ init_cs = 4 # http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE says 3
+
+ def __init__(self, pin, freq=38000, verbose=False):
+ super().__init__(pin, freq, 34, 30, verbose)
+
+ def tx(self, addr, data, toggle):
+ def checksum(v):
+ cs = self.init_cs
+ for _ in range(12):
+ if v & 1:
+ cs += 1
+ v >>= 1
+ return cs
+
+ self.append(2000, 1000, _TBIT)
+ d = ((data & 0x3f) << 6) | (addr & 0xf) | ((toggle & 3) << 4)
+ d |= checksum(d) << 12
+ self.verbose and print(bin(d))
+
+ mask = 1
+ while mask < 0x10000:
+ bit = bool(d & mask)
+ if bit ^ self.carrier:
+ self.add(_TBIT)
+ self.append(_TBIT)
+ else:
+ self.append(_TBIT, _TBIT)
+ mask <<= 1
--- /dev/null
+# ir_tx.mcetest Test for nonblocking MCE IR blaster.
+
+# Released under the MIT License (MIT). See LICENSE.
+
+# Copyright (c) 2020 Peter Hinch
+
+# Implements a 2-button remote control on a Pyboard with auto repeat.
+from sys import platform
+ESP32 = platform == 'esp32'
+if ESP32:
+ from machine import Pin
+else:
+ from pyb import Pin, LED
+
+from micropython import const
+import uasyncio as asyncio
+from aswitch import Switch, Delay_ms
+from ir_tx.mce import MCE
+
+loop = asyncio.get_event_loop()
+_FIRST = const(0)
+_REP = const(1)
+_END = const(2)
+_REP_DELAY = const(60)
+
+class Rbutton:
+ def __init__(self, irb, pin, addr, data, rep_code=False):
+ self.irb = irb
+ self.sw = Switch(pin)
+ self.addr = addr
+ self.data = data
+ self.rep_code = rep_code
+ self.sw.close_func(self.cfunc)
+ self.sw.open_func(self.ofunc)
+ self.tim = Delay_ms(self.repeat)
+ self.stop = False
+
+ def cfunc(self): # Button push: send data and set up for repeats
+ print('start')
+ self.irb.transmit(self.addr, self.data, _FIRST)
+ self.tim.trigger(_REP_DELAY)
+
+ def ofunc(self): # Button release: cancel repeat timer
+ self.stop = True
+
+ async def repeat(self):
+ await asyncio.sleep(0) # Let timer stop before retriggering
+ if self.stop: # Button has been released: send last message
+ self.stop = False
+ self.tim.stop() # Not strictly necessary
+ self.irb.transmit(self.addr, self.data, _END)
+ print('stop')
+ else:
+ print('rep')
+ self.tim.trigger(_REP_DELAY)
+ self.irb.transmit(self.addr, self.data, _REP)
+
+async def main():
+ if ESP32: # Pins for IR LED gate
+ pin = (Pin(23, Pin.OUT, value = 0), Pin(21, Pin.OUT, value = 0))
+ else:
+ pin = Pin('X1')
+ irb = MCE(pin, verbose=True)
+
+ b = [] # Rbutton instances
+ px3 = Pin(18, Pin.IN, Pin.PULL_UP) if ESP32 else Pin('X3', Pin.IN, Pin.PULL_UP)
+ px4 = Pin(19, Pin.IN, Pin.PULL_UP) if ESP32 else Pin('X4', Pin.IN, Pin.PULL_UP)
+ b.append(Rbutton(irb, px3, 0x1, 0x7))
+ b.append(Rbutton(irb, px4, 0xe, 0xb))
+ if ESP32:
+ while True:
+ print('Running')
+ await asyncio.sleep(5)
+ else:
+ led = LED(1)
+ while True:
+ await asyncio.sleep_ms(500) # Obligatory flashing LED.
+ led.toggle()
+
+# Greeting strings. Common:
+s = '''Test for IR transmitter. Run:
+from ir_tx.mcetest import test
+test()
+'''
+# Pyboard:
+spb = '''
+IR LED on pin X1
+Ground pin X3 to send addr 1 data 7
+Ground pin X4 to send addr 0xe data 0x0b.'''
+# ESP32
+sesp = '''
+IR LED gate on pins 23, 21
+Ground pin 18 to send addr 1 data 7
+Ground pin 19 to send addr 0xe data 0x0b.'''
+
+print(''.join((s, sesp)) if ESP32 else ''.join((s, spb)))
+
+def test():
+ loop.run_until_complete(main())
class NEC(IR):
def __init__(self, pin, freq=38000, verbose=False): # NEC specifies 38KHz
- super().__init__(pin, freq, 68, 50, verbose)
+ super().__init__(pin, freq, 68, 33, verbose) # Measured duty ratio 33%
def _bit(self, b):
self.append(_TBURST, _T_ONE if b else _TBURST)
# Copyright Peter Hinch 2020 Released under the MIT license
from micropython import const
-from sys import platform
from ir_tx import IR
# Philips RC5 protocol
_T_RC5 = const(889) # Time for pulse of carrier
-ermsg = 'ESP32 does not support Philips protocols'
+
+
class RC5(IR):
def __init__(self, pin, freq=36000, verbose=False):
super().__init__(pin, freq, 28, 30, verbose)
- def tx(self, addr, data, toggle):
- d = (data & 0x3f) | ((addr & 0x1f) << 6) | ((data & 0x40) << 6) | ((toggle & 1) << 11)
+ def tx(self, addr, data, toggle): # Fix RC5X S2 bit polarity
+ d = (data & 0x3f) | ((addr & 0x1f) << 6) | (((data & 0x40) ^ 0x40) << 6) | ((toggle & 1) << 11)
self.verbose and print(bin(d))
mask = 0x2000
while mask:
-# ir_tx_test.py Test for nonblocking NEC/SONY/RC-5/RC-6 mode 0 IR blaster.
+# ir_tx.test Test for nonblocking NEC/SONY/RC-5/RC-6 mode 0 IR blaster.
# Released under the MIT License (MIT). See LICENSE.
# Greeting strings. Common:
s = '''Test for IR transmitter. Run:
-from ir_tx_test import test
+from ir_tx.test import test
test() for NEC protocol
test(1) for Sony SIRC 12 bit
test(2) for Sony SIRC 15 bit