1#!/usr/bin/env python3 2# SPDX-License-Identifier: GPL-2.0+ 3# vim: ts=2:sw=2:et:tw=80:nowrap 4 5# This is simply to aide in creating the entries in the order of the value of 6# the device-global NI signal/terminal constants defined in comedi.h 7import comedi_h 8import os, sys, re 9from csv_collection import CSVCollection 10 11 12def c_to_o(filename, prefix='\t\t\t\t\t ni_routing/', suffix=' \\'): 13 if not filename.endswith('.c'): 14 return '' 15 return prefix + filename.rpartition('.c')[0] + '.o' + suffix 16 17 18def routedict_to_structinit_single(name, D, return_name=False): 19 Locals = dict() 20 lines = [ 21 '\t.family = "{}",'.format(name), 22 '\t.register_values = {', 23 '\t\t/*', 24 '\t\t * destination = {', 25 '\t\t * source = register value,', 26 '\t\t * ...', 27 '\t\t * }', 28 '\t\t */', 29 ] 30 if (False): 31 # print table with index0:src, index1:dest 32 D0 = D # (src-> dest->reg_value) 33 #D1 : destD 34 else: 35 D0 = dict() 36 for src, destD in D.items(): 37 for dest, val in destD.items(): 38 D0.setdefault(dest, {})[src] = val 39 40 41 D0 = sorted(D0.items(), key=lambda i: eval(i[0], comedi_h.__dict__, Locals)) 42 43 for D0_sig, D1_D in D0: 44 D1 = sorted(D1_D.items(), key=lambda i: eval(i[0], comedi_h.__dict__, Locals)) 45 46 lines.append('\t\t[B({})] = {{'.format(D0_sig)) 47 for D1_sig, value in D1: 48 if not re.match('[VIU]\([^)]*\)', value): 49 sys.stderr.write('Invalid register format: {}\n'.format(repr(value))) 50 sys.stderr.write( 51 'Register values should be formatted with V(),I(),or U()\n') 52 raise RuntimeError('Invalid register values format') 53 lines.append('\t\t\t[B({})]\t= {},'.format(D1_sig, value)) 54 lines.append('\t\t},') 55 lines.append('\t},') 56 57 lines = '\n'.join(lines) 58 if return_name: 59 return N, lines 60 else: 61 return lines 62 63 64def routedict_to_routelist_single(name, D, indent=1): 65 Locals = dict() 66 67 indents = dict( 68 I0 = '\t'*(indent), 69 I1 = '\t'*(indent+1), 70 I2 = '\t'*(indent+2), 71 I3 = '\t'*(indent+3), 72 I4 = '\t'*(indent+4), 73 ) 74 75 if (False): 76 # data is src -> dest-list 77 D0 = D 78 keyname = 'src' 79 valname = 'dest' 80 else: 81 # data is dest -> src-list 82 keyname = 'dest' 83 valname = 'src' 84 D0 = dict() 85 for src, destD in D.items(): 86 for dest, val in destD.items(): 87 D0.setdefault(dest, {})[src] = val 88 89 # Sort by order of device-global names (numerically) 90 D0 = sorted(D0.items(), key=lambda i: eval(i[0], comedi_h.__dict__, Locals)) 91 92 lines = [ '{I0}.device = "{name}",\n' 93 '{I0}.routes = (struct ni_route_set[]){{' 94 .format(name=name, **indents) ] 95 for D0_sig, D1_D in D0: 96 D1 = [ k for k,v in D1_D.items() if v ] 97 D1.sort(key=lambda i: eval(i, comedi_h.__dict__, Locals)) 98 99 lines.append('{I1}{{\n{I2}.{keyname} = {D0_sig},\n' 100 '{I2}.{valname} = (int[]){{' 101 .format(keyname=keyname, valname=valname, D0_sig=D0_sig, **indents) 102 ) 103 for D1_sig in D1: 104 lines.append( '{I3}{D1_sig},'.format(D1_sig=D1_sig, **indents) ) 105 lines.append( '{I3}0, /* Termination */'.format(**indents) ) 106 107 lines.append('{I2}}}\n{I1}}},'.format(**indents)) 108 109 lines.append('{I1}{{ /* Termination of list */\n{I2}.{keyname} = 0,\n{I1}}},' 110 .format(keyname=keyname, **indents)) 111 112 lines.append('{I0}}},'.format(**indents)) 113 114 return '\n'.join(lines) 115 116 117class DeviceRoutes(CSVCollection): 118 MKFILE_SEGMENTS = 'device-route.mk' 119 SET_C = 'ni_device_routes.c' 120 ITEMS_DIR = 'ni_device_routes' 121 EXTERN_H = 'all.h' 122 OUTPUT_DIR = 'c' 123 124 output_file_top = """\ 125// SPDX-License-Identifier: GPL-2.0+ 126/* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 127/* 128 * comedi/drivers/ni_routing/{filename} 129 * List of valid routes for specific NI boards. 130 * 131 * COMEDI - Linux Control and Measurement Device Interface 132 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 133 * 134 * This program is free software; you can redistribute it and/or modify 135 * it under the terms of the GNU General Public License as published by 136 * the Free Software Foundation; either version 2 of the License, or 137 * (at your option) any later version. 138 * 139 * This program is distributed in the hope that it will be useful, 140 * but WITHOUT ANY WARRANTY; without even the implied warranty of 141 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 142 * GNU General Public License for more details. 143 */ 144 145/* 146 * The contents of this file are generated using the tools in 147 * comedi/drivers/ni_routing/tools 148 * 149 * Please use those tools to help maintain the contents of this file. 150 */ 151 152#include "ni_device_routes.h" 153#include "{extern_h}"\ 154""".format(filename=SET_C, extern_h=os.path.join(ITEMS_DIR, EXTERN_H)) 155 156 extern_header = """\ 157/* SPDX-License-Identifier: GPL-2.0+ */ 158/* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 159/* 160 * comedi/drivers/ni_routing/{filename} 161 * List of valid routes for specific NI boards. 162 * 163 * COMEDI - Linux Control and Measurement Device Interface 164 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 165 * 166 * This program is free software; you can redistribute it and/or modify 167 * it under the terms of the GNU General Public License as published by 168 * the Free Software Foundation; either version 2 of the License, or 169 * (at your option) any later version. 170 * 171 * This program is distributed in the hope that it will be useful, 172 * but WITHOUT ANY WARRANTY; without even the implied warranty of 173 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 174 * GNU General Public License for more details. 175 */ 176 177/* 178 * The contents of this file are generated using the tools in 179 * comedi/drivers/ni_routing/tools 180 * 181 * Please use those tools to help maintain the contents of this file. 182 */ 183 184#ifndef _COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H 185#define _COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H 186 187#include "../ni_device_routes.h" 188 189{externs} 190 191#endif //_COMEDI_DRIVERS_NI_ROUTING_NI_DEVICE_ROUTES_EXTERN_H 192""" 193 194 single_output_file_top = """\ 195// SPDX-License-Identifier: GPL-2.0+ 196/* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 197/* 198 * comedi/drivers/ni_routing/{filename} 199 * List of valid routes for specific NI boards. 200 * 201 * COMEDI - Linux Control and Measurement Device Interface 202 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 203 * 204 * This program is free software; you can redistribute it and/or modify 205 * it under the terms of the GNU General Public License as published by 206 * the Free Software Foundation; either version 2 of the License, or 207 * (at your option) any later version. 208 * 209 * This program is distributed in the hope that it will be useful, 210 * but WITHOUT ANY WARRANTY; without even the implied warranty of 211 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 212 * GNU General Public License for more details. 213 */ 214 215/* 216 * The contents of this file are generated using the tools in 217 * comedi/drivers/ni_routing/tools 218 * 219 * Please use those tools to help maintain the contents of this file. 220 */ 221 222#include "../ni_device_routes.h" 223#include "{extern_h}" 224 225struct ni_device_routes {table_name} = {{\ 226""" 227 228 def __init__(self, pattern='csv/device_routes/*.csv'): 229 super(DeviceRoutes,self).__init__(pattern) 230 231 def to_listinit(self): 232 chunks = [ self.output_file_top, 233 '', 234 'struct ni_device_routes *const ni_device_routes_list[] = {' 235 ] 236 # put the sheets in lexical order of device numbers then bus 237 sheets = sorted(self.items(), key=lambda i : tuple(i[0].split('-')[::-1]) ) 238 239 externs = [] 240 objs = [c_to_o(self.SET_C)] 241 242 for sheet,D in sheets: 243 S = sheet.lower() 244 dev_table_name = 'ni_{}_device_routes'.format(S.replace('-','_')) 245 sheet_filename = os.path.join(self.ITEMS_DIR,'{}.c'.format(S)) 246 externs.append('extern struct ni_device_routes {};'.format(dev_table_name)) 247 248 chunks.append('\t&{},'.format(dev_table_name)) 249 250 s_chunks = [ 251 self.single_output_file_top.format( 252 filename = sheet_filename, 253 table_name = dev_table_name, 254 extern_h = self.EXTERN_H, 255 ), 256 routedict_to_routelist_single(S, D), 257 '};', 258 ] 259 260 objs.append(c_to_o(sheet_filename)) 261 262 with open(os.path.join(self.OUTPUT_DIR, sheet_filename), 'w') as f: 263 f.write('\n'.join(s_chunks)) 264 f.write('\n') 265 266 with open(os.path.join(self.OUTPUT_DIR, self.MKFILE_SEGMENTS), 'w') as f: 267 f.write('# This is the segment that should be included in comedi/drivers/Makefile\n') 268 f.write('ni_routing-objs\t\t\t\t+= \\\n') 269 f.write('\n'.join(objs)) 270 f.write('\n') 271 272 EXTERN_H = os.path.join(self.ITEMS_DIR, self.EXTERN_H) 273 with open(os.path.join(self.OUTPUT_DIR, EXTERN_H), 'w') as f: 274 f.write(self.extern_header.format( 275 filename=EXTERN_H, externs='\n'.join(externs))) 276 277 chunks.append('\tNULL,') # terminate list 278 chunks.append('};') 279 return '\n'.join(chunks) 280 281 def save(self): 282 filename=os.path.join(self.OUTPUT_DIR, self.SET_C) 283 284 try: 285 os.makedirs(os.path.join(self.OUTPUT_DIR, self.ITEMS_DIR)) 286 except: 287 pass 288 with open(filename,'w') as f: 289 f.write( self.to_listinit() ) 290 f.write( '\n' ) 291 292 293class RouteValues(CSVCollection): 294 MKFILE_SEGMENTS = 'route-values.mk' 295 SET_C = 'ni_route_values.c' 296 ITEMS_DIR = 'ni_route_values' 297 EXTERN_H = 'all.h' 298 OUTPUT_DIR = 'c' 299 300 output_file_top = """\ 301// SPDX-License-Identifier: GPL-2.0+ 302/* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 303/* 304 * comedi/drivers/ni_routing/{filename} 305 * Route information for NI boards. 306 * 307 * COMEDI - Linux Control and Measurement Device Interface 308 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 309 * 310 * This program is free software; you can redistribute it and/or modify 311 * it under the terms of the GNU General Public License as published by 312 * the Free Software Foundation; either version 2 of the License, or 313 * (at your option) any later version. 314 * 315 * This program is distributed in the hope that it will be useful, 316 * but WITHOUT ANY WARRANTY; without even the implied warranty of 317 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 318 * GNU General Public License for more details. 319 */ 320 321/* 322 * This file includes the tables that are a list of all the values of various 323 * signals routes available on NI hardware. In many cases, one does not 324 * explicitly make these routes, rather one might indicate that something is 325 * used as the source of one particular trigger or another (using 326 * *_src=TRIG_EXT). 327 * 328 * The contents of this file are generated using the tools in 329 * comedi/drivers/ni_routing/tools 330 * 331 * Please use those tools to help maintain the contents of this file. 332 */ 333 334#include "ni_route_values.h" 335#include "{extern_h}"\ 336""".format(filename=SET_C, extern_h=os.path.join(ITEMS_DIR, EXTERN_H)) 337 338 extern_header = """\ 339/* SPDX-License-Identifier: GPL-2.0+ */ 340/* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 341/* 342 * comedi/drivers/ni_routing/{filename} 343 * List of valid routes for specific NI boards. 344 * 345 * COMEDI - Linux Control and Measurement Device Interface 346 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 347 * 348 * This program is free software; you can redistribute it and/or modify 349 * it under the terms of the GNU General Public License as published by 350 * the Free Software Foundation; either version 2 of the License, or 351 * (at your option) any later version. 352 * 353 * This program is distributed in the hope that it will be useful, 354 * but WITHOUT ANY WARRANTY; without even the implied warranty of 355 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 356 * GNU General Public License for more details. 357 */ 358 359/* 360 * The contents of this file are generated using the tools in 361 * comedi/drivers/ni_routing/tools 362 * 363 * Please use those tools to help maintain the contents of this file. 364 */ 365 366#ifndef _COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H 367#define _COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H 368 369#include "../ni_route_values.h" 370 371{externs} 372 373#endif //_COMEDI_DRIVERS_NI_ROUTING_NI_ROUTE_VALUES_EXTERN_H 374""" 375 376 single_output_file_top = """\ 377// SPDX-License-Identifier: GPL-2.0+ 378/* vim: set ts=8 sw=8 noet tw=80 nowrap: */ 379/* 380 * comedi/drivers/ni_routing/{filename} 381 * Route information for {sheet} boards. 382 * 383 * COMEDI - Linux Control and Measurement Device Interface 384 * Copyright (C) 2016 Spencer E. Olson <olsonse@umich.edu> 385 * 386 * This program is free software; you can redistribute it and/or modify 387 * it under the terms of the GNU General Public License as published by 388 * the Free Software Foundation; either version 2 of the License, or 389 * (at your option) any later version. 390 * 391 * This program is distributed in the hope that it will be useful, 392 * but WITHOUT ANY WARRANTY; without even the implied warranty of 393 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 394 * GNU General Public License for more details. 395 */ 396 397/* 398 * This file includes a list of all the values of various signals routes 399 * available on NI 660x hardware. In many cases, one does not explicitly make 400 * these routes, rather one might indicate that something is used as the source 401 * of one particular trigger or another (using *_src=TRIG_EXT). 402 * 403 * The contents of this file can be generated using the tools in 404 * comedi/drivers/ni_routing/tools. This file also contains specific notes to 405 * this family of devices. 406 * 407 * Please use those tools to help maintain the contents of this file, but be 408 * mindful to not lose the notes already made in this file, since these notes 409 * are critical to a complete undertsanding of the register values of this 410 * family. 411 */ 412 413#include "../ni_route_values.h" 414#include "{extern_h}" 415 416const struct family_route_values {table_name} = {{\ 417""" 418 419 def __init__(self, pattern='csv/route_values/*.csv'): 420 super(RouteValues,self).__init__(pattern) 421 422 def to_structinit(self): 423 chunks = [ self.output_file_top, 424 '', 425 'const struct family_route_values *const ni_all_route_values[] = {' 426 ] 427 # put the sheets in lexical order for consistency 428 sheets = sorted(self.items(), key=lambda i : i[0] ) 429 430 externs = [] 431 objs = [c_to_o(self.SET_C)] 432 433 for sheet,D in sheets: 434 S = sheet.lower() 435 fam_table_name = '{}_route_values'.format(S.replace('-','_')) 436 sheet_filename = os.path.join(self.ITEMS_DIR,'{}.c'.format(S)) 437 externs.append('extern const struct family_route_values {};'.format(fam_table_name)) 438 439 chunks.append('\t&{},'.format(fam_table_name)) 440 441 s_chunks = [ 442 self.single_output_file_top.format( 443 filename = sheet_filename, 444 sheet = sheet.upper(), 445 table_name = fam_table_name, 446 extern_h = self.EXTERN_H, 447 ), 448 routedict_to_structinit_single(S, D), 449 '};', 450 ] 451 452 objs.append(c_to_o(sheet_filename)) 453 454 with open(os.path.join(self.OUTPUT_DIR, sheet_filename), 'w') as f: 455 f.write('\n'.join(s_chunks)) 456 f.write( '\n' ) 457 458 with open(os.path.join(self.OUTPUT_DIR, self.MKFILE_SEGMENTS), 'w') as f: 459 f.write('# This is the segment that should be included in comedi/drivers/Makefile\n') 460 f.write('ni_routing-objs\t\t\t\t+= \\\n') 461 f.write('\n'.join(objs)) 462 f.write('\n') 463 464 EXTERN_H = os.path.join(self.ITEMS_DIR, self.EXTERN_H) 465 with open(os.path.join(self.OUTPUT_DIR, EXTERN_H), 'w') as f: 466 f.write(self.extern_header.format( 467 filename=EXTERN_H, externs='\n'.join(externs))) 468 469 chunks.append('\tNULL,') # terminate list 470 chunks.append('};') 471 return '\n'.join(chunks) 472 473 def save(self): 474 filename=os.path.join(self.OUTPUT_DIR, self.SET_C) 475 476 try: 477 os.makedirs(os.path.join(self.OUTPUT_DIR, self.ITEMS_DIR)) 478 except: 479 pass 480 with open(filename,'w') as f: 481 f.write( self.to_structinit() ) 482 f.write( '\n' ) 483 484 485 486if __name__ == '__main__': 487 import argparse 488 parser = argparse.ArgumentParser() 489 parser.add_argument( '--route_values', action='store_true', 490 help='Extract route values from csv/route_values/*.csv' ) 491 parser.add_argument( '--device_routes', action='store_true', 492 help='Extract route values from csv/device_routes/*.csv' ) 493 args = parser.parse_args() 494 KL = list() 495 if args.route_values: 496 KL.append( RouteValues ) 497 if args.device_routes: 498 KL.append( DeviceRoutes ) 499 if not KL: 500 parser.error('nothing to do...') 501 for K in KL: 502 doc = K() 503 doc.save() 504