1. System IR remote information
eInstruction CPS-IR
8-button infrared remotes with unique serial numbers.

1.1. Framing
scope measurements, in microseconds:
-
start: 976
-
pause: 524
-
pulse: 160
-
zero: 472
-
one: 952
Circuit has a 455 kHz oscillator. 2.20 us period.
-
LED ON time is 3 clocks.
-
LEF OFF time is 9 clocks.
-
Period tick is 12 clocks / 26.37 us / 37.917 kHz.
-
start burst is 38 pulses. 1002.2 us or ON-ON of 995.6 us.
-
short burst is 7 LED pulses. 184us period, but ON-ON width is 178 us.
-
zero gap is 476 us from start of last to start of next LED pulse. 18 ticks, so gap is 17 ticks.
-
one gap is 950 us from start of last to start of next LED pulse. 36 ticks, gap is 35 ticks.
1.2. Sample decodes
1.3. Encoding scheme
Bits are in time-order. Leftmost bit is the first received from the packet.
iiii iiii iiii iiii iiii iiii xxxx kkkk
(32 bits)
- octets
-
id[2], id[1], id[0], b
- b octet
-
xxxx kkkk
upper 4-bits of last byte have unknown meaning. - keymap
0x0f & key
-
-
0x03 → A
-
0x02 → B
-
0x0f → C
-
0x0b → D
-
0x0e → E
-
0x0a → F or *
-
0x0c → G or <
-
0x08 → H or >
-
2. Morse code library
- Place this file onto your Maker Pi board using Thonny
-
-
Right-click and Save As: morse.py
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import board
import re
import simpleio
import time
PIEZO_PIN = board.GP22
MORSE_PITCH = 700
dot = 0.050 # = 60 / (50 * WPM)
dash = 3*dot
gap = dot
lspace = 3*dot
wspace = 7*dot
MORSE_CHARS = {
"A":(dot, dash),
"B":(dash, dot, dot, dot),
"C":(dash, dot, dash, dot),
"D":(dash, dot, dot),
"E":(dot,),
"F":(dot, dot, dash, dot),
"G":(dash, dash, dot),
"H":(dot, dot, dot, dot),
"I":(dot, dot),
"J":(dot, dash, dash, dash),
"K":(dash, dot, dash),
"L":(dot, dash, dot, dot),
"M":(dash, dash),
"N":(dash, dot),
"O":(dash, dash, dash),
"P":(dot, dash, dash, dot),
"Q":(dash, dash, dot, dash),
"R":(dot, dash, dot),
"S":(dot, dot, dot),
"T":(dash,),
"U":(dot, dot, dash),
"V":(dot, dot, dot, dash),
"W":(dot, dash, dash),
"X":(dash, dot, dot, dash),
"Y":(dash, dot, dash, dash),
"Z":(dash, dash, dot, dot),
"0":(dash, dash, dash, dash, dash),
"1":(dot, dash, dash, dash, dash),
"2":(dot, dot, dash, dash, dash),
"3":(dot, dot, dot, dash, dash),
"4":(dot, dot, dot, dot, dash),
"5":(dot, dot, dot, dot, dot),
"6":(dash, dot, dot, dot, dot),
"7":(dash, dash, dot, dot, dot),
"8":(dash, dash, dash, dot, dot),
"9":(dash, dash, dash, dash, dot),
# https://en.wikipedia.org/wiki/Prosigns_for_Morse_code
"?":(dot, dot, dash, dash, dot, dot), # ? - SAY AGAIN or indicate question/request
"AR":(dot, dash, dot, dash, dot), # AR - OUT - end of message
"AS":(dot, dash, dot, dot, dot), # AS - WAIT - I must pause for a few minutes
"VE":(dot, dot, dot, dash, dot), # VE - VERIFIED - message is verified
"BT":(dash, dot, dot, dot, dash), # BT - BREAK - start new section
"KA":(dash, dot, dash, dot, dash), # KA - ATTENTION - new message
"SK":(dot, dot, dot, dash, dot, dash), # SK - OUT - end of contact
}
def morse_char(c):
if c == " ":
time.sleep(wspace - lspace)
else:
try:
for t in MORSE_CHARS[c]:
simpleio.tone(PIEZO_PIN, MORSE_PITCH, duration=t)
time.sleep(dot)
except KeyError:
# unknown character
simpleio.tone(PIEZO_PIN, MORSE_PITCH/3, duration=dot)
RE_PROSIGN_START = re.compile("<")
RE_PROSIGN_END = re.compile(">")
def morse(string):
first, *rest = RE_PROSIGN_START.split(string, 1)
# rest is a list of length 0 or 1
for c in first.upper():
morse_char(c)
time.sleep(lspace)
# send a prosign
if rest:
prosign, *rest = RE_PROSIGN_END.split(rest[0], 1)
# rest is a list of length 0 or 1
morse_char(prosign.upper())
time.sleep(lspace)
# send what's after the prosign
if rest:
# recursion! seems an appropriate solution to handle an
# arbitrary number of embedded prosigns
morse(rest[0])
3. Infrared remote code
- Place this file onto your Maker Pi board using Thonny
-
-
Right-click and Save As: adafruit_irremote.py
-
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
# SPDX-License-Identifier: MIT
# Circuit Playground Express Demo Code
# Adjust the pulseio 'board.PIN' if using something else
import pulseio
import board
import adafruit_irremote
import digitalio
import time
from time import sleep, monotonic
import board
import pwmio
import digitalio
# This "morse.py" needs to be downloaded to your board
import morse
# button setup
button0 = digitalio.DigitalInOut(board.GP20)
button1 = digitalio.DigitalInOut(board.GP21)
button0.direction = button1.direction = digitalio.Direction.INPUT
pulsein = pulseio.PulseIn(board.GP26, maxlen=120, idle_state=True)
decoder = adafruit_irremote.GenericDecode()
def match_pulse(p, expected, tolerance=50):
for idx, e in enumerate(expected):
err = p - e
#print("match:", idx, p, e, err)
if abs(err) <= tolerance:
return (idx, err)
return (None, None)
def decode_bit(pulses):
sync = 1000
start = 476
burst = 150
mark = 950
space = 476
header = [sync, start, burst]
data = [space, mark]
gap = [burst]
piter = iter(pulses)
for h in header:
p = next(piter)
value, err = match_pulse(p, [h])
#print("header:", value)
while True:
try:
p = next(piter)
bit, err = match_pulse(p, data)
#print("bit:", bit)
p = next(piter)
burst, err = match_pulse(p, gap)
#print("burst:", burst)
yield bit
except StopIteration:
break
def decode(p, n_pulses=67):
if len(p) != n_pulses:
#print(f"Invalid packet: expected {n_pulses}, got {len(p)} pulses")
return None
bits = []
for bit in decode_bit(p):
if bit is not None:
bits.append(bit)
else:
return None
return bits
def bits2bytes(bits, n=4):
values = [0] * n
for idx, bit in enumerate(bits):
byte, i = divmod(idx, 8)
values[byte] += bit << (7-i)
return values
REMOTE_KEY = {
0x03: "A",
0x02: "B",
0x0f: "C",
0x0b: "D",
0x0e: "E",
0x0a: "F",
0x0c: "G",
0x08: "H",
}
def remote_morse():
print("****************************")
print("*** IR remote morse code ***")
print("****************************")
last_key = ""
while (button0.value == 1) or (button1.value == 1):
pulses = decoder.read_pulses(pulsein, blocking=False, pulse_window=0.1)
if pulses is None:
continue
bits = decode(pulses)
if not bits:
print("bad packet:", bits)
continue
#print(len(bits), bits)
values = bits2bytes(bits)
#print(values)
print([hex(v) for v in values])
key = REMOTE_KEY[values[3] & 0x0f]
morse.morse_char(key)
last_key = key
#print("----------------------------")
while True:
remote_morse()
time.sleep(1)