X-Git-Url: https://vault307.fbx.one/gitweb/micorpython_ir.git/blobdiff_plain/5bdfdd8333ec035dd71a5b4a031096087e07c682..3bc46448ddca0bfdf3a98d96c3e9315159bf642b:/ir_rx.py?ds=inline diff --git a/ir_rx.py b/ir_rx.py index 6c484bc..210d617 100644 --- a/ir_rx.py +++ b/ir_rx.py @@ -40,20 +40,24 @@ BADADDR = -7 # a block start and a repeat code start (~108ms depending on protocol) class IR_RX(): - verbose = False + _erstr = "'{}' object has no attribute '{}'" + def __init__(self, pin, nedges, tblock, callback, *args): # Optional args for callback 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 if platform == 'pyboard': - ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin) + ei = ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin) elif ESP32: - pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING)) + ei = pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING)) else: - pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING), hard = True) + ei = pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING), hard = True) + self._eint = ei # Keep reference?? self.edge = 0 self.tim = Timer(-1) # Sofware timer self.cb = self.decode @@ -69,12 +73,29 @@ class IR_RX(): self._times[self.edge] = t self.edge += 1 + @property + def extended(self): + raise AttributeError(self._erstr.format(self.__qualname__, 'extended')) + + @property + def bits(self): + raise AttributeError(self._erstr.format(self.__qualname__, 'bits')) + + 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 + class NEC_IR(IR_RX): - def __init__(self, pin, callback, extended=True, *args): - # Block lasts <= 80ms and has 68 edges - tblock = 80 if extended else 73 # Allow for some tx tolerance (?) - super().__init__(pin, 68, tblock, callback, *args) - self._extended = extended + def __init__(self, pin, callback, *args): + # Block lasts <= 80ms (extended mode) and has 68 edges + super().__init__(pin, 68, 80, callback, *args) + self._extended = True self._addr = 0 def decode(self, _): @@ -112,8 +133,76 @@ class NEC_IR(IR_RX): except RuntimeError as e: cmd = e.args[0] addr = self._addr if cmd == REPEAT else 0 # REPEAT uses last address - self.edge = 0 # Set up for new data burst and run user callback - self.callback(cmd, addr, 0, *self.args) + # Set up for new data burst and run user callback + self.do_callback(cmd, addr, 0, REPEAT) + + @property + def extended(self): + return self._extended + + @extended.setter + def extended(self, value): + self._extended = bool(value) + +class SONY_IR(IR_RX): + def __init__(self, pin, callback, *args): + # 20 bit block has 42 edges and lasts <= 39ms nominal. Add 4ms to time + # for tolerances except in 20 bit case where timing is tight with a + # repeat period of 45ms. + t = int(3 + bits * 1.8) + (1 if bits == 20 else 4) + super().__init__(pin, 2 + bits * 2, t, callback, *args) + self._addr = 0 + self._bits = 20 + + def decode(self, _): + try: + nedges = self.edge # No. of edges detected + self.verbose and print('nedges', nedges) + if nedges > 42: + raise RuntimeError(OVERRUN) + bits = (nedges - 2) // 2 + if nedges not in (26, 32, 42) or bits > self._bits: + raise RuntimeError(BADBLOCK) + self.verbose and print('SIRC {}bit'.format(bits)) + width = ticks_diff(self._times[1], self._times[0]) + if not 1800 < width < 3000: # 2.4ms leading mark for all valid data + raise RuntimeError(BADSTART) + width = ticks_diff(self._times[2], self._times[1]) + if not 350 < width < 1000: # 600μs space + raise RuntimeError(BADSTART) + + val = 0 # Data received, LSB 1st + x = 2 + bit = 1 + while x < nedges - 2: + if ticks_diff(self._times[x + 1], self._times[x]) > 900: + val |= bit + bit <<= 1 + x += 2 + + cmd = val & 0x7f # 7 bit command + val >>= 7 + if nedges < 42: + addr = val & 0xff # 5 or 8 bit addr + val = 0 + else: + addr = val & 0x1f # 5 bit addr + val >>= 5 # 8 bit extended + except RuntimeError as e: + cmd = e.args[0] + addr = 0 + val = 0 + self.do_callback(cmd, addr, val) + + @property + def bits(self): + return self._bits + + @bits.setter + def bits(self, value): + if value not in (12, 15, 20): + raise ValueError('bits must be 12, 15 or 20') + self._bits = value class RC5_IR(IR_RX): def __init__(self, pin, callback, *args): @@ -160,8 +249,8 @@ class RC5_IR(IR_RX): except RuntimeError as e: val, addr, ctrl = e.args[0], 0, 0 - self.edge = 0 # Set up for new data burst and run user callback - self.callback(val, addr, ctrl, *self.args) + # 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 @@ -231,5 +320,5 @@ class RC6_M0(IR_RX): ctrl = (v >> 16) & 1 except RuntimeError as e: val, addr, ctrl = e.args[0], 0, 0 - self.edge = 0 # Set up for new data burst and run user callback - self.callback(val, addr, ctrl, *self.args) + # Set up for new data burst and run user callback + self.do_callback(val, addr, ctrl)