]> vault307.fbx.one Git - micorpython_ir.git/blobdiff - ir_rx.py
Update ir_rx_test and README re ESP8266 iss 5714.
[micorpython_ir.git] / ir_rx.py
index 6f20b2b0a61f941a1ab77b346150beba884b3c23..69d2da983fedb4bfcf617f55af0b6232e75e2de4 100644 (file)
--- a/ir_rx.py
+++ b/ir_rx.py
@@ -40,6 +40,7 @@ BADADDR = -7
 # a block start and a repeat code start (~108ms depending on protocol)
 
 class IR_RX():
+    verbose = False
     def __init__(self, pin, nedges, tblock, callback, *args):  # Optional args for callback
         self._nedges = nedges
         self._tblock = tblock
@@ -48,14 +49,15 @@ class IR_RX():
 
         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
+        self.cb = self.decode
 
 
     # Pin interrupt. Save time of each edge for later decode.
@@ -69,60 +71,109 @@ class IR_RX():
             self.edge += 1
 
 class NEC_IR(IR_RX):
-    def __init__(self, pin, callback, extended, *args):
+    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
         self._addr = 0
 
-    def _decode(self, _):
-        overrun = self.edge > 68
-        val = OVERRUN if overrun else BADSTART
-        if not overrun:
+    def decode(self, _):
+        try:
+            if self.edge > 68:
+                raise RuntimeError(OVERRUN)
             width = ticks_diff(self._times[1], self._times[0])
-            if width > 4000:  # 9ms leading mark for all valid data
-                width = ticks_diff(self._times[2], self._times[1])
-                if width > 3000: # 4.5ms space for normal data
-                    if self.edge < 68:
-                        # Haven't received the correct number of edges
-                        val = BADBLOCK
-                    else:
-                        # Time spaces only (marks are always 562.5µs)
-                        # Space is 1.6875ms (1) or 562.5µs (0)
-                        # Skip last bit which is always 1
-                        val = 0
-                        for edge in range(3, 68 - 2, 2):
-                            val >>= 1
-                            if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120:
-                                val |= 0x80000000
-                elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges.
-                    val = REPEAT if self.edge == 4 else BADREP
-        addr = 0
-        if val >= 0:  # validate. Byte layout of val ~cmd cmd ~addr addr
-            addr = val & 0xff
-            cmd = (val >> 16) & 0xff
-            if addr == ((val >> 8) ^ 0xff) & 0xff:  # 8 bit address OK
-                val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA
-                self._addr = addr
+            if width < 4000:  # 9ms leading mark for all valid data
+                raise RuntimeError(BADSTART)
+            width = ticks_diff(self._times[2], self._times[1])
+            if width > 3000:  # 4.5ms space for normal data
+                if self.edge < 68:  # Haven't received the correct number of edges
+                    raise RuntimeError(BADBLOCK)
+                # Time spaces only (marks are always 562.5µs)
+                # Space is 1.6875ms (1) or 562.5µs (0)
+                # Skip last bit which is always 1
+                val = 0
+                for edge in range(3, 68 - 2, 2):
+                    val >>= 1
+                    if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120:
+                        val |= 0x80000000
+            elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges.
+                raise RuntimeError(REPEAT if self.edge == 4 else BADREP)  # Treat REPEAT as error.
             else:
+                raise RuntimeError(BADSTART)
+            addr = val & 0xff  # 8 bit addr
+            cmd = (val >> 16) & 0xff
+            if cmd != (val >> 24) ^ 0xff:
+                raise RuntimeError(BADDATA)
+            if addr != ((val >> 8) ^ 0xff) & 0xff:  # 8 bit addr doesn't match check
+                if not self._extended:
+                    raise RuntimeError(BADADDR)
                 addr |= val & 0xff00  # pass assumed 16 bit address to callback
-                if self._extended:
-                    val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA
-                    self._addr = addr
-                else:
-                    val = BADADDR
-        if val == REPEAT:
-            addr = self._addr  # Last valid addresss
+            self._addr = addr
+        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)
+
+
+class SONY_IR(IR_RX):
+    def __init__(self, pin, callback, bits=20, *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 = bits
+
+    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.edge = 0  # Set up for new data burst and run user callback
-        self.callback(val, addr, *self.args)
+        self.callback(cmd, addr, val, *self.args)
 
 class RC5_IR(IR_RX):
     def __init__(self, pin, callback, *args):
         # Block lasts <= 30ms and has <= 28 edges
         super().__init__(pin, 28, 30, callback, *args)
 
-    def _decode(self, _):
+    def decode(self, _):
         try:
             nedges = self.edge  # No. of edges detected
             if not 14 <= nedges <= 28:
@@ -138,7 +189,7 @@ class RC5_IR(IR_RX):
                     bits <<= 1
                     bits |= bit
                 bit ^= 1
-            #print(bin(bits))  # Matches inverted scope waveform
+            self.verbose and print(bin(bits))  # Matches inverted scope waveform
             # Decode Manchester code
             x = 30
             while not bits >> x:
@@ -166,13 +217,15 @@ class RC5_IR(IR_RX):
         self.callback(val, addr, ctrl, *self.args)
 
 class RC6_M0(IR_RX):
-    # Even on Pyboard D these 444us nominal pulses can be recorded as up to 705us
+    # 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)
+    # Header nominal 2666, 889, 444, 889, 444, 444, 444, 444 carrier ON at end
     hdr = ((1800, 4000), (593, 1333), (222, 750), (593, 1333), (222, 750), (222, 750), (222, 750), (222, 750))
     def __init__(self, pin, callback, *args):
         # Block lasts 23ms nominal and has <=44 edges
         super().__init__(pin, 44, 30, callback, *args)
 
-    def _decode(self, _):
+    def decode(self, _):
         try:
             nedges = self.edge  # No. of edges detected
             if not 22 <= nedges <= 44:
@@ -180,48 +233,55 @@ class RC6_M0(IR_RX):
             for x, lims in enumerate(self.hdr):
                 width = ticks_diff(self._times[x + 1], self._times[x])
                 if not (lims[0] < width < lims[1]):
-                    print('Bad start', x, width, lims)
+                    self.verbose and print('Bad start', x, width, lims)
                     raise RuntimeError(BADSTART)
             x += 1
             width = ticks_diff(self._times[x + 1], self._times[x])
-            ctrl = width > 889  # Long bit
-            start = x + 2  # Skip 2nd long bit
-
-            # Regenerate bitstream
-            bits = 0
-            bit = 0
-            for x in range(start, nedges):
-                width = ticks_diff(self._times[x], self._times[x - 1])
-                if not 222 < width < 1333:
-                    print('Width', width)
-                    raise RuntimeError(BADBLOCK)
-                for _ in range(1 if width < 666 else 2):
-                    bits <<= 1
-                    bits |= bit
+            # 2nd bit of last 0 is 444μs (0) or 1333μs (1)
+            if not 222 < width < 1555:
+                self.verbose and print('Bad block 1 Width', width, 'x', x)
+                raise RuntimeError(BADBLOCK)
+            short = width < 889
+            v = int(not short)
+            bit = v
+            bits = 1  # Bits decoded
+            x += 1 + int(short)
+            width = ticks_diff(self._times[x + 1], self._times[x])
+            if not 222 < width < 1555:
+                self.verbose and print('Bad block 2 Width', width, 'x', x)
+                raise RuntimeError(BADBLOCK)
+            short = width < 1111
+            if not short:
                 bit ^= 1
-            print(bin(bits), len(bin(bits)) - 2)
-
-            # Decode Manchester code
-            x = 32
-            while not bits >> x:
-                x -= 1
-            m0 = 1 << (x - 1)
-            m1 = 1 << x  # MSB of pair
-            v = 0  # 16 bit bitstream
-            for _ in range(16):
-                v <<= 1
-                b0 = (bits & m0) > 0
-                b1 = (bits & m1) > 0
-                #print(int(b1), int(b0))
-                if b0 == b1:
+            x += 1 + int(short)  # If it's short, we know width of next
+            v <<= 1
+            v |= bit  # MSB of result
+            bits += 1
+            # Decode bitstream
+            while bits < 17:
+                # -1 convert count to index, -1 because we look ahead
+                if x > nedges - 2:
                     raise RuntimeError(BADBLOCK)
-                v |= b0
-                m0 >>= 2
-                m1 >>= 2
-            # Split into fields (val, addr)
+                # width is 444/889 nominal
+                width = ticks_diff(self._times[x + 1], self._times[x])
+                if not 222 < width < 1111:
+                    self.verbose and print('Bad block 3 Width', width, 'x', x)
+                    raise RuntimeError(BADBLOCK)
+                short = width < 666
+                if not short:
+                    bit ^= 1
+                v <<= 1
+                v |= bit
+                bits += 1
+                x += 1 + int(short)
+
+            if self.verbose:
+                 ss = '20-bit format {:020b} x={} nedges={} bits={}'
+                 print(ss.format(v, x, nedges, bits))
+
             val = v & 0xff
             addr = (v >> 8) & 0xff
-
+            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