]> vault307.fbx.one Git - micorpython_ir.git/blobdiff - ir_rx.py
Prior to package.
[micorpython_ir.git] / ir_rx.py
index 6c484bc26c100cf0d9958e331af1aecba74d59e3..210d61767a79ef24ed0eb762de770e1b44849acd 100644 (file)
--- 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():
 # 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
     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':
 
         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:
         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:
         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
         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
 
             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):
 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, _):
         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
         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):
 
 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
 
         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
 
 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
             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)