From: Peter Hinch Date: Mon, 6 Jun 2022 17:04:55 +0000 (+0100) Subject: Support transmit and receive on Samsung remotes. X-Git-Url: https://vault307.fbx.one/gitweb/micorpython_ir.git/commitdiff_plain/7156dff5bcd19a1debf7db1ffd4add94e010c66f Support transmit and receive on Samsung remotes. --- diff --git a/README.md b/README.md index 48259c5..f33feb5 100644 --- 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. +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 @@ -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. -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 -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 | |:---------:|:-----:|:-------------:|:-------:| @@ -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 | -| Samsung | 38 | Measured | N | +| Samsung | 38 | Measured | Y | | 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) -[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) +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) diff --git a/RECEIVER.md b/RECEIVER.md index fe1493e..13ce77a 100644 --- a/RECEIVER.md +++ b/RECEIVER.md @@ -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). -#### NEC classes +#### NEC classes (includes Samsung) -`NEC_8`, `NEC_16` +`NEC_8`, `NEC_16`, `SAMSUNG` 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. +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` diff --git a/TRANSMITTER.md b/TRANSMITTER.md index a328d68..c76995b 100644 --- a/TRANSMITTER.md +++ b/TRANSMITTER.md @@ -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. -## 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. @@ -169,7 +172,7 @@ skipping validation. | RC6_M0 | 6.0ms | 2.0ms | | MCE | 6.7ms | 2.0ms | -#### NEC class +#### NEC class (also Samsung) Class `NEC`. Example invocation: ```python @@ -187,6 +190,16 @@ the complement for values < 256. 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: diff --git a/ir_rx/acquire.py b/ir_rx/acquire.py index ea0b2e4..af3ab38 100644 --- a/ir_rx/acquire.py +++ b/ir_rx/acquire.py @@ -70,8 +70,8 @@ class IR_GET(IR_RX): 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? diff --git a/ir_rx/nec.py b/ir_rx/nec.py index e516924..011b13d 100644 --- a/ir_rx/nec.py +++ b/ir_rx/nec.py @@ -1,26 +1,29 @@ # 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 -# 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): - 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 + 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]) - 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 @@ -55,8 +58,12 @@ class NEC_ABC(IR_RX): 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): - 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 index 382dcbf..0000000 --- a/ir_rx/samsung.py +++ /dev/null @@ -1,37 +0,0 @@ -# samsung.py Decoder for IR remote control using synchronous code -# Supports Samsung TV remote protocols. - -# Author: J.E. Tannenbaum -# Copyright J.E.Tannenbaum 2021 Released under the MIT license - -from utime import ticks_us, ticks_diff -from ir_rx import IR_RX - -class SAMSUNG(IR_RX): - def __init__(self, pin, callback, *args): - super().__init__(pin, 68, 80, callback, *args) - - def decode(self, _): - def near(v, target): - return target * 0.8 < v < target * 1.2 - - lb = self.edge - 1 # Possible length of burst - burst = [] - for x in range(lb): - dt = ticks_diff(self._times[x + 1], self._times[x]) - if x > 0 and dt > 10000: # Reached gap between repeats - break - burst.append(dt) - - lb = len(burst) # Actual length - cmd = 0 - if near(burst[0], 4500) and near(burst[1], 4500) and lb == 67: - # Skip the starting bits and the checksum at the end of the sequence - for x in range(2, lb - 1, 2): - cmd *= 2 - # Test for logical 1 (One byte low, next byte high) - if burst[x] < 1000 and burst[x + 1] > 1000: - cmd += 1 - - # Set up for new data burst and run user callback - self.do_callback(cmd, 0, 0) diff --git a/ir_rx/test.py b/ir_rx/test.py index 48f342e..c4dbd7f 100644 --- a/ir_rx/test.py +++ b/ir_rx/test.py @@ -2,7 +2,7 @@ # 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. @@ -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 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 -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) -elif platform == 'esp32' or platform == 'esp32_LoBo': +elif platform == "esp32" or platform == "esp32_LoBo": 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. - print('Repeat code.') + print("Repeat code.") 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): - 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.verbose = True + # ir.verbose = True # A real application would do something here... try: while True: - print('running') + print("running") time.sleep(5) gc.collect() except KeyboardInterrupt: ir.close() + # **** 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, @@ -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(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) diff --git a/ir_tx/nec.py b/ir_tx/nec.py index da1af24..807ec68 100644 --- a/ir_tx/nec.py +++ b/ir_tx/nec.py @@ -2,8 +2,9 @@ # 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 @@ -12,15 +13,19 @@ _T_ONE = const(1687) 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 - 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):