]> vault307.fbx.one Git - micorpython_ir.git/commitdiff
Doc improvements. Add acquire script.
authorPeter Hinch <peter@hinch.me.uk>
Sun, 15 Mar 2020 18:43:35 +0000 (18:43 +0000)
committerPeter Hinch <peter@hinch.me.uk>
Sun, 15 Mar 2020 18:43:35 +0000 (18:43 +0000)
README.md
RECEIVER.md
TRANSMITTER.md
images/circuits.fzz
images/gate_mosfet.png [new file with mode: 0644]
ir_rx/__init__.py
ir_rx/acquire.py [new file with mode: 0644]

index 371615fbfb08d8fcc035c38773fd8ea9af470e32..44318d546476d17cccac2cbe812d0139d497aead 100644 (file)
--- a/README.md
+++ b/README.md
@@ -6,12 +6,14 @@ require `uasyncio` but are compatible with it, and are designed for standard
 firmware builds.
 
 The receiver is cross platform and has been tested on Pyboard, ESP8266 and
-ESP32. The transmitter driver is compatible with Pyboard (1.x and D series) and
-also (subject to limitations) with ESP32. For the transmitter a Pyboard is
-recommended.
+ESP32.
 
-The transmitter is documented [here](./TRANSMITTER.md) and the receiver is
-[here](./RECEIVER.md).
+#### [Receiver docs](./RECEIVER.md)
+
+The transmitter driver is compatible with Pyboard (1.x and D series) and ESP32.
+ESP8266 is unsupported; it seems incapable of generating the required signals.
+
+#### [Transmitter docs](./TRANSMITTER.md)
 
 # 1. IR communication
 
index edd27dc6a607495be5b83e841604853a30cc04a6..12d9577ad02cb1a59ff4e5fb356e4adfba2f6a76 100644 (file)
@@ -21,26 +21,43 @@ On the WeMos D1 Mini the equivalent pin is D7.
 
 A remote using the NEC protocol is [this one](https://www.adafruit.com/products/389).
 
-# 2. Installation and demo script
+# 2. Installation and demo scripts
 
 The receiver is a Python package. This minimises RAM usage: applications only
-import the device driver for the protocol in use.
-
+import the device driver for the protocol in use. Clone the repository to the
+current directory of your PC with:
+```bash
+$ git clone https://github.com/peterhinch/micropython_ir
+```
 
 Copy the following to the target filesystem:
  1. `ir_rx` Directory and contents.
 
 There are no dependencies.
 
-The demo can be used to characterise IR remotes. It displays the codes returned
-by each button. This can aid in the design of receiver applications. The demo
-prints "running" every 5 seconds and reports any data received from the remote.
+## 2.1 Test scripts
 
+The demo can be used to characterise IR remotes where the protocol is known. It
+displays the codes returned by each button. This can aid in the design of
+receiver applications. The demo prints "running" every 5 seconds and reports
+any data received from the remote.
 ```python
 from ir_rx.test import test
 ```
 Instructions will be displayed at the REPL.
 
+If the protocol in use is unknown, there are two options: trial and error with
+the above script or run the following:
+```python
+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.
+
 # 3. The driver
 
 This implements a class for each supported protocol. Each class is subclassed
@@ -92,13 +109,14 @@ The user callback takes the following args:
 Bound variable:  
  1. `verbose=False` If `True` emits debug output.
 
-Method:
- 1. `error_function` Arg: a function taking a single `int` arg. If this is
- specified it will be called if an error occurs. The value corresponds to the
- error code (see below). Typical usage might be to provide some user feedback
- of incorrect reception although beware of occasional triggers by external
- events. In my testing the TSOP4838 produces 200µs pulses on occasion for no
- obvious reason. See [section 4](./RECEIVER.md#4-errors).
+Methods:
+ 1. `error_function` Arg: a function taking a single `int` arg. If specified
+ the function will be called if an error occurs. The arg value corresponds to
+ the error code. Typical usage might be to provide some user feedback of
+ incorrect reception although beware of occasional triggers by external events.
+ In my testing the TSOP4838 produces 200µs pulses on occasion for no obvious
+ reason. See [section 4](./RECEIVER.md#4-errors).
+ 2. `close` No args. Shuts down the pin and timer interrupts.
 
 A function is provided to print errors in human readable form. This may be
 invoked as follows:
index 24cd24423b22c16bcd125372837dba657cbee883..c29a0ddbd840f0a9c924cbe500ee7db3e3365629 100644 (file)
@@ -37,10 +37,13 @@ which is the driver default. If using a circuit where "off" is required to be
 
 The ESP32 RMT device does not currently support the carrier option. A simple
 hardware gate is required to turn the IR LED on when both the carrier pin and
-the RMT pin are high. A suitable circuit is below.  
+the RMT pin are high. A suitable circuit is below; the transistor type is not
+critical.  
 ![Image](images/gate.png)
 
-The transistor type is not critical.
+This simpler alternative uses MOSFETS, but the device type needs attention. The
+chosen type has a low gate-source threshold voltage and low Rdson.  
+![Image](images/gate_mosfet.png)
 
 # 2. Dependencies and installation
 
@@ -57,7 +60,11 @@ from [this repo](https://github.com/peterhinch/micropython-async).
 ## 2.2 Installation
 
 The transmitter is a Python package. This minimises RAM usage: applications
-only import the device driver for the protocol in use.
+only import the device driver for the protocol in use. Clone the repository to
+the current directory of your PC with:
+```bash
+$ git clone https://github.com/peterhinch/micropython_ir
+```
 
 Copy the following to the target filesystem:
  1. `ir_tx` Directory and contents.
index ad48376633883df0873fd8ea95d6eae757485228..7ecee24c990016c6821d293cd215f0fc1567bb81 100644 (file)
Binary files a/images/circuits.fzz and b/images/circuits.fzz differ
diff --git a/images/gate_mosfet.png b/images/gate_mosfet.png
new file mode 100644 (file)
index 0000000..d2e137c
Binary files /dev/null and b/images/gate_mosfet.png differ
index 4b965245c326565c71ea7dfb816b48ac5222ebe1..0e7ad7f77026eb753c821ab5473a587e21860d2e 100644 (file)
@@ -32,6 +32,7 @@ class IR_RX():
     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
@@ -41,10 +42,9 @@ class IR_RX():
 
         self._times = array('i',  (0 for _ in range(nedges + 1)))  # +1 for overrun
         if platform == 'esp32' or platform == 'esp32_LoBo':  # ESP32 Doesn't support hard IRQ
-            ei = pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
+            pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
         else:
-            ei = pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING), hard = True)
-        self._eint = ei  # Keep reference??
+            pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING), hard = True)
         self.edge = 0
         self.tim = Timer(-1)  # Sofware timer
         self.cb = self.decode
@@ -68,3 +68,7 @@ class IR_RX():
 
     def error_function(self, func):
         self._errf = func
+
+    def close(self):
+        self._pin.irq(handler = None)
+        self.tim.deinit()
diff --git a/ir_rx/acquire.py b/ir_rx/acquire.py
new file mode 100644 (file)
index 0000000..7b492e0
--- /dev/null
@@ -0,0 +1,99 @@
+# acquire.py Acquire a pulse train from an IR remote
+# Supports NEC protocol.
+# For a remote using NEC see https://www.adafruit.com/products/389
+
+# Author: Peter Hinch
+# Copyright Peter Hinch 2020 Released under the MIT license
+
+from machine import Pin, freq
+from sys import platform
+
+from utime import sleep_ms, ticks_us, ticks_diff
+from ir_rx import IR_RX
+
+
+class IR_GET(IR_RX):
+    def __init__(self, pin, nedges=100, twait=100, display=True):
+        self.display = display
+        super().__init__(pin, nedges, twait, lambda *_ : None)
+        self.data = None
+
+    def decode(self, _):
+        def near(v, target):
+            return target * 0.8 < v < target * 1.2
+        nedges = self.edge
+        if nedges < 4:
+            return  # Noise
+        burst = []
+        duration = ticks_diff(self._times[0], self._times[nedges])  # 24892 for RC-5 22205 for RC-6
+        for x in range(nedges - 1):
+            dt = ticks_diff(self._times[x + 1], self._times[x])
+            if x > 0 and dt > 10000:  # Reached gap between repeats
+                break
+            burst.append(dt)
+
+        if self.display:
+            detected = False
+            for x, e in enumerate(burst):
+                print('{:03d} {:5d}'.format(x, e))
+            print()
+            if burst[0] > 5000:
+                print('NEC')
+                detected = True
+            elif burst[0] > 2000:  # Sony or Philips RC-6
+                if burst[1] > 750:  # Probably Philips
+                    if min(burst) < 600:
+                        print('Philips RC-6 mode 0')
+                        detected = True
+                else:
+                    lb = len(burst)
+                    try:
+                        nbits = {25:12, 31:15, 41:20}[len(burst)]
+                    except IndexError:
+                        pass
+                    else:
+                        detected = True
+                    if detected:
+                        print('Sony {}bit'.format(nbits))
+
+            elif burst[0] < 1200:
+                print('Philips RC-5')
+                detected = True
+            if not detected:
+                print('Unknown protocol')
+
+            print()
+        self.data = burst
+        # Set up for new data burst. Run null callback
+        self.do_callback(0, 0, 0)
+
+    def acquire(self):
+        while self.data is None:
+            sleep_ms(5)
+        self.close()
+        return self.data
+
+def test():
+    # Define pin according to platform
+    if platform == 'pyboard':
+        pin = Pin('X3', Pin.IN)
+    elif platform == 'esp8266':
+        freq(160000000)
+        pin = Pin(13, Pin.IN)
+    elif platform == 'esp32' or platform == 'esp32_LoBo':
+        pin = Pin(23, Pin.IN)
+    irg = IR_GET(pin)
+    print('Waiting for IR data...')
+    irg.acquire()
+
+#          RC          Python   Calculated
+# NEC      66          66       66
+# Sony 12: 24       24       26 (2 hdr + 2*(7 data + 5 addr)  RC issues another: detect 26ms gap
+# Sony 15: 75          30
+# Sony 20  n/a         40
+
+# Yamaha NEC 
+# Pi/Vista MCE RC6 mode 0 Din't receive
+# Panasonic TV recorder RC6 mode 0 Didn't receive
+# Virgin RC-5 Receive OK
+# Samsung TV RC6 mode 0  Didn't receive