Skip to content

Commit 4c8dc6e

Browse files
committed
Added support for fast loading.
Added IR library https://github.com/peterhinch/micropython_ir Updated axp202_adc_brightness.py Updated mpconfigboard.h
1 parent 43ce4df commit 4c8dc6e

File tree

18 files changed

+1131
-6
lines changed

18 files changed

+1131
-6
lines changed

Diff for: examples/ttgo/axp202_adc_brightness.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def set_batt_per(per):
6969
update_task(None)
7070
lv.scr_load(scr)
7171
watch.tft.backlight_fade(100)
72-
# lv.task_create(update_task, 1000, 5, None)
72+
lv.task_create(update_task, 1000, 5, None)
7373

7474

7575

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# ir_rx __init__.py Decoder for IR remote control using synchronous code
2+
# IR_RX abstract base class for IR receivers.
3+
4+
# Author: Peter Hinch
5+
# Copyright Peter Hinch 2020 Released under the MIT license
6+
7+
from machine import Timer, Pin
8+
from array import array
9+
from utime import ticks_us
10+
11+
# Save RAM
12+
# from micropython import alloc_emergency_exception_buf
13+
# alloc_emergency_exception_buf(100)
14+
15+
16+
# On 1st edge start a block timer. While the timer is running, record the time
17+
# of each edge. When the timer times out decode the data. Duration must exceed
18+
# the worst case block transmission time, but be less than the interval between
19+
# a block start and a repeat code start (~108ms depending on protocol)
20+
21+
class IR_RX():
22+
# Result/error codes
23+
# Repeat button code
24+
REPEAT = -1
25+
# Error codes
26+
BADSTART = -2
27+
BADBLOCK = -3
28+
BADREP = -4
29+
OVERRUN = -5
30+
BADDATA = -6
31+
BADADDR = -7
32+
33+
def __init__(self, pin, nedges, tblock, callback, *args): # Optional args for callback
34+
self._pin = pin
35+
self._nedges = nedges
36+
self._tblock = tblock
37+
self.callback = callback
38+
self.args = args
39+
self._errf = lambda _ : None
40+
self.verbose = False
41+
42+
self._times = array('i', (0 for _ in range(nedges + 1))) # +1 for overrun
43+
pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
44+
self.edge = 0
45+
self.tim = Timer(-1) # Sofware timer
46+
self.cb = self.decode
47+
48+
# Pin interrupt. Save time of each edge for later decode.
49+
def _cb_pin(self, line):
50+
t = ticks_us()
51+
# On overrun ignore pulses until software timer times out
52+
if self.edge <= self._nedges: # Allow 1 extra pulse to record overrun
53+
if not self.edge: # First edge received
54+
self.tim.init(period=self._tblock , mode=Timer.ONE_SHOT, callback=self.cb)
55+
self._times[self.edge] = t
56+
self.edge += 1
57+
58+
def do_callback(self, cmd, addr, ext, thresh=0):
59+
self.edge = 0
60+
if cmd >= thresh:
61+
self.callback(cmd, addr, ext, *self.args)
62+
else:
63+
self._errf(cmd)
64+
65+
def error_function(self, func):
66+
self._errf = func
67+
68+
def close(self):
69+
self._pin.irq(handler = None)
70+
self.tim.deinit()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# acquire.py Acquire a pulse train from an IR remote
2+
# Supports NEC protocol.
3+
# For a remote using NEC see https://www.adafruit.com/products/389
4+
5+
# Author: Peter Hinch
6+
# Copyright Peter Hinch 2020 Released under the MIT license
7+
8+
from machine import Pin, freq
9+
from sys import platform
10+
11+
from utime import sleep_ms, ticks_us, ticks_diff
12+
from ir_rx import IR_RX
13+
14+
15+
class IR_GET(IR_RX):
16+
def __init__(self, pin, nedges=100, twait=100, display=True):
17+
self.display = display
18+
super().__init__(pin, nedges, twait, lambda *_ : None)
19+
self.data = None
20+
21+
def decode(self, _):
22+
def near(v, target):
23+
return target * 0.8 < v < target * 1.2
24+
lb = self.edge - 1 # Possible length of burst
25+
if lb < 3:
26+
return # Noise
27+
burst = []
28+
for x in range(lb):
29+
dt = ticks_diff(self._times[x + 1], self._times[x])
30+
if x > 0 and dt > 10000: # Reached gap between repeats
31+
break
32+
burst.append(dt)
33+
lb = len(burst) # Actual length
34+
# Duration of pulse train 24892 for RC-5 22205 for RC-6
35+
duration = ticks_diff(self._times[lb - 1], self._times[0])
36+
37+
if self.display:
38+
for x, e in enumerate(burst):
39+
print('{:03d} {:5d}'.format(x, e))
40+
print()
41+
# Attempt to determine protocol
42+
ok = False # Protocol not yet found
43+
if near(burst[0], 9000) and lb == 67:
44+
print('NEC')
45+
ok = True
46+
47+
if not ok and near(burst[0], 2400) and near(burst[1], 600): # Maybe Sony
48+
try:
49+
nbits = {25:12, 31:15, 41:20}[lb]
50+
except KeyError:
51+
pass
52+
else:
53+
ok = True
54+
print('Sony {}bit'.format(nbits))
55+
56+
if not ok and near(burst[0], 889): # Maybe RC-5
57+
if near(duration, 24892) and near(max(burst), 1778):
58+
print('Philps RC-5')
59+
ok = True
60+
61+
if not ok and near(burst[0], 2666) and near(burst[1], 889): # RC-6?
62+
if near(duration, 22205) and near(burst[1], 889) and near(burst[2], 444):
63+
print('Philips RC-6 mode 0')
64+
ok = True
65+
66+
if not ok and near(burst[0], 2000) and near(burst[1], 1000):
67+
if near(duration, 19000):
68+
print('Microsoft MCE edition protocol.')
69+
# Constant duration, variable burst length, presumably bi-phase
70+
print('Protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration))
71+
ok = True
72+
73+
if not ok and near(burst[0], 4500) and near(burst[1], 4500): # Samsung?
74+
print('Unsupported protocol. Samsung?')
75+
ok = True
76+
77+
if not ok and near(burst[0], 3500) and near(burst[1], 1680): # Panasonic?
78+
print('Unsupported protocol. Panasonic?')
79+
ok = True
80+
81+
if not ok:
82+
print('Unknown protocol start {} {} Burst length {} duration {}'.format(burst[0], burst[1], lb, duration))
83+
84+
print()
85+
self.data = burst
86+
# Set up for new data burst. Run null callback
87+
self.do_callback(0, 0, 0)
88+
89+
def acquire(self):
90+
while self.data is None:
91+
sleep_ms(5)
92+
self.close()
93+
return self.data
94+
95+
def test():
96+
# Define pin according to platform
97+
if platform == 'pyboard':
98+
pin = Pin('X3', Pin.IN)
99+
elif platform == 'esp8266':
100+
freq(160000000)
101+
pin = Pin(13, Pin.IN)
102+
elif platform == 'esp32' or platform == 'esp32_LoBo':
103+
pin = Pin(23, Pin.IN)
104+
irg = IR_GET(pin)
105+
print('Waiting for IR data...')
106+
return irg.acquire()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# mce.py Decoder for IR remote control using synchronous code
2+
# Supports Microsoft MCE edition remote protocol.
3+
4+
# Author: Peter Hinch
5+
# Copyright Peter Hinch 2020 Released under the MIT license
6+
7+
# WARNING: This is experimental and subject to change.
8+
9+
from utime import ticks_us, ticks_diff
10+
from ir_rx import IR_RX
11+
12+
class MCE(IR_RX):
13+
init_cs = 4 # http://www.hifi-remote.com/johnsfine/DecodeIR.html#OrtekMCE says 3
14+
def __init__(self, pin, callback, *args):
15+
# Block lasts ~19ms and has <= 34 edges
16+
super().__init__(pin, 34, 25, callback, *args)
17+
18+
def decode(self, _):
19+
def check(v):
20+
if self.init_cs == -1:
21+
return True
22+
csum = v >> 12
23+
cs = self.init_cs
24+
for _ in range(12):
25+
if v & 1:
26+
cs += 1
27+
v >>= 1
28+
return cs == csum
29+
30+
try:
31+
t0 = ticks_diff(self._times[1], self._times[0]) # 2000μs mark
32+
t1 = ticks_diff(self._times[2], self._times[1]) # 1000μs space
33+
if not ((1800 < t0 < 2200) and (800 < t1 < 1200)):
34+
raise RuntimeError(self.BADSTART)
35+
nedges = self.edge # No. of edges detected
36+
if not 14 <= nedges <= 34:
37+
raise RuntimeError(self.OVERRUN if nedges > 28 else self.BADSTART)
38+
# Manchester decode
39+
mask = 1
40+
bit = 1
41+
v = 0
42+
x = 2
43+
for _ in range(16):
44+
# -1 convert count to index, -1 because we look ahead
45+
if x > nedges - 2:
46+
raise RuntimeError(self.BADBLOCK)
47+
# width is 500/1000 nominal
48+
width = ticks_diff(self._times[x + 1], self._times[x])
49+
if not 250 < width < 1350:
50+
self.verbose and print('Bad block 3 Width', width, 'x', x)
51+
raise RuntimeError(self.BADBLOCK)
52+
short = int(width < 750)
53+
bit ^= short ^ 1
54+
v |= mask if bit else 0
55+
mask <<= 1
56+
x += 1 + short
57+
58+
self.verbose and print(bin(v))
59+
if not check(v):
60+
raise RuntimeError(self.BADDATA)
61+
val = (v >> 6) & 0x3f
62+
addr = v & 0xf # Constant for all buttons on my remote
63+
ctrl = (v >> 4) & 3
64+
65+
except RuntimeError as e:
66+
val, addr, ctrl = e.args[0], 0, 0
67+
# Set up for new data burst and run user callback/error function
68+
self.do_callback(val, addr, ctrl)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# nec.py Decoder for IR remote control using synchronous code
2+
# Supports NEC protocol.
3+
# For a remote using NEC see https://www.adafruit.com/products/389
4+
5+
# Author: Peter Hinch
6+
# Copyright Peter Hinch 2020 Released under the MIT license
7+
8+
from utime import ticks_us, ticks_diff
9+
from ir_rx import IR_RX
10+
11+
class NEC_ABC(IR_RX):
12+
def __init__(self, pin, extended, callback, *args):
13+
# Block lasts <= 80ms (extended mode) and has 68 edges
14+
super().__init__(pin, 68, 80, callback, *args)
15+
self._extended = extended
16+
self._addr = 0
17+
18+
def decode(self, _):
19+
try:
20+
if self.edge > 68:
21+
raise RuntimeError(self.OVERRUN)
22+
width = ticks_diff(self._times[1], self._times[0])
23+
if width < 4000: # 9ms leading mark for all valid data
24+
raise RuntimeError(self.BADSTART)
25+
width = ticks_diff(self._times[2], self._times[1])
26+
if width > 3000: # 4.5ms space for normal data
27+
if self.edge < 68: # Haven't received the correct number of edges
28+
raise RuntimeError(self.BADBLOCK)
29+
# Time spaces only (marks are always 562.5µs)
30+
# Space is 1.6875ms (1) or 562.5µs (0)
31+
# Skip last bit which is always 1
32+
val = 0
33+
for edge in range(3, 68 - 2, 2):
34+
val >>= 1
35+
if ticks_diff(self._times[edge + 1], self._times[edge]) > 1120:
36+
val |= 0x80000000
37+
elif width > 1700: # 2.5ms space for a repeat code. Should have exactly 4 edges.
38+
raise RuntimeError(self.REPEAT if self.edge == 4 else self.BADREP) # Treat REPEAT as error.
39+
else:
40+
raise RuntimeError(self.BADSTART)
41+
addr = val & 0xff # 8 bit addr
42+
cmd = (val >> 16) & 0xff
43+
if cmd != (val >> 24) ^ 0xff:
44+
raise RuntimeError(self.BADDATA)
45+
if addr != ((val >> 8) ^ 0xff) & 0xff: # 8 bit addr doesn't match check
46+
if not self._extended:
47+
raise RuntimeError(self.BADADDR)
48+
addr |= val & 0xff00 # pass assumed 16 bit address to callback
49+
self._addr = addr
50+
except RuntimeError as e:
51+
cmd = e.args[0]
52+
addr = self._addr if cmd == self.REPEAT else 0 # REPEAT uses last address
53+
# Set up for new data burst and run user callback
54+
self.do_callback(cmd, addr, 0, self.REPEAT)
55+
56+
class NEC_8(NEC_ABC):
57+
def __init__(self, pin, callback, *args):
58+
super().__init__(pin, False, callback, *args)
59+
60+
class NEC_16(NEC_ABC):
61+
def __init__(self, pin, callback, *args):
62+
super().__init__(pin, True, callback, *args)

0 commit comments

Comments
 (0)