-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathirdecode.py
executable file
·157 lines (119 loc) · 4.1 KB
/
irdecode.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
147
148
149
150
151
152
153
154
155
156
157
#!/usr/bin/env python
#
# Decode the pulse/space output of `mode2` into bits and bytes
#
# Usage:
# mode2 -d /dev/lirc0 | irdecode.py
# timings are currently somewhat hardcoded here.
from __future__ import print_function
import logging
import select
import sys
# the min and max dirations of the pulse and space parts of the header
MIN_HEADER_PULSE_WIDTH=4400
MAX_HEADER_PULSE_WIDTH=4800
MIN_HEADER_SPACE_WIDTH=MIN_HEADER_PULSE_WIDTH
MAX_HEADER_SPACE_WIDTH=MAX_HEADER_PULSE_WIDTH
# the min and max durations of the pulse part of a one, zero, or trailer
MIN_PULSE_WIDTH=400
MAX_PULSE_WIDTH=750
# the min and max durations of the space part of a zero
MIN_ZERO_SPACE_WIDTH=350
MAX_ZERO_SPACE_WIDTH=750
# the min and max durations of the space part of a one
MIN_ONE_SPACE_WIDTH=1500
MAX_ONE_SPACE_WIDTH=1820
def read(f):
pulse_width = None
logger = logging.getLogger("reader")
pulseDecoder = PulseDecoder()
while True:
r, w, e = select.select([f], [], [f], 0.1)
if f in e:
return
if f not in r:
# timeout
if pulse_width:
pulseDecoder.pulse(pulse_width, None)
pulse_width = None
continue
line = f.readline().strip()
if line is None:
return
try:
(t, d) = line.split(" ", 1)
d = int(d)
except:
logger.warn("Cannot parse %s", line)
continue
if t == "pulse":
pulse_width = d
space_width = 0
continue
if t != "space":
logger.error("Cannot parse %s (%s)", line, t)
continue
space_width = d
if pulse_width is None:
logger.info("gap %s us", space_width)
continue
pulseDecoder.pulse(pulse_width, space_width)
pulse_width = None
class PulseDecoder:
def __init__(self):
self.logger = logging.getLogger("PulseDecoder")
self.bitDecoder = BitDecoder()
def pulse(self, pulse_width, space_width):
if (pulse_width > MIN_PULSE_WIDTH and
pulse_width < MAX_PULSE_WIDTH and
(space_width is None or space_width > 10000)):
self.logger.info("gap %s us", space_width)
self.bitDecoder.gap()
return
if (pulse_width > MIN_HEADER_PULSE_WIDTH and
pulse_width < MAX_HEADER_PULSE_WIDTH and
space_width > MIN_HEADER_SPACE_WIDTH and
space_width < MAX_HEADER_SPACE_WIDTH):
self.logger.debug("header")
return
if (pulse_width > MIN_PULSE_WIDTH and
pulse_width < MAX_PULSE_WIDTH and
space_width > MIN_ONE_SPACE_WIDTH and
space_width < MAX_ONE_SPACE_WIDTH):
self.logger.debug("one")
self.bitDecoder.bit(1)
return
if (pulse_width > MIN_PULSE_WIDTH and
pulse_width < MAX_PULSE_WIDTH and
space_width > MIN_ZERO_SPACE_WIDTH and
space_width < MAX_ZERO_SPACE_WIDTH):
self.logger.debug("zero")
self.bitDecoder.bit(0)
return
self.logger.warn("Unknown %d %d", pulse_width, space_width)
class BitDecoder:
def __init__(self):
self._reset()
self.logger = logging.getLogger("bitdecoder")
self.byte_buffer = ""
def _reset(self):
self.bit_count = 0
self.bit_buffer = 0
def bit(self, val):
self.bit_buffer = (self.bit_buffer << 1) | (val & 0x1)
self.bit_count += 1
if self.bit_count >= 8:
self.logger.debug("Byte: %02x", self.bit_buffer)
self.byte_buffer += "%02x" % self.bit_buffer
self._reset()
def gap(self):
if self.bit_count != 0:
self.logger.warn("Discarding %i bits", self.bit_count)
self.logger.info("Read: %s" % self.byte_buffer)
self._reset()
self.byte_buffer=""
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
#logging.getLogger("reader").setLevel(logging.WARN)
#logging.getLogger("PulseDecoder").setLevel(logging.DEBUG)
read(sys.stdin)