-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathyamahanec2lirc.py
More file actions
279 lines (228 loc) · 8.71 KB
/
yamahanec2lirc.py
File metadata and controls
279 lines (228 loc) · 8.71 KB
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
'''
yamahanec2lirc.py - Converts Yamaha/NEC IR codes into LIRC format.
Copyright by Ian Burns <ian.burns138@gmail.com>
yamahanec2lirc is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Invocation:
python yamahanec2lirc.py <infile> <device> <product> <id_code> > <output_file>
eg python yamahanec2lirc.py yamaha_rxv.csv RECEIVER 767 1 > yamaha_rxv767.lircd
Notes on input file:
CSV format, in similar form to the files in doc/yamaha_rxv
Column 1: Device - The device the code applies to. eg Receiver, Tuner
Column 2: Function Group - This groups the codes into similar functions
Column 3: Function Name - This is the remote code name
Column 4: Zone - The receiver zone that the code applies to
Column 5: ID1 Code - This is the remote code in Yamaha/NEC format. The receiver supports two different code sets, I assume so you could have two receivers and not have the remotes interfere with one another
Column 6: ID2 Code - See column 5
Column 7: Comment - This specifies which products the code will work with. If blank, then will appear in all product lirc remote definitions, otherwise will be filtered by products specified
Column 8: Export Comment - Comments in this column will appear as comments above the code in the lirc remote definition. If prefixed with # then the code itself will be commented out.
The program generates codes for the device specified (ie when device matches the name in device column).
It generates a remote definition for the following:
<Device>_<Product>_ALL - Where the Zone column contains "ALL" or "-", the code will be added to this remote definition
<Device>_<Product>_MAIN - Where the Zone column contains "MAIN", the code will be added to this remote definition
<Device>_<Product>_ZONEx - Where the Zone column matches each zone (ZONE2, ZONE3, etc), the code will be added to this remote definition
eg RECEIVER_767_ALL, RECEIVER_767_MAIN, RECEIVER_767_ZONE2
Remote code names are named like <Function Group>_<Function Name>, eg ZONE_CONTROL_PARTY_OFF
'''
import re
import csv
import sys
def flip_bits(nibble):
rn = 0x00
for i in range(0, 4):
if (nibble & (0x01 << i) != 0):
rn |= (0x08 >> i)
return rn
def swap_n_flip(byte):
hn = (byte & 0xF0) >> 4
ln = (byte & 0x0F)
hn = flip_bits(hn)
ln = flip_bits(ln)
swapped = hn | (ln << 4)
return swapped
def lirc_to_yamahanec_code(lirccode):
"""Convert lirc code to yamaha/nec IR code"""
#( "KEY_VOLUMEUP", 0x5EA158A7, "7A-1A" ),
b1 = (lirccode >> 24) & 0xFF
b2 = (lirccode >> 16) & 0xFF
b3 = (lirccode >> 8) & 0xFF
b4 = (lirccode >> 0) & 0xFF
yncode = ""
if (0xFF - b1 == b2):
yncode += "%02X" % swap_n_flip(b1)
else:
yncode += "%02X%02X" % (swap_n_flip(b1), swap_n_flip(b2))
yncode += "-"
if (0xFF - b3 == b4):
yncode += "%02X" % swap_n_flip(b3)
else:
yncode += "%02X%02X" % (swap_n_flip(b3), swap_n_flip(b4))
return yncode
def yamahanec_code_to_lirc(yncode):
"""Convert yamaha/nec IR code to lirc format"""
# Match "7A-037C" style codes
m = re.match("([0-9a-fA-F]{2})-([0-9a-fA-F]{2})([0-9a-fA-F]{2})", yncode)
if (m is not None and m.group(1) is not None and m.group(2) is not None and m.group(3) is not None):
b1 = int(m.group(1), 16)
b2 = int(m.group(2), 16)
b3 = int(m.group(3), 16)
b1s = swap_n_flip(b1)
b2s = swap_n_flip(b2)
b3s = swap_n_flip(b3)
code = (b1s << 24) | ((0xFF - b1s) << 16) | (b2s << 8) | (b3s << 0)
else:
# Match "7E-6C" style codes
m = re.match("([0-9a-fA-F]{2})-([0-9a-fA-F]{2})", yncode)
if (m is not None and m.group(1) is not None and m.group(2) is not None):
b1 = int(m.group(1), 16)
b2 = int(m.group(2), 16)
b1s = swap_n_flip(b1)
b2s = swap_n_flip(b2)
code = (b1s << 24) | ((0xFF - b1s) << 16) | (b2s << 8) | ((0xFF - b2s) << 0)
else:
# Match "7F01-5B24" style codes
m = re.match("([0-9a-fA-F]{2})([0-9a-fA-F]{2})-([0-9a-fA-F]{2})([0-9a-fA-F]{2})", yncode)
if (m is not None and m.group(1) is not None and m.group(2) is not None and m.group(3) is not None and m.group(4) is not None):
b1 = int(m.group(1), 16)
b2 = int(m.group(2), 16)
b3 = int(m.group(3), 16)
b4 = int(m.group(4), 16)
b1s = swap_n_flip(b1)
b2s = swap_n_flip(b2)
b3s = swap_n_flip(b3)
b4s = swap_n_flip(b4)
code = (b1s << 24) | (b2s << 16) | (b3s << 8) | (b4s << 0)
else:
# Match "7F01-56" style codes
m = re.match("([0-9a-fA-F]{2})([0-9a-fA-F]{2})-([0-9a-fA-F]{2})", yncode)
if (m is not None and m.group(1) is not None and m.group(2) is not None and m.group(3) is not None):
b1 = int(m.group(1), 16)
b2 = int(m.group(2), 16)
b3 = int(m.group(3), 16)
b1s = swap_n_flip(b1)
b2s = swap_n_flip(b2)
b3s = swap_n_flip(b3)
code = (b1s << 24) | (b2s << 16) | (b3s << 8) | ((0xFF - b3s) << 0)
else:
raise Exception("Invalid code format: \"%s\"" % (yncode))
return code
# Key name, expected lirc code, yamaha-nec code
test_codes = [
("KEY_BDDVD", 0x5EA100FE, "7A-007F"),
("KEY_TV", 0x5EA1C03E, "7A-037C"),
("KEY_CD", 0x5EA1609E, "7A-0679"),
("KEY_RADIO", 0x5EA1906E, "7A-0976"),
("KEY_6", 0xFE806A95, "7F01-56"),
("KEY_7", 0xFE80EA15, "7F01-57"),
("KEY_8", 0xFE801AE5, "7F01-58"),
("KEY_9", 0xFE809A65, "7F01-59"),
("KEY_VOLUMEUP", 0x5EA158A7, "7A-1A"),
("KEY_VOLUMEDOWN", 0x5EA1D827, "7A-1B"),
("KEY_MUTE", 0x5EA138C7, "7A-1C"),
("KEY_FM", 0xFE801AE4, "7F01-5827"),
("KEY_AM", 0xFE80AA54, "7F01-552A"),
("KEY_PRESETUP", 0xFE80DA24, "7F01-5B24"),
("KEY_PRESETDOWN", 0xFE807A84, "7F01-5E21")
]
def test():
"""Check that the conversions match what is expected"""
for test in test_codes:
code = yamahanec_code_to_lirc(test[2])
if (code != test[1]):
raise Exception("Error converting y->l %s" % (test[0]))
code = lirc_to_yamahanec_code(test[1])
if (code != test[2]):
raise Exception("Error converting %s l->y" % (test[0]))
test()
# Command line
if (len(sys.argv) != 5):
raise Exception(
"Invalid number of command line arguments.\nCheck the top of the file for instructions.")
infile = sys.argv[1]
device = sys.argv[2]
product = sys.argv[3]
id_code = int(sys.argv[4])
COL_DEVICE = 0
COL_FNGRP = 1
COL_FNNAME = 2
COL_ZONE = 3
COL_ID1 = 4
COL_ID2 = 5
COL_PRODUCT = 6
COL_EXPORTCOMMENT = 7
def parse_file(zone):
csvfile = open(infile, 'rb')
csvreader = csv.reader(csvfile, delimiter=',', quotechar='\"')
for row in csvreader:
if (row[COL_DEVICE] == device and
(row[COL_ZONE] == zone or (zone == "ALL" and row[COL_ZONE] == "-")) and
(row[COL_PRODUCT] == "" or row[COL_PRODUCT].find(product) >= 0)):
if (id_code == 1):
yncode = row[COL_ID1]
else:
yncode = row[COL_ID2]
try:
lirc_code = yamahanec_code_to_lirc(yncode)
except:
print "Failed at %s_%s for zone %s" % (row[COL_FNGRP], row[COL_FNNAME], zone)
raise
key_name = "%s_%s" % (row[COL_FNGRP], row[COL_FNNAME])
# Print comment row
if (row[COL_EXPORTCOMMENT] != ""):
s = row[COL_EXPORTCOMMENT]
if (s.startswith("#")):
s = s[1:]
print "# %s" % (s)
# If export comment row starts with # then comment out the IR code
if (row[COL_EXPORTCOMMENT].startswith("#")):
comment_out = "#"
else:
comment_out = ""
print "%s %s 0x%08X" % (comment_out, key_name.ljust(30), lirc_code)
csvfile.close()
header = "\
begin remote\n\
\n\
name %s\n\
bits 32\n\
flags SPACE_ENC|CONST_LENGTH\n\
eps 30\n\
aeps 100\n\
\n\
header 8980 4448\n\
one 598 1645\n\
zero 598 524\n\
ptrail 594\n\
repeat 8964 2224\n\
gap 107495\n\
toggle_bit_mask 0x0\n\
\n\
begin codes\n\
"
footer = "\
end codes\n\
\n\
end remote\n\
"
zones = ["ALL", "MAIN", "ZONE2"]
for zone in zones:
remote_name = "%s_%s_%s" % (device, product, zone)
print header % (remote_name)
parse_file(zone)
print footer
# Reverse lookup - lirc to yamaha/nec
#print "z2 KEY_PLUS10: %s" % lirc_to_yamahanec_code(0xFE80DE21)
#print "m KEY_PLUS10: %s" % lirc_to_yamahanec_code(0xFE80DA25)
#print "Self test1: %s" % lirc_to_yamahanec_code(0x5ea1FB04)
#print "Self test2: %s" % lirc_to_yamahanec_code(0x5ea1FB84)
#print "Zone2 on: %s" % lirc_to_yamahanec_code(0x7e815da2)
#print "Main on: %s" % lirc_to_yamahanec_code(0x7e817e81)