]> sigrok.org Git - sigrok-util.git/blame - source/new-driver
new-driver: Update to match recent drivers API changes.
[sigrok-util.git] / source / new-driver
CommitLineData
a65d66c0 1#!/usr/bin/python3
0af91589
UH
2##
3## This file is part of the sigrok-util project.
4##
5## Copyright (C) 2012 Bert Vermeulen <bert@biot.com>
6##
7## This program is free software: you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published by
9## the Free Software Foundation, either version 3 of the License, or
10## (at your option) any later version.
11##
12## This program is distributed in the hope that it will be useful,
13## but WITHOUT ANY WARRANTY; without even the implied warranty of
14## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15## GNU General Public License for more details.
16##
17## You should have received a copy of the GNU General Public License
18## along with this program. If not, see <http://www.gnu.org/licenses/>.
19##
a65d66c0
BV
20
21import os
22import sys
23import tempfile
24from subprocess import Popen, PIPE
25import shutil
26import re
27import socket
28import datetime
29
3e61a9d8 30TMPL_AUTOCONF_DRIVER = "DRIVER([${name}], [${short}])\n"
d0d6e169 31TMPL_AUTOCONF_DRIVER2 = "DRIVER2([HW_${upper}], [$HW_${upper}], [HAVE_HW_${upper}])\n"
7d787983 32
d51b5323 33TMPL_HWMAKE_DRIVERLIB = """if HW_${upper}
68ec5073 34libsigrok_la_SOURCES += \\
6ebf3016
BV
35 src/hardware/${short}/protocol.h \\
36 src/hardware/${short}/protocol.c \\
37 src/hardware/${short}/api.c
d51b5323 38endif
d51b5323 39"""
3e61a9d8 40TMPL_DRIVERS_EXTERN = """\
d51b5323
BV
41#ifdef HAVE_HW_${upper}
42extern SR_PRIV struct sr_dev_driver ${lib}_driver_info;
43#endif
44"""
3e61a9d8 45TMPL_DRIVERS_POINTER = """\
d51b5323 46#ifdef HAVE_HW_${upper}
87604b0c 47 (DRVS) {&${lib}_driver_info, NULL},
d51b5323
BV
48#endif
49"""
a65d66c0
BV
50FILE_DRV_API = 'drv-api.c'
51FILE_DRV_PROTOCOL = 'drv-protocol.c'
52FILE_DRV_PROTOCOL_H = 'drv-protocol.h'
53
54def tmpl(template):
55 out = re.sub(r'\${([^}]+)}', lambda x: str(names[x.group(1)]), template)
56
57 return out
58
59
60def tmpl_file(filename):
61 template = open(TMPLDIR + '/' + filename).read()
62
63 return tmpl(template)
64
65
66def new_driver():
67 tmp = tempfile.mkdtemp()
68 try:
69 os.chdir(tmp)
1684b33d 70 process = Popen("git clone --depth=1 " + LIBSR, shell=True, stderr=PIPE)
617f4da0
AJ
71 out, err = process.communicate()
72 if process.returncode:
a65d66c0
BV
73 raise Exception(err.decode())
74 gitdir = tmp + '/libsigrok/'
3e61a9d8
BV
75 do_autoconf(gitdir)
76 do_drivers(gitdir)
77 do_automake(gitdir)
a65d66c0
BV
78 do_driverskel(gitdir)
79 make_patch(gitdir)
80 except Exception as e:
81 print(e)
82 shutil.rmtree(tmp)
83
84
d0d6e169 85# add DRIVER and DRIVER2 entries to configure.ac
3e61a9d8 86def do_autoconf(gitdir):
a65d66c0
BV
87 cacpath = gitdir + 'configure.ac'
88 configure_ac = open(cacpath).read()
89
a65d66c0 90 out = ''
3e61a9d8
BV
91 state = 'driver'
92 active = False
a65d66c0 93 for line in configure_ac.split('\n')[:-1]:
3e61a9d8
BV
94 if state == 'driver':
95 m = re.match('DRIVER\(\[([^\]]+)', line)
a65d66c0 96 if m:
3e61a9d8
BV
97 active = True
98 if active:
99 if (m and m.group(1).upper() > names['name'].upper()) or m is None:
100 out += tmpl(TMPL_AUTOCONF_DRIVER)
101 state = 'automake'
102 active = False
103 elif state == 'automake':
d0d6e169 104 m = re.match('DRIVER2\(\[([^\]]+)', line)
a65d66c0 105 if m:
3e61a9d8 106 active = True
a65d66c0 107 else:
d0d6e169 108 submatch = re.match('DRIVER2\(\[([^\]]+)', line)
3e61a9d8 109 if active and submatch is None:
d0d6e169
UH
110 # we're past the DRIVER2 list
111 out += tmpl(TMPL_AUTOCONF_DRIVER2)
3e61a9d8
BV
112 state = 'done'
113 if active:
d0d6e169
UH
114 if (m and m.group(1) > 'HW_' + names['upper']):
115 out += tmpl(TMPL_AUTOCONF_DRIVER2)
3e61a9d8 116 state = 'done'
a65d66c0
BV
117 out += line + '\n'
118 if state != 'done':
3e61a9d8
BV
119 raise Exception('No DRIVER entries found in configure.ac')
120 open(cacpath, 'w').write(out)
a65d66c0 121
a65d66c0 122
3e61a9d8
BV
123# add HAVE_HW_ extern and pointers to drivers.c
124def do_drivers(gitdir):
6ebf3016 125 path = gitdir + 'src/drivers.c'
3e61a9d8 126 source = open(path).read()
d51b5323 127 out = ''
3e61a9d8
BV
128 state = 'extern'
129 first_entry = ''
130 for line in source.split('\n')[:-1]:
131 m = re.match('#ifdef HAVE_HW_(.*)', line)
132 if m:
133 if not first_entry:
134 first_entry = m.group(1)
135 elif m.group(1) == first_entry:
136 # second time we see this, so we're past the externs
137 if state != 'idle':
138 # tack driver on to the end of the list
139 out += tmpl(TMPL_DRIVERS_EXTERN)
140 state = 'pointer'
d51b5323 141 if state == 'extern':
3e61a9d8
BV
142 if m.group(1) > names['upper']:
143 out += tmpl(TMPL_DRIVERS_EXTERN)
144 state = 'idle'
145 elif state == 'pointer':
146 if m.group(1) > names['upper']:
147 out += tmpl(TMPL_DRIVERS_POINTER)
148 state = 'done'
149 elif state == 'pointer' and not re.match('(\s*&|#endif|$)', line):
150 # we passed the last entry
151 out += tmpl(TMPL_DRIVERS_POINTER)
152 state = 'done'
d51b5323
BV
153 out += line + '\n'
154 if state != 'done':
3e61a9d8
BV
155 raise Exception('No "HAVE_HW_*" markers found in drivers.c' + state)
156 open(path, 'w').write(out)
d51b5323
BV
157
158
3e61a9d8
BV
159# add HW_ entry to Makefile.am
160def do_automake(gitdir):
7d787983 161 path = gitdir + 'Makefile.am'
a65d66c0
BV
162 hwmake = open(path).read()
163
a65d66c0
BV
164 out = ''
165 state = 'copy'
166 for line in hwmake.split('\n')[:-1]:
3e61a9d8
BV
167 if state == 'copy' and re.match('if HW_(.*)$', line):
168 state = 'drivers'
169 if state == 'drivers':
170 m = re.match('if HW_(.*)$', line)
d51b5323
BV
171 if m:
172 drv_short = m.group(1)
173 if drv_short > names['upper']:
174 out += tmpl(TMPL_HWMAKE_DRIVERLIB)
175 state = 'done'
6ebf3016 176 elif not re.match('(libsigrok_la_SOURCES|\s*src/hardware/|endif)', line):
3e61a9d8
BV
177 print("[%s]" % line.strip())
178 # we passed the last entry
179 out += tmpl(TMPL_HWMAKE_DRIVERLIB)
180 state = 'done'
a65d66c0 181 out += line + '\n'
7d787983 182 if state != 'done':
3e61a9d8
BV
183 raise Exception('No "if HW_" markers found in Makefile.am')
184 open(path, 'w').write(out)
a65d66c0
BV
185
186
187def do_driverskel(gitdir):
6ebf3016 188 drvdir = gitdir + 'src/hardware/' + names['short']
a65d66c0 189 os.mkdir(drvdir)
a65d66c0
BV
190 open(drvdir + '/api.c', 'w').write(tmpl_file(FILE_DRV_API))
191 open(drvdir + '/protocol.c', 'w').write(tmpl_file(FILE_DRV_PROTOCOL))
192 open(drvdir + '/protocol.h', 'w').write(tmpl_file(FILE_DRV_PROTOCOL_H))
193
194
195def make_patch(gitdir):
196 os.chdir(gitdir)
6ebf3016 197 command('git add src/hardware/' + names['short'])
0af91589 198 cmd = 'git commit -m "%s: Initial driver skeleton." ' % names['short']
6ebf3016 199 cmd += 'configure.ac Makefile.am src/drivers.c src/hardware/' + names['short']
a65d66c0
BV
200 command(cmd)
201 cmd = "git format-patch HEAD~1"
202 out, err = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE).communicate()
203 if err:
204 raise Exception(err.decode())
205 patch = out.decode().strip()
206 shutil.move(gitdir + '/' + patch, scriptdir + '/' + patch)
207 print(patch)
208
209
210def command(cmd):
211 out, err = Popen(cmd, shell=True, stderr=PIPE).communicate()
212 if err:
213 raise Exception(err.decode())
214
215
216def parse_gitconfig():
0af91589
UH
217 try:
218 author = email = None
219 for line in open(os.environ['HOME'] + '/.gitconfig').readlines():
220 m = re.match('\s*(\w+)\s*=\s*(.*)\s*$', line)
221 if m:
222 key, value = m.groups()
223 if key == 'name':
224 author = value
225 elif key == 'email':
226 email = value
227 if author and email:
228 break
229 except:
230 pass
231 if not author or not email:
232 print("Please put your name and email in ~/.gitconfig")
233 sys.exit()
234
235 return author, email
a65d66c0
BV
236
237#
238# main
239#
240
241scriptdir = os.getcwd()
87c5b243
BV
242if scriptdir.split('/')[-2:] != ['sigrok-util', 'source']:
243 print("Please call this script from the 'source' directory.")
244 sys.exit(1)
245
246LIBSR = 'git://sigrok.org/libsigrok'
247TMPLDIR = scriptdir
a65d66c0
BV
248
249if len(sys.argv) < 2:
0af91589 250 print("Usage: new-driver <name>")
a65d66c0
BV
251 sys.exit()
252
253author, email = parse_gitconfig()
254name = ' '.join(sys.argv[1:])
255names = {
256 'name': name,
257 'short': re.sub('[^a-z0-9]', '-', name.lower()),
258 'lib': re.sub('[^a-z0-9]', '_', name.lower()),
259 'upper': re.sub('[^A-Z0-9]', '_', name.upper()),
260 'libupper': re.sub('[^A-Z0-9]', '', name.upper()),
0af91589
UH
261 'year': datetime.datetime.now().year,
262 'author': author,
263 'email': email,
a65d66c0
BV
264}
265new_driver()
266