]> vault307.fbx.one Git - micorpython_ir.git/blobdiff - ir_tx.py
README.md Include test results.
[micorpython_ir.git] / ir_tx.py
index 97578407f391b9469929c168336c81db647033ca..4a91336680394e324f9a9815a3156ce4dfd07448 100644 (file)
--- a/ir_tx.py
+++ b/ir_tx.py
@@ -6,7 +6,6 @@
 # Copyright (c) 2020 Peter Hinch
 
 from pyb import Pin, Timer
 # Copyright (c) 2020 Peter Hinch
 
 from pyb import Pin, Timer
-from time import sleep_us, sleep
 from micropython import const
 from array import array
 import micropython
 from micropython import const
 from array import array
 import micropython
@@ -26,39 +25,39 @@ _T_RC6 = const(444)
 _T2_RC6 = const(889)
 
 # IR abstract base class. Array holds periods in μs between toggling 36/38KHz
 _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. See README.md for details of operation.
 class IR:
 
 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 = 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._tcb = self._cb
-        self.pretrans()
+        self._ch.pulse_width_percent(_SPACE)  # Turn off IR LED
+        self._duty = duty if not _SPACE else (100 - duty)
+        self._tim = Timer(5)  # Timer 5 controls carrier on/off times
+        self._tcb = self.cb  # Pre-allocate
+        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).
 
     # 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.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
         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
 
         self._tim.init(prescaler=84, period=v, callback=self._tcb)
         self.aptr += 1
 
@@ -67,51 +66,74 @@ class IR:
             self.arr[self.aptr] = t
             self.aptr += 1
             self.carrier = not self.carrier  # Keep track of carrier state
             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
 
     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):
 
         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 _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)
         self.append(9000, 4500)
         if addr < 256:  # Short address: append complement
             addr |= ((addr ^ 0xff) << 8)
-        for x in range(16):
+        for _ in range(16):
             self._bit(addr & 1)
             addr >>= 1
         data |= ((data ^ 0xff) << 8)
             self._bit(addr & 1)
             addr >>= 1
         data |= ((data ^ 0xff) << 8)
-        for x in range(16):
+        for _ in range(16):
             self._bit(data & 1)
             data >>= 1
             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)
 
     def repeat(self):
         self.aptr = 0
         self.append(9000, 2250, _TBURST, _STOP)
+        self.aptr = 0  # Reset pointer
+        self.cb(self._tim)  # Initiate physical transmission.
+
+# NEC protocol
+class SONY(IR):
+
+    def __init__(self, pin, bits=12, freq=40000, verbose=False):  # Sony specifies 40KHz
+        super().__init__(pin, freq, 3 + bits * 2, 30, verbose)
+        if bits not in (12, 15, 20):
+            raise ValueError('bits must be 12, 15 or 20.')
+        self.bits = bits
+
+    def tx(self, addr, data, ext):
+        self.append(2400, 600)
+        bits = self.bits
+        v = data & 0x7f
+        if bits == 12:
+            v |= (addr & 0x1f) << 7
+        elif bits == 15:
+            v |= (addr & 0xff) << 7
+        else:
+            v |= (addr & 0x1f) << 7
+            v |= (ext & 0xff) << 12
+        for _ in range(bits):
+            self.append(1200 if v & 1 else 600, 600)
+            v >>= 1
 
 
 # Philips RC5 protocol
 class RC5(IR):
 
 
 
 # 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)
         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:
         mask = 0x2000
         while mask:
             if mask == 0x2000:
@@ -124,17 +146,14 @@ class RC5(IR):
                 else:
                     self.append(_T_RC5, _T_RC5)
             mask >>= 1
                 else:
                     self.append(_T_RC5, _T_RC5)
             mask >>= 1
-        self.append(_STOP)
-        self.start()
 
 # Philips RC6 mode 0 protocol
 class RC6_M0(IR):
 
 
 # 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
         # 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 +164,7 @@ class RC6_M0(IR):
             self.append(_T2_RC6, _T2_RC6)
         d = (data & 0xff) | ((addr & 0xff) << 8)
         mask = 0x8000
             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:
         while mask:
             bit = bool(d & mask)
             if bit ^ self.carrier:
@@ -154,5 +173,3 @@ class RC6_M0(IR):
                 self.add(_T_RC6)
                 self.append(_T_RC6)
             mask >>= 1
                 self.add(_T_RC6)
                 self.append(_T_RC6)
             mask >>= 1
-        self.append(_STOP)
-        self.start()