63 lines
2.4 KiB
Python
63 lines
2.4 KiB
Python
# nec.py Decoder for IR remote control using synchronous code
|
|
# 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 utime import ticks_us, ticks_diff
|
|
from stm32_ir_receiver import IR_RX
|
|
|
|
class NEC_ABC(IR_RX):
|
|
def __init__(self, pin, extended, callback, *args):
|
|
# Block lasts <= 80ms (extended mode) and has 68 edges
|
|
super().__init__(pin, 68, 80, callback, *args)
|
|
self._extended = extended
|
|
self._addr = 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
|
|
raise RuntimeError(self.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(self.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(self.REPEAT if self.edge == 4 else self.BADREP) # Treat REPEAT as error.
|
|
else:
|
|
raise RuntimeError(self.BADSTART)
|
|
addr = val & 0xff # 8 bit addr
|
|
cmd = (val >> 16) & 0xff
|
|
if cmd != (val >> 24) ^ 0xff:
|
|
raise RuntimeError(self.BADDATA)
|
|
if addr != ((val >> 8) ^ 0xff) & 0xff: # 8 bit addr doesn't match check
|
|
if not self._extended:
|
|
raise RuntimeError(self.BADADDR)
|
|
addr |= val & 0xff00 # pass assumed 16 bit address to callback
|
|
self._addr = addr
|
|
except RuntimeError as e:
|
|
cmd = e.args[0]
|
|
addr = self._addr if cmd == self.REPEAT else 0 # REPEAT uses last address
|
|
# Set up for new data burst and run user callback
|
|
self.do_callback(cmd, addr, 0, self.REPEAT)
|
|
|
|
class NEC_8(NEC_ABC):
|
|
def __init__(self, pin, callback, *args):
|
|
super().__init__(pin, False, callback, *args)
|
|
|
|
class NEC_16(NEC_ABC):
|
|
def __init__(self, pin, callback, *args):
|
|
super().__init__(pin, True, callback, *args)
|