]>
vault307.fbx.one Git - micorpython_ir.git/blob - ir_rx.py
896d9cdb4c5269931d90e77baf040dae509a1102
1 # ir_rx.py Decoder for IR remote control using synchronous code
2 # Supports RC-5 RC-6 mode 0 and NEC protocols.
3 # For a remote using NEC see https://www.adafruit.com/products/389
6 # Copyright Peter Hinch 2020 Released under the MIT license
8 from sys
import platform
9 from micropython
import const
10 from machine
import Timer
11 from array
import array
12 from utime
import ticks_us
, ticks_diff
14 if platform
== 'pyboard':
15 from pyb
import Pin
, ExtInt
17 from machine
import Pin
19 ESP32
= platform
== 'esp32' or platform
== 'esp32_LoBo'
22 # from micropython import alloc_emergency_exception_buf
23 # alloc_emergency_exception_buf(100)
25 # Result codes (accessible to application)
37 # On 1st edge start a block timer. While the timer is running, record the time
38 # of each edge. When the timer times out decode the data. Duration must exceed
39 # the worst case block transmission time, but be less than the interval between
40 # a block start and a repeat code start (~108ms depending on protocol)
43 def __init__(self
, pin
, nedges
, tblock
, callback
, *args
): # Optional args for callback
46 self
.callback
= callback
49 self
._times
= array('i', (0 for _
in range(nedges
+ 1))) # +1 for overrun
50 if platform
== 'pyboard':
51 ExtInt(pin
, ExtInt
.IRQ_RISING_FALLING
, Pin
.PULL_NONE
, self
._cb
_pin
)
53 pin
.irq(handler
= self
._cb
_pin
, trigger
= (Pin
.IRQ_FALLING | Pin
.IRQ_RISING
))
55 pin
.irq(handler
= self
._cb
_pin
, trigger
= (Pin
.IRQ_FALLING | Pin
.IRQ_RISING
), hard
= True)
57 self
.tim
= Timer(-1) # Sofware timer
58 self
.cb
= self
._decode
61 # Pin interrupt. Save time of each edge for later decode.
62 def _cb_pin(self
, line
):
64 # On overrun ignore pulses until software timer times out
65 if self
.edge
<= self
._nedges
: # Allow 1 extra pulse to record overrun
66 if not self
.edge
: # First edge received
67 self
.tim
.init(period
=self
._tblock
, mode
=Timer
.ONE_SHOT
, callback
=self
.cb
)
68 self
._times
[self
.edge
] = t
72 def __init__(self
, pin
, callback
, extended
, *args
):
73 # Block lasts <= 80ms and has 68 edges
74 tblock
= 80 if extended
else 73 # Allow for some tx tolerance (?)
75 super().__init
__(pin
, 68, tblock
, callback
, *args
)
76 self
._extended
= extended
80 overrun
= self
.edge
> 68
81 val
= OVERRUN
if overrun
else BADSTART
83 width
= ticks_diff(self
._times
[1], self
._times
[0])
84 if width
> 4000: # 9ms leading mark for all valid data
85 width
= ticks_diff(self
._times
[2], self
._times
[1])
86 if width
> 3000: # 4.5ms space for normal data
88 # Haven't received the correct number of edges
91 # Time spaces only (marks are always 562.5µs)
92 # Space is 1.6875ms (1) or 562.5µs (0)
93 # Skip last bit which is always 1
95 for edge
in range(3, 68 - 2, 2):
97 if ticks_diff(self
._times
[edge
+ 1], self
._times
[edge
]) > 1120:
99 elif width
> 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges.
100 val
= REPEAT
if self
.edge
== 4 else BADREP
102 if val
>= 0: # validate. Byte layout of val ~cmd cmd ~addr addr
104 cmd
= (val
>> 16) & 0xff
105 if addr
== ((val
>> 8) ^
0xff) & 0xff: # 8 bit address OK
106 val
= cmd
if cmd
== (val
>> 24) ^
0xff else BADDATA
109 addr |
= val
& 0xff00 # pass assumed 16 bit address to callback
111 val
= cmd
if cmd
== (val
>> 24) ^
0xff else BADDATA
116 addr
= self
._addr
# Last valid addresss
117 self
.edge
= 0 # Set up for new data burst and run user callback
118 self
.callback(val
, addr
, *self
.args
)
121 def __init__(self
, pin
, callback
, *args
):
122 # Block lasts <= 30ms and has <= 28 edges
123 super().__init
__(pin
, 28, 30, callback
, *args
)
125 def _decode(self
, _
):
127 nedges
= self
.edge
# No. of edges detected
128 if not 14 <= nedges
<= 28:
129 raise RuntimeError(OVERRUN
if nedges
> 28 else BADSTART
)
130 # Regenerate bitstream
133 for x
in range(1, nedges
):
134 width
= ticks_diff(self
._times
[x
], self
._times
[x
- 1])
135 if not 500 < width
< 2000:
136 raise RuntimeError(BADBLOCK
)
137 for _
in range(1 if width
< 1334 else 2):
141 #print(bin(bits)) # Matches inverted scope waveform
142 # Decode Manchester code
146 m0
= 1 << x
# Mask MS two bits (always 01)
148 v
= 0 # 14 bit bitstream
154 raise RuntimeError(BADBLOCK
)
158 # Split into fields (val, addr, ctrl)
159 val
= (v
& 0x3f) |
(0x40 if ((v
>> 12) & 1) else 0)
160 addr
= (v
>> 6) & 0x1f
163 except RuntimeError as e
:
164 val
, addr
, ctrl
= e
.args
[0], 0, 0
165 self
.edge
= 0 # Set up for new data burst and run user callback
166 self
.callback(val
, addr
, ctrl
, *self
.args
)
169 # Even on Pyboard D the 444μs nominal pulses can be recorded as up to 705μs
170 # Scope shows 360-520 μs (-84μs +76μs relative to nominal)
171 # Header nominal 2666, 889, 444, 889, 444, 444, 444, 444 carrier ON at end
172 hdr
= ((1800, 4000), (593, 1333), (222, 750), (593, 1333), (222, 750), (222, 750), (222, 750), (222, 750))
173 def __init__(self
, pin
, callback
, *args
):
174 # Block lasts 23ms nominal and has <=44 edges
175 super().__init
__(pin
, 44, 30, callback
, *args
)
177 def _decode(self
, _
):
179 nedges
= self
.edge
# No. of edges detected
180 if not 22 <= nedges
<= 44:
181 raise RuntimeError(OVERRUN
if nedges
> 28 else BADSTART
)
182 for x
, lims
in enumerate(self
.hdr
):
183 width
= ticks_diff(self
._times
[x
+ 1], self
._times
[x
])
184 #print('x = {}, width = {}, lims = {}'.format(x, width, lims))
185 if not (lims
[0] < width
< lims
[1]):
186 #print('Bad start', x, width, lims)
187 raise RuntimeError(BADSTART
)
189 width
= ticks_diff(self
._times
[x
+ 1], self
._times
[x
])
190 # Long bit is 889μs (0) or 1333μs (1)
191 ctrl
= width
> 1111 # If 1333, ctrl == True and carrier is off
192 start
= x
+ 2 if ctrl
else x
+ 3 # Skip 2nd long bit
194 # Regenerate bitstream
195 bits
= 1 # MSB is a dummy 1 to mark start of bitstream
197 for x
in range(start
, nedges
- 1):
198 width
= ticks_diff(self
._times
[x
+ 1], self
._times
[x
])
199 if not 222 < width
< 1333:
200 #print('Width', width, 'x', x)
201 raise RuntimeError(BADBLOCK
)
202 for _
in range(1 if width
< 666 else 2):
206 print('36-bit format {:036b} x={} nedges={}'.format(bits
, x
, nedges
))
208 # Decode Manchester code. Bitstream varies in length: find MS 1.
212 # Now points to dummy 1
213 x
-= 2 # Point to MS biphase pair
215 m1
= m0
<< 1 # MSB of pair
216 v
= 0 # 16 bit bitstream
221 print(int(b1
), int(b0
))
223 raise RuntimeError(BADBLOCK
)
227 # Split into fields (val, addr)
229 addr
= (v
>> 8) & 0xff
231 except RuntimeError as e
:
232 val
, addr
, ctrl
= e
.args
[0], 0, 0
233 self
.edge
= 0 # Set up for new data burst and run user callback
234 self
.callback(val
, addr
, ctrl
, *self
.args
)