# ir_rx __init__.py Decoder for IR remote control using synchronous code # IR_RX abstract base class for IR receivers. # Author: Peter Hinch # Copyright Peter Hinch 2020-2021 Released under the MIT license from machine import Timer, Pin from array import array from utime import ticks_us # Save RAM # from micropython import alloc_emergency_exception_buf # alloc_emergency_exception_buf(100) # On 1st edge start a block timer. While the timer is running, record the time # of each edge. When the timer times out decode the data. Duration must exceed # the worst case block transmission time, but be less than the interval between # a block start and a repeat code start (~108ms depending on protocol) class IR_RX(): # Result/error codes # Repeat button code REPEAT = -1 # Error codes BADSTART = -2 BADBLOCK = -3 BADREP = -4 OVERRUN = -5 BADDATA = -6 BADADDR = -7 def __init__(self, pin, nedges, tblock, callback, *args): # Optional args for callback self._pin = pin self._nedges = nedges self._tblock = tblock self.callback = callback self.args = args self._errf = lambda _ : None self.verbose = False self._times = array('i', (0 for _ in range(nedges + 1))) # +1 for overrun pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING)) self.edge = 0 self.tim = Timer(-1) # Sofware timer self.cb = self.decode # Pin interrupt. Save time of each edge for later decode. def _cb_pin(self, line): t = ticks_us() # On overrun ignore pulses until software timer times out if self.edge <= self._nedges: # Allow 1 extra pulse to record overrun if not self.edge: # First edge received self.tim.init(period=self._tblock , mode=Timer.ONE_SHOT, callback=self.cb) self._times[self.edge] = t self.edge += 1 def do_callback(self, cmd, addr, ext, thresh=0): self.edge = 0 if cmd >= thresh: self.callback(cmd, addr, ext, *self.args) else: self._errf(cmd) def error_function(self, func): self._errf = func def close(self): self._pin.irq(handler = None) self.tim.deinit()