]> vault307.fbx.one Git - micorpython_ir.git/blob - ir_tx.py
97578407f391b9469929c168336c81db647033ca
[micorpython_ir.git] / ir_tx.py
1 # ir_tx.py Nonblocking IR blaster
2 # Runs on Pyboard D or Pyboard 1.x only (not Pyboard Lite)
3
4 # Released under the MIT License (MIT). See LICENSE.
5
6 # Copyright (c) 2020 Peter Hinch
7
8 from pyb import Pin, Timer
9 from time import sleep_us, sleep
10 from micropython import const
11 from array import array
12 import micropython
13
14 # micropython.alloc_emergency_exception_buf(100)
15
16 # Common
17 _SPACE = const(0) # Or 100. Depends on wiring: 0 assumes logic 0 turns IR off.
18 _STOP = const(0) # End of data
19 # NEC
20 _TBURST = const(563)
21 _T_ONE = const(1687)
22 # RC5
23 _T_RC5 = const(889) # Time for pulse of carrier
24 # RC6_M0
25 _T_RC6 = const(444)
26 _T2_RC6 = const(889)
27
28 # IR abstract base class. Array holds periods in μs between toggling 36/38KHz
29 # carrier on or off.
30 # Subclass is responsible for populating .arr and initiating transmission.
31 # Operation is in two phases: .transmit populates .arr with times in μs, then
32 # calls .start to initiate physical transmission.
33 class IR:
34
35 def __init__(self, pin, freq, asize, duty):
36 tim = Timer(2, freq=freq)
37 self._ch = tim.channel(1, Timer.PWM, pin=pin)
38 self._ch.pulse_width_percent(_SPACE)
39 self.duty = duty
40 self.arr = array('H', 0 for _ in range(asize))
41 self._tim = Timer(5)
42 self._tcb = self._cb
43 self.pretrans()
44
45 # Before populating array, zero pointer, set notional carrier state (off).
46 def pretrans(self):
47 self.aptr = 0 # Index into array
48 self.carrier = False
49
50 def start(self):
51 self.aptr = 0 # Reset pointer and initiate TX.
52 self._cb(self._tim)
53
54 def _cb(self, t):
55 t.deinit()
56 p = self.aptr
57 v = self.arr[p]
58 if v == _STOP:
59 self._ch.pulse_width_percent(_SPACE) # Turn off IR LED.
60 return
61 self._ch.pulse_width_percent(_SPACE if p & 1 else self.duty)
62 self._tim.init(prescaler=84, period=v, callback=self._tcb)
63 self.aptr += 1
64
65 def append(self, *times): # Append one or more time peiods to .arr
66 for t in times:
67 self.arr[self.aptr] = t
68 self.aptr += 1
69 self.carrier = not self.carrier # Keep track of carrier state
70 print('append', t, 'carrier', self.carrier)
71
72 def add(self, t): # Increase last time value
73 print('add', t)
74 self.arr[self.aptr - 1] += t # Carrier unaffected
75
76 # NEC protocol
77 class NEC(IR):
78
79 def __init__(self, pin, freq=38000): # NEC specifies 38KHz
80 super().__init__(pin, freq, 68, 50)
81
82 def _bit(self, b):
83 self.append(_TBURST, _T_ONE if b else _TBURST)
84
85 def transmit(self, addr, data, _=0): # Ignore toggle if passed
86 self.pretrans() # Set initial conditions
87 self.append(9000, 4500)
88 if addr < 256: # Short address: append complement
89 addr |= ((addr ^ 0xff) << 8)
90 for x in range(16):
91 self._bit(addr & 1)
92 addr >>= 1
93 data |= ((data ^ 0xff) << 8)
94 for x in range(16):
95 self._bit(data & 1)
96 data >>= 1
97 self.append(_TBURST, _STOP)
98 self.start()
99
100 def repeat(self):
101 self.aptr = 0
102 self.append(9000, 2250, _TBURST, _STOP)
103
104
105 # Philips RC5 protocol
106 class RC5(IR):
107
108 def __init__(self, pin, freq=36000):
109 super().__init__(pin, freq, 28, 30)
110
111 def transmit(self, addr, data, toggle):
112 self.pretrans() # Set initial conditions
113 d = (data & 0x3f) | ((addr & 0x1f) << 6) | ((data & 0x40) << 6) | ((toggle & 1) << 11)
114 print(bin(d))
115 mask = 0x2000
116 while mask:
117 if mask == 0x2000:
118 self.append(_T_RC5)
119 else:
120 bit = bool(d & mask)
121 if bit ^ self.carrier:
122 self.add(_T_RC5)
123 self.append(_T_RC5)
124 else:
125 self.append(_T_RC5, _T_RC5)
126 mask >>= 1
127 self.append(_STOP)
128 self.start()
129
130 # Philips RC6 mode 0 protocol
131 class RC6_M0(IR):
132
133 def __init__(self, pin, freq=36000):
134 super().__init__(pin, freq, 44, 30)
135
136 def transmit(self, addr, data, toggle):
137 self.pretrans() # Set initial conditions
138 # leader, 1, 0, 0, 0
139 self.append(2666, _T2_RC6, _T_RC6, _T2_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6, _T_RC6)
140 # Append a single bit of twice duration
141 if toggle:
142 self.add(_T2_RC6)
143 self.append(_T2_RC6)
144 else:
145 self.append(_T2_RC6, _T2_RC6)
146 d = (data & 0xff) | ((addr & 0xff) << 8)
147 mask = 0x8000
148 print('toggle', toggle, self.carrier, bool(d & mask))
149 while mask:
150 bit = bool(d & mask)
151 if bit ^ self.carrier:
152 self.append(_T_RC6, _T_RC6)
153 else:
154 self.add(_T_RC6)
155 self.append(_T_RC6)
156 mask >>= 1
157 self.append(_STOP)
158 self.start()