]> vault307.fbx.one Git - micorpython_ir.git/commitdiff
Support transmit and receive on Samsung remotes.
authorPeter Hinch <peter@hinch.me.uk>
Mon, 6 Jun 2022 17:04:55 +0000 (18:04 +0100)
committerPeter Hinch <peter@hinch.me.uk>
Mon, 6 Jun 2022 17:04:55 +0000 (18:04 +0100)
README.md
RECEIVER.md
TRANSMITTER.md
ir_rx/acquire.py
ir_rx/nec.py
ir_rx/samsung.py [deleted file]
ir_rx/test.py
ir_tx/nec.py

index 48259c5f25034e06ae3c675d27b87bae22be717c..f33feb50a585c309ab92d050ec27bb8f4889de6a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -52,6 +52,7 @@ The drivers support NEC and Sony protocols plus two Philips protocols, namely
 RC-5 and RC-6 mode 0. There is also support for the OrtekMCE protocol used on
 VRC-1100 remotes. These originally supported Microsoft Media Center but can be
 used to control Kodi and (with a suitable receiver) to emulate a PC keyboard.
 RC-5 and RC-6 mode 0. There is also support for the OrtekMCE protocol used on
 VRC-1100 remotes. These originally supported Microsoft Media Center but can be
 used to control Kodi and (with a suitable receiver) to emulate a PC keyboard.
+The Samsung protocol (NEC variant) is also supported.
 
 Examining waveforms from various remote controls it is evident that numerous
 protocols exist. Some are doubtless proprietary and undocumented. The supported
 
 Examining waveforms from various remote controls it is evident that numerous
 protocols exist. Some are doubtless proprietary and undocumented. The supported
@@ -77,14 +78,14 @@ microcontroller.
 In my testing a 38KHz demodulator worked with 36KHz and 40KHz remotes, but this
 is obviously neither guaranteed nor optimal.
 
 In my testing a 38KHz demodulator worked with 36KHz and 40KHz remotes, but this
 is obviously neither guaranteed nor optimal.
 
-The transmitter requires a Pyboard 1.x (not Lite), a Pyboard D or an ESP32.
-Output is via an IR LED which will need a transistor to provide sufficient
-current. The ESP32 requires an extra transistor to work as a transmitter.
+The transmitter requires a Pyboard 1.x (not Lite), a Pyboard D, an ESP32 or
+Raspberry Pico (RP2). Output is via an IR LED which will need a transistor to
+provide sufficient current.
 
 ## 3.1 Carrier frequencies
 
 
 ## 3.1 Carrier frequencies
 
-These are as follows. The Samsung and Panasonic remotes appear to use
-proprietary protocols and are not supported by these drivers.
+These are as follows. The Panasonic remote appears to use a proprietary
+protocol and is not supported by these drivers.
 
 | Protocol  | F KHz | How found     | Support |
 |:---------:|:-----:|:-------------:|:-------:|
 
 | Protocol  | F KHz | How found     | Support |
 |:---------:|:-----:|:-------------:|:-------:|
@@ -92,7 +93,7 @@ proprietary protocols and are not supported by these drivers.
 | RC-5 RC-6 | 36    | Spec/measured | Y       |
 | Sony      | 40    | Spec/measured | Y       |
 | MCE       | 38    | Measured      | Y       | 
 | RC-5 RC-6 | 36    | Spec/measured | Y       |
 | Sony      | 40    | Spec/measured | Y       |
 | MCE       | 38    | Measured      | Y       | 
-| Samsung   | 38    | Measured      | N       |
+| Samsung   | 38    | Measured      | Y       |
 | Panasonic | 36.3  | Measured      | N       |
 
 # 4. Receiver limitations
 | Panasonic | 36.3  | Measured      | N       |
 
 # 4. Receiver limitations
@@ -111,9 +112,14 @@ excellent resource.
 
 The NEC protocol:  
 [altium](http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol)  
 
 The NEC protocol:  
 [altium](http://techdocs.altium.com/display/FPGA/NEC+Infrared+Transmission+Protocol)  
-[circuitvalley](http://www.circuitvalley.com/2013/09/nec-protocol-ir-infrared-remote-control.html)
+[circuitvalley](http://www.circuitvalley.com/2013/09/nec-protocol-ir-infrared-remote-control.html)  
 [sbprojects.net](https://www.sbprojects.net/knowledge/ir/nec.php)
 
 [sbprojects.net](https://www.sbprojects.net/knowledge/ir/nec.php)
 
+The Samsung protocol:  
+[Rustic Engineering](https://rusticengineering.wordpress.com/2011/02/09/infrared-room-control-with-samsung-ir-protocol/)  
+[TechDesign Electronics](https://www.techdesign.be/projects/011/011_waves.htm) Waveforms of various protocols.  
+
+
 Philips protocols:  
 [RC5 Wikipedia](https://en.wikipedia.org/wiki/RC-5)  
 [RC5 sbprojects.net](https://www.sbprojects.net/knowledge/ir/rc5.php)  
 Philips protocols:  
 [RC5 Wikipedia](https://en.wikipedia.org/wiki/RC-5)  
 [RC5 sbprojects.net](https://www.sbprojects.net/knowledge/ir/rc5.php)  
index fe1493efbcd4d02e3418e0aa1a21a8c9dd498440..13ce77a24339cb1557c1e9aa5c011fe953fe7bd4 100644 (file)
@@ -141,9 +141,9 @@ Class variables:
  1. These are constants defining the NEC repeat code and the error codes sent
  to the error function. They are discussed in [section 4](./RECEIVER.md#4-errors).
 
  1. These are constants defining the NEC repeat code and the error codes sent
  to the error function. They are discussed in [section 4](./RECEIVER.md#4-errors).
 
-#### NEC classes
+#### NEC classes (includes Samsung)
 
 
-`NEC_8`, `NEC_16`
+`NEC_8`, `NEC_16`, `SAMSUNG`
 
 Typical invocation:
 ```python
 
 Typical invocation:
 ```python
@@ -157,6 +157,13 @@ The `NEC_8` class enables error checking for remotes that return an 8 bit
 address: the complement is checked and the address returned as an 8-bit value.
 A 16-bit address will result in an error.
 
 address: the complement is checked and the address returned as an 8-bit value.
 A 16-bit address will result in an error.
 
+The `SAMSUNG` class returns 16 bit address and data values. The remote sample
+tested did not issue repeat codes - if a button is held down it simply repeated
+the original value. In common with other NEC classes the callback receives a
+value of 0 in the `ctrl` arg.
+
+Thanks are due to J.E.Tannenbaum for information about the Samsung protocol.
+
 #### Sony classes
 
 `SONY_12`, `SONY_15`, `SONY_20`
 #### Sony classes
 
 `SONY_12`, `SONY_15`, `SONY_20`
index a328d68f4fcaf7c5354415aee405a84b38f1600c..c76995bb5390014de2e4b4dcbd55519aa818ab0c 100644 (file)
@@ -22,7 +22,10 @@ device similar to the ESP32 RMT. The device driver is
 [documented here](./RP2_RMT.md); this is for experimenters and those wanting to
 use the library in conjunction with their own PIO assembler code.
 
 [documented here](./RP2_RMT.md); this is for experimenters and those wanting to
 use the library in conjunction with their own PIO assembler code.
 
-## 1.1 Pyboard Wiring
+## 1.1 Wiring
+
+All microcontrollers require an external circuit to drive the LED. The notes
+below on specific microcontrollers assume that such a circuit is used.
 
 I use the following circuit which delivers just under 40mA to the diode. R2 may
 be reduced for higher current.  
 
 I use the following circuit which delivers just under 40mA to the diode. R2 may
 be reduced for higher current.  
@@ -169,7 +172,7 @@ skipping validation.
 | RC6_M0   | 6.0ms | 2.0ms   |
 | MCE      | 6.7ms | 2.0ms   |
 
 | RC6_M0   | 6.0ms | 2.0ms   |
 | MCE      | 6.7ms | 2.0ms   |
 
-#### NEC class
+#### NEC class (also Samsung)
 
 Class `NEC`. Example invocation:
 ```python
 
 Class `NEC`. Example invocation:
 ```python
@@ -187,6 +190,16 @@ the complement for values < 256.
 
 A value passed in `toggle` is ignored.
 
 
 A value passed in `toggle` is ignored.
 
+For Samsung protocol set the `samsung` class variable `True`:
+```python
+from ir_tx.nec import NEC
+NEC.samsung=True
+```
+Samsung remotes do not seem to use repeat codes: the sample I have simply
+repeats the original code.
+
+Thanks are due to J.E.Tannenbaum for information about the Samsung protocol.
+
 #### Sony classes
 
 Classes `SONY_12`, `SONY_15` and `SONY_20`. Example invocation:
 #### Sony classes
 
 Classes `SONY_12`, `SONY_15` and `SONY_20`. Example invocation:
index ea0b2e4eafd35499fa3c7ca2d86dcec57739762c..af3ab38ba17ad61a46c58ff4700ef3a0c6f9fa5b 100644 (file)
@@ -70,8 +70,8 @@ class IR_GET(IR_RX):
                     print('Protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration))
                     ok = True
 
                     print('Protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration))
                     ok = True
 
-            if not ok and near(burst[0], 4500) and near(burst[1], 4500):  # Samsung?
-                print('Unsupported protocol. Samsung?')
+            if not ok and near(burst[0], 4500) and near(burst[1], 4500) and lb == 67:  # Samsung
+                print('Samsung')
                 ok = True
 
             if not ok and near(burst[0], 3500) and near(burst[1], 1680):  # Panasonic?
                 ok = True
 
             if not ok and near(burst[0], 3500) and near(burst[1], 1680):  # Panasonic?
index e516924412c8a9bf009e427f3062b80ff97f56b6..011b13dda9af7cd816bb97e60de97525534c5ebe 100644 (file)
@@ -1,26 +1,29 @@
 # nec.py Decoder for IR remote control using synchronous code
 # nec.py Decoder for IR remote control using synchronous code
-# Supports NEC protocol.
+# Supports NEC and Samsung protocols.
+# With thanks to J.E. Tannenbaum for information re Samsung protocol
+
 # For a remote using NEC see https://www.adafruit.com/products/389
 
 # Author: Peter Hinch
 # For a remote using NEC see https://www.adafruit.com/products/389
 
 # Author: Peter Hinch
-# Copyright Peter Hinch 2020 Released under the MIT license
+# Copyright Peter Hinch 2020-2022 Released under the MIT license
 
 from utime import ticks_us, ticks_diff
 from ir_rx import IR_RX
 
 class NEC_ABC(IR_RX):
 
 from utime import ticks_us, ticks_diff
 from ir_rx import IR_RX
 
 class NEC_ABC(IR_RX):
-    def __init__(self, pin, extended, callback, *args):
+    def __init__(self, pin, extended, samsung, callback, *args):
         # Block lasts <= 80ms (extended mode) and has 68 edges
         super().__init__(pin, 68, 80, callback, *args)
         self._extended = extended
         self._addr = 0
         # Block lasts <= 80ms (extended mode) and has 68 edges
         super().__init__(pin, 68, 80, callback, *args)
         self._extended = extended
         self._addr = 0
+        self._leader = 2500 if samsung else 4000  # 4.5ms for Samsung else 9ms
 
     def decode(self, _):
         try:
             if self.edge > 68:
                 raise RuntimeError(self.OVERRUN)
             width = ticks_diff(self._times[1], self._times[0])
 
     def decode(self, _):
         try:
             if self.edge > 68:
                 raise RuntimeError(self.OVERRUN)
             width = ticks_diff(self._times[1], self._times[0])
-            if width < 4000:  # 9ms leading mark for all valid data
+            if width < self._leader:  # 9ms leading mark for all valid data
                 raise RuntimeError(self.BADSTART)
             width = ticks_diff(self._times[2], self._times[1])
             if width > 3000:  # 4.5ms space for normal data
                 raise RuntimeError(self.BADSTART)
             width = ticks_diff(self._times[2], self._times[1])
             if width > 3000:  # 4.5ms space for normal data
@@ -55,8 +58,12 @@ class NEC_ABC(IR_RX):
 
 class NEC_8(NEC_ABC):
     def __init__(self, pin, callback, *args):
 
 class NEC_8(NEC_ABC):
     def __init__(self, pin, callback, *args):
-        super().__init__(pin, False, callback, *args)
+        super().__init__(pin, False, False, callback, *args)
 
 class NEC_16(NEC_ABC):
     def __init__(self, pin, callback, *args):
 
 class NEC_16(NEC_ABC):
     def __init__(self, pin, callback, *args):
-        super().__init__(pin, True, callback, *args)
+        super().__init__(pin, True, False, callback, *args)
+
+class SAMSUNG(NEC_ABC):
+    def __init__(self, pin, callback, *args):
+        super().__init__(pin, True, True, callback, *args)
diff --git a/ir_rx/samsung.py b/ir_rx/samsung.py
deleted file mode 100644 (file)
index 382dcbf..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# samsung.py Decoder for IR remote control using synchronous code\r
-# Supports Samsung TV remote protocols.\r
-\r
-# Author: J.E. Tannenbaum\r
-# Copyright J.E.Tannenbaum 2021 Released under the MIT license\r
-\r
-from utime import ticks_us, ticks_diff\r
-from ir_rx import IR_RX\r
-\r
-class SAMSUNG(IR_RX):\r
-    def __init__(self, pin, callback, *args):\r
-        super().__init__(pin, 68, 80, callback, *args)\r
-\r
-    def decode(self, _):\r
-        def near(v, target):\r
-            return target * 0.8 < v < target * 1.2\r
-\r
-        lb = self.edge - 1  # Possible length of burst\r
-        burst = []\r
-        for x in range(lb):\r
-            dt = ticks_diff(self._times[x + 1], self._times[x])\r
-            if x > 0 and dt > 10000:  # Reached gap between repeats\r
-                break\r
-            burst.append(dt)\r
-\r
-        lb = len(burst)  # Actual length\r
-        cmd = 0\r
-        if near(burst[0], 4500) and near(burst[1], 4500) and lb == 67:\r
-            # Skip the starting bits and the checksum at the end of the sequence\r
-            for x in range(2, lb - 1, 2):\r
-                cmd *= 2\r
-                # Test for logical 1 (One byte low, next byte high)\r
-                if burst[x] < 1000 and burst[x + 1] > 1000:\r
-                    cmd += 1\r
-\r
-        # Set up for new data burst and run user callback\r
-        self.do_callback(cmd, 0, 0)\r
index 48f342e2f4633a1ef70a6cde8fe815fb4dcca4c2..c4dbd7f4e39008818140658214b63d36eb647579 100644 (file)
@@ -2,7 +2,7 @@
 # Supports Pyboard, ESP32 and ESP8266
 
 # Author: Peter Hinch
 # Supports Pyboard, ESP32 and ESP8266
 
 # Author: Peter Hinch
-# Copyright Peter Hinch 2020 Released under the MIT license
+# Copyright Peter Hinch 2020-2022 Released under the MIT license
 
 # Run this to characterise a remote.
 
 
 # Run this to characterise a remote.
 
@@ -11,46 +11,49 @@ import time
 import gc
 from machine import Pin, freq
 from ir_rx.print_error import print_error  # Optional print of error codes
 import gc
 from machine import Pin, freq
 from ir_rx.print_error import print_error  # Optional print of error codes
+
 # Import all implemented classes
 # Import all implemented classes
-from ir_rx.nec import NEC_8, NEC_16
+from ir_rx.nec import NEC_8, NEC_16, SAMSUNG
 from ir_rx.sony import SONY_12, SONY_15, SONY_20
 from ir_rx.philips import RC5_IR, RC6_M0
 from ir_rx.mce import MCE
 
 # Define pin according to platform
 from ir_rx.sony import SONY_12, SONY_15, SONY_20
 from ir_rx.philips import RC5_IR, RC6_M0
 from ir_rx.mce import MCE
 
 # Define pin according to platform
-if platform == 'pyboard':
-    p = Pin('X3', Pin.IN)
-elif platform == 'esp8266':
+if platform == "pyboard":
+    p = Pin("X3", Pin.IN)
+elif platform == "esp8266":
     freq(160000000)
     p = Pin(13, Pin.IN)
     freq(160000000)
     p = Pin(13, Pin.IN)
-elif platform == 'esp32' or platform == 'esp32_LoBo':
+elif platform == "esp32" or platform == "esp32_LoBo":
     p = Pin(23, Pin.IN)
     p = Pin(23, Pin.IN)
-elif platform == 'rp2':
+elif platform == "rp2":
     p = Pin(16, Pin.IN)
 
 # User callback
 def cb(data, addr, ctrl):
     if data < 0:  # NEC protocol sends repeat codes.
     p = Pin(16, Pin.IN)
 
 # User callback
 def cb(data, addr, ctrl):
     if data < 0:  # NEC protocol sends repeat codes.
-        print('Repeat code.')
+        print("Repeat code.")
     else:
     else:
-        print('Data {:02x} Addr {:04x} Ctrl {:02x}'.format(data, addr, ctrl))
+        print(f"Data 0x{data:02x} Addr 0x{addr:04x} Ctrl 0x{ctrl:02x}")
+
 
 def test(proto=0):
 
 def test(proto=0):
-    classes = (NEC_8, NEC_16, SONY_12, SONY_15, SONY_20, RC5_IR, RC6_M0, MCE)
+    classes = (NEC_8, NEC_16, SONY_12, SONY_15, SONY_20, RC5_IR, RC6_M0, MCE, SAMSUNG)
     ir = classes[proto](p, cb)  # Instantiate receiver
     ir.error_function(print_error)  # Show debug information
     ir = classes[proto](p, cb)  # Instantiate receiver
     ir.error_function(print_error)  # Show debug information
-    #ir.verbose = True
+    # ir.verbose = True
     # A real application would do something here...
     try:
         while True:
     # A real application would do something here...
     try:
         while True:
-            print('running')
+            print("running")
             time.sleep(5)
             gc.collect()
     except KeyboardInterrupt:
         ir.close()
 
             time.sleep(5)
             gc.collect()
     except KeyboardInterrupt:
         ir.close()
 
+
 # **** DISPLAY GREETING ****
 # **** DISPLAY GREETING ****
-s = '''Test for IR receiver. Run:
+s = """Test for IR receiver. Run:
 from ir_rx.test import test
 test() for NEC 8 bit protocol,
 test(1) for NEC 16 bit,
 from ir_rx.test import test
 test() for NEC 8 bit protocol,
 test(1) for NEC 16 bit,
@@ -60,7 +63,8 @@ test(4) for Sony SIRC 20 bit,
 test(5) for Philips RC-5 protocol,
 test(6) for RC6 mode 0.
 test(7) for Microsoft Vista MCE.
 test(5) for Philips RC-5 protocol,
 test(6) for RC6 mode 0.
 test(7) for Microsoft Vista MCE.
+test(8) for Samsung.
 
 
-Hit ctrl-c to stop, then ctrl-d to soft reset.'''
+Hit ctrl-c to stop, then ctrl-d to soft reset."""
 
 print(s)
 
 print(s)
index da1af24a8ae75a0f32735a04aedf56c7c5e61b4c..807ec68abb220eeead32a1d98cf0b638000308b7 100644 (file)
@@ -2,8 +2,9 @@
 # NEC protocol.
 
 # Author: Peter Hinch
 # NEC protocol.
 
 # Author: Peter Hinch
-# Copyright Peter Hinch 2020 Released under the MIT license
+# Copyright Peter Hinch 2020-2022 Released under the MIT license
 
 
+# With thanks to J.E. Tannenbaum for information re Samsung protocol
 from micropython import const
 from ir_tx import IR, STOP
 
 from micropython import const
 from ir_tx import IR, STOP
 
@@ -12,15 +13,19 @@ _T_ONE = const(1687)
 
 class NEC(IR):
     valid = (0xffff, 0xff, 0)  # Max addr, data, toggle
 
 class NEC(IR):
     valid = (0xffff, 0xff, 0)  # Max addr, data, toggle
+    samsung = False
 
 
-    def __init__(self, pin, freq=38000, verbose=False):  # NEC specifies 38KHz
+    def __init__(self, pin, freq=38000, verbose=False):  # NEC specifies 38KHz also Samsung
         super().__init__(pin, freq, 68, 33, verbose)  # Measured duty ratio 33%
 
     def _bit(self, b):
         self.append(_TBURST, _T_ONE if b else _TBURST)
 
     def tx(self, addr, data, _):  # Ignore toggle
         super().__init__(pin, freq, 68, 33, verbose)  # Measured duty ratio 33%
 
     def _bit(self, b):
         self.append(_TBURST, _T_ONE if b else _TBURST)
 
     def tx(self, addr, data, _):  # Ignore toggle
-        self.append(9000, 4500)
+        if self.samsung:
+            self.append(4500, 4500)
+        else:
+            self.append(9000, 4500)
         if addr < 256:  # Short address: append complement
             addr |= ((addr ^ 0xff) << 8)
         for _ in range(16):
         if addr < 256:  # Short address: append complement
             addr |= ((addr ^ 0xff) << 8)
         for _ in range(16):