From: Peter Hinch Date: Tue, 25 Feb 2020 06:55:03 +0000 (+0000) Subject: Prior to RC6 rx redesign. X-Git-Url: https://vault307.fbx.one/gitweb/micorpython_ir.git/commitdiff_plain/d60573594da7d18c86ff2bfd954a86a23eebcbe9 Prior to RC6 rx redesign. --- diff --git a/ir_rx.py b/ir_rx.py index 6f20b2b..896d9cd 100644 --- a/ir_rx.py +++ b/ir_rx.py @@ -166,7 +166,9 @@ 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 @@ -179,43 +181,47 @@ class RC6_M0(IR_RX): raise RuntimeError(OVERRUN if nedges > 28 else BADSTART) for x, lims in enumerate(self.hdr): width = ticks_diff(self._times[x + 1], self._times[x]) + #print('x = {}, width = {}, lims = {}'.format(x, width, lims)) if not (lims[0] < width < lims[1]): - print('Bad start', x, width, lims) + #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 + # Long bit is 889μs (0) or 1333μs (1) + ctrl = width > 1111 # If 1333, ctrl == True and carrier is off + start = x + 2 if ctrl else x + 3 # 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]) + bits = 1 # MSB is a dummy 1 to mark start of bitstream + bit = int(ctrl) + for x in range(start, nedges - 1): + width = ticks_diff(self._times[x + 1], self._times[x]) if not 222 < width < 1333: - print('Width', width) + #print('Width', width, 'x', x) raise RuntimeError(BADBLOCK) for _ in range(1 if width < 666 else 2): bits <<= 1 bits |= bit bit ^= 1 - print(bin(bits), len(bin(bits)) - 2) + print('36-bit format {:036b} x={} nedges={}'.format(bits, x, nedges)) - # Decode Manchester code - x = 32 + # Decode Manchester code. Bitstream varies in length: find MS 1. + x = 36 while not bits >> x: x -= 1 - m0 = 1 << (x - 1) - m1 = 1 << x # MSB of pair + # Now points to dummy 1 + x -= 2 # Point to MS biphase pair + m0 = 1 << x + m1 = m0 << 1 # 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)) + print(int(b1), int(b0)) if b0 == b1: raise RuntimeError(BADBLOCK) - v |= b0 + v |= b1 m0 >>= 2 m1 >>= 2 # Split into fields (val, addr) diff --git a/ir_rx_test.py b/ir_rx_test.py index 908d23f..401c077 100644 --- a/ir_rx_test.py +++ b/ir_rx_test.py @@ -9,7 +9,7 @@ from sys import platform import time from machine import Pin, freq -from arem import * +from ir_rx import * ESP32 = platform == 'esp32' or platform == 'esp32_LoBo' diff --git a/ir_tx.py b/ir_tx.py index 9757840..0697d9a 100644 --- a/ir_tx.py +++ b/ir_tx.py @@ -26,39 +26,41 @@ _T_RC6 = const(444) _T2_RC6 = const(889) # IR abstract base class. Array holds periods in μs between toggling 36/38KHz -# carrier on or off. -# Subclass is responsible for populating .arr and initiating transmission. -# Operation is in two phases: .transmit populates .arr with times in μs, then -# calls .start to initiate physical transmission. +# carrier on or off. Physical transmission occurs in an ISR context controlled +# by timer 2 and timer 5. +# Operation is in two phases: .transmit populates .arr with times in μs (via +# subclass), then initiates physical transmission. class IR: - def __init__(self, pin, freq, asize, duty): - tim = Timer(2, freq=freq) + def __init__(self, pin, freq, asize, duty, verbose): + tim = Timer(2, freq=freq) # Timer 2/pin produces 36/38KHz carrier self._ch = tim.channel(1, Timer.PWM, pin=pin) - self._ch.pulse_width_percent(_SPACE) - self.duty = duty - self.arr = array('H', 0 for _ in range(asize)) - self._tim = Timer(5) + self._ch.pulse_width_percent(_SPACE) # Turn off IR LED + self._duty = duty + self._tim = Timer(5) # Timer 5 controls carrier on/off times self._tcb = self._cb - self.pretrans() + self.verbose = verbose + self.arr = array('H', 0 for _ in range(asize)) # on/off times (μs) + self.carrier = False # Notional carrier state while encoding biphase + self.aptr = 0 # Index into array # Before populating array, zero pointer, set notional carrier state (off). - def pretrans(self): - self.aptr = 0 # Index into array + def transmit(self, addr, data, toggle=0): # NEC: toggle is unused + self.aptr = 0 # Inital conditions for tx: index into array self.carrier = False + self.tx(addr, data, toggle) + self.append(_STOP) + self.aptr = 0 # Reset pointer + self._cb(self._tim) # Initiate physical transmission. - def start(self): - self.aptr = 0 # Reset pointer and initiate TX. - self._cb(self._tim) - - def _cb(self, t): + def _cb(self, t): # T5 callback, generate a carrier mark or space t.deinit() p = self.aptr v = self.arr[p] if v == _STOP: self._ch.pulse_width_percent(_SPACE) # Turn off IR LED. return - self._ch.pulse_width_percent(_SPACE if p & 1 else self.duty) + self._ch.pulse_width_percent(_SPACE if p & 1 else self._duty) self._tim.init(prescaler=84, period=v, callback=self._tcb) self.aptr += 1 @@ -67,23 +69,22 @@ class IR: self.arr[self.aptr] = t self.aptr += 1 self.carrier = not self.carrier # Keep track of carrier state - print('append', t, 'carrier', self.carrier) + self.verbose and print('append', t, 'carrier', self.carrier) def add(self, t): # Increase last time value - print('add', t) + self.verbose and print('add', t) self.arr[self.aptr - 1] += t # Carrier unaffected # NEC protocol class NEC(IR): - def __init__(self, pin, freq=38000): # NEC specifies 38KHz - super().__init__(pin, freq, 68, 50) + def __init__(self, pin, freq=38000, verbose=False): # NEC specifies 38KHz + super().__init__(pin, freq, 68, 50, verbose) def _bit(self, b): self.append(_TBURST, _T_ONE if b else _TBURST) - def transmit(self, addr, data, _=0): # Ignore toggle if passed - self.pretrans() # Set initial conditions + def tx(self, addr, data, _): # Ignore toggle self.append(9000, 4500) if addr < 256: # Short address: append complement addr |= ((addr ^ 0xff) << 8) @@ -94,24 +95,22 @@ class NEC(IR): for x in range(16): self._bit(data & 1) data >>= 1 - self.append(_TBURST, _STOP) - self.start() + self.append(_TBURST,) def repeat(self): self.aptr = 0 - self.append(9000, 2250, _TBURST, _STOP) + self.append(9000, 2250, _TBURST) # Philips RC5 protocol class RC5(IR): - def __init__(self, pin, freq=36000): - super().__init__(pin, freq, 28, 30) + def __init__(self, pin, freq=36000, verbose=False): + super().__init__(pin, freq, 28, 30, verbose) - def transmit(self, addr, data, toggle): - self.pretrans() # Set initial conditions + def tx(self, addr, data, toggle): d = (data & 0x3f) | ((addr & 0x1f) << 6) | ((data & 0x40) << 6) | ((toggle & 1) << 11) - print(bin(d)) + self.verbose and print(bin(d)) mask = 0x2000 while mask: if mask == 0x2000: @@ -124,17 +123,14 @@ class RC5(IR): else: self.append(_T_RC5, _T_RC5) mask >>= 1 - self.append(_STOP) - self.start() # Philips RC6 mode 0 protocol class RC6_M0(IR): - def __init__(self, pin, freq=36000): - super().__init__(pin, freq, 44, 30) + def __init__(self, pin, freq=36000, verbose=False): + super().__init__(pin, freq, 44, 30, verbose) - def transmit(self, addr, data, toggle): - self.pretrans() # Set initial conditions + def tx(self, addr, data, toggle): # leader, 1, 0, 0, 0 self.append(2666, _T2_RC6, _T_RC6, _T2_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6) # Append a single bit of twice duration @@ -145,7 +141,7 @@ class RC6_M0(IR): self.append(_T2_RC6, _T2_RC6) d = (data & 0xff) | ((addr & 0xff) << 8) mask = 0x8000 - print('toggle', toggle, self.carrier, bool(d & mask)) + self.verbose and print('toggle', toggle, self.carrier, bool(d & mask)) while mask: bit = bool(d & mask) if bit ^ self.carrier: @@ -154,5 +150,3 @@ class RC6_M0(IR): self.add(_T_RC6) self.append(_T_RC6) mask >>= 1 - self.append(_STOP) - self.start() diff --git a/ir_tx_test.py b/ir_tx_test.py index 2d78728..0220c7b 100644 --- a/ir_tx_test.py +++ b/ir_tx_test.py @@ -54,13 +54,13 @@ async def main(proto): # Option to send REPEAT code. Most remotes do this. rep_code = True elif proto == 5: - irb = RC5(pin, 38000) + irb = RC5(pin, 38000) # My decoder chip is 38KHz elif proto == 6: - irb = RC6_M0(pin, 38000) + irb = RC6_M0(pin, 38000, True) # Verbose b = [] # Rbutton instances b.append(Rbutton(irb, Pin('X3', Pin.IN, Pin.PULL_UP), 0x1, 0x7, rep_code)) - b.append(Rbutton(irb, Pin('X4', Pin.IN, Pin.PULL_UP), 0x10, 0xb, rep_code)) + b.append(Rbutton(irb, Pin('X4', Pin.IN, Pin.PULL_UP), 0xfa, 0xb, rep_code)) led = LED(1) while True: await asyncio.sleep_ms(500) # Obligatory flashing LED.