mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2026-05-16 04:35:36 +02:00
0837de2a5a
* round CTB clocks to next closest possible value, added freq measurement * added time for firmware to measrue actual value after frequency change * add check for backwards compatibility * change CTB and XCTB clock values to MHz, TODO: units and validation errors * changed runclk command to use units and float, TODO: dbit, adcclk, why is everything called StringTo ? * do the same for dbit and adcclk * added tolerance to exptime, fixed test * update default values in server defs * added virtual check in Altera_PLL, update testcases * change python and pyctbgui to accept and return floating point MHz * update help and comments * Dev/ctb clocks fix (#1434) * introduced new type Hz, typetraits, String conversions, command generation (not yet generated) * incorrect unit typo * cmd generation and compiles * default to MHz, removed space between units for consistency with timers, min and max checks for clks * in python, but need to change the default to Hz again for clean code and intuition * allow ints, doubles, implicit conversions * dont allow raw ints, doubles and implicit conversions * fixed tests * added operators for Hz in python * fix test for min clk for xilinx ctb * fix test * fix python tests * fixed xilinx period and default clks * test fix * removed the 3 clock cycle check for ctb and implemented properly the max adc clk frq for altera ctb * removing 3 clock cycle code from xilinx as well * formatting * loadpattern before 3 clk cycles code * actualtime and measurement time to be implemented in 100ns already in fw * fix tests * pyzmq dependency forthe tests * fixed pyctbgui for freq * insert tolerance check again * also added tolerance check for patwaittime * formatting * minor: rounding test * removed Rep redundant in ToString for freq * intro frequency unit enums, removed unnecessary template behavior for ToString with freq unit, switching from parsing string unit argument to the enum argument for ToString, adding parsing string to unit at CLI boundary * minor, and binaries * minor, default clk vals are 0 but set up at detector setup * get frequency only for that unit * tolerance process * missed in previous commit * some more changes to exptime and validations * ctb is probably done * periodleft and delayleft * fixed xilinx freq conv as well * fixed m3 bug, binaries * xilinx: setup also done in stop server so that the clk is not 0 * missed a test marker * binaries in * review fixes, simpler validation of timers in ctb and xilinx ctb * typo fix * format * fix tests --------- Co-authored-by: Martin Mueller <martin.mueller@psi.ch> Co-authored-by: Dhanya Thattil <dhanya.thattil@psi.ch>
241 lines
8.6 KiB
Python
241 lines
8.6 KiB
Python
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
|
|
# command to generate the ast
|
|
# clang version: 14.0.0-1ubuntu1.1
|
|
# clang++ -Xclang -ast-dump=json -Xclang -ast-dump-filter -Xclang StringTo -c ToString.cpp -I ../include/ -std=gnu++11
|
|
#
|
|
import yaml
|
|
|
|
AUTOCOMPLETE_PATH = Path(__file__).parent
|
|
DUMP_PATH = AUTOCOMPLETE_PATH / 'dump.json'
|
|
FIXED_PATH = AUTOCOMPLETE_PATH / 'fixed.json'
|
|
|
|
type_values = {
|
|
'special::mv': ["mv", "mV"],
|
|
"special::deg": ["deg"],
|
|
"special::time_unit": ["s", "ms", "us", "ns"],
|
|
"special::freq_unit": ["Hz", "kHz", "MHz"],
|
|
"special::hard": ["hard"],
|
|
"special::force-delete-normal-file": ["--force-delete-normal-file"],
|
|
"special::currentSourceFix": ["fix", "nofix"],
|
|
"special::currentSourceLow": ["normal", "low"],
|
|
"special::path": [],
|
|
"special::pedestal_parameters" : ["", "0"],
|
|
"special::validate": ["--validate"]
|
|
}
|
|
|
|
|
|
def get_types(arg_types):
|
|
ret = set()
|
|
for arg_type in arg_types:
|
|
if type_info(arg_type) == 'base':
|
|
if arg_type == 'bool':
|
|
ret = ret.union(["0", "1"])
|
|
else:
|
|
tmp = [not_list for not_list in type_values[arg_type] if not isinstance(not_list, list)]
|
|
ret = ret.union(tmp)
|
|
|
|
#Intercept the options and in case detector specific options appear replace the
|
|
#list of options with a command line call that fetches them
|
|
#TODO! Rename sls_detector_get
|
|
if "defs::dacIndex" in arg_types:
|
|
return r"`sls_detector_get daclist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`"
|
|
elif "defs::detectorSettings" in arg_types:
|
|
return r"`sls_detector_get settingslist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`"
|
|
elif "defs::timingMode" in arg_types:
|
|
return r"`sls_detector_get timinglist | sed -e 's/.*\[\(.*\)\].*/\\1/' | sed 's/,//g'`"
|
|
|
|
|
|
return ret
|
|
|
|
|
|
def type_info(type_name):
|
|
if type_name.startswith('defs::') or type_name.startswith('slsDetectorDefs::'):
|
|
return 'enum'
|
|
if type_name.startswith('special::'):
|
|
return 'special'
|
|
return 'base'
|
|
|
|
|
|
def get_enum(function):
|
|
return function['type']['qualType'].split(' ')[0]
|
|
|
|
|
|
def get_literal(ifstmt):
|
|
stringliteral = []
|
|
expression = ifstmt['inner'][0]
|
|
if expression['kind'] == 'BinaryOperator':
|
|
if expression['opcode'] == '!=':
|
|
return None, None
|
|
for cxxOperatorCall in expression['inner']:
|
|
if cxxOperatorCall['kind'] == 'CXXOperatorCallExpr':
|
|
implicitCastExpr = cxxOperatorCall['inner'][2]
|
|
stringliteral.append(implicitCastExpr['inner'][0]['value'][1:-1])
|
|
else:
|
|
cxxOperatorCall = expression
|
|
implicitCastExpr = cxxOperatorCall['inner'][2]
|
|
stringliteral = implicitCastExpr['inner'][0]['value'][1:-1]
|
|
|
|
retstmt = get_object_by_kind(ifstmt['inner'], 'ReturnStmt')
|
|
if retstmt is None:
|
|
print(f"Error: No 'ReturnStmt' found in: {ifstmt['inner']}")
|
|
exit(1)
|
|
declrefexpt = get_object_by_kind(retstmt['inner'], 'DeclRefExpr')
|
|
enum_val = declrefexpt["referencedDecl"]["name"]
|
|
|
|
return enum_val, stringliteral
|
|
|
|
|
|
def get_object_by_kind(inner, kind, position=1):
|
|
for obj in inner:
|
|
if obj['kind'] == kind:
|
|
position -= 1
|
|
if position == 0:
|
|
return obj
|
|
return None
|
|
|
|
|
|
def generate_type_values():
|
|
functions = json.loads(FIXED_PATH.read_text())
|
|
for function in functions:
|
|
if function['kind'] != 'FunctionDecl' or function['name'] != 'StringTo':
|
|
continue
|
|
enum = get_enum(function)
|
|
|
|
if not enum.startswith('defs::'):
|
|
continue
|
|
# if enum != 'defs::dacIndex':
|
|
# continue
|
|
if not function['loc']['file'].endswith('ToString.cpp'):
|
|
continue
|
|
|
|
compound_stmt = get_object_by_kind(function['inner'], 'CompoundStmt')
|
|
|
|
for ifstmt in compound_stmt['inner']:
|
|
if ifstmt['kind'] != 'IfStmt':
|
|
continue
|
|
enum_val, stringliteral = get_literal(ifstmt)
|
|
if enum_val is None:
|
|
continue
|
|
|
|
if enum not in type_values or type_values[enum] is None:
|
|
type_values[enum] = []
|
|
type_values[enum].append(stringliteral)
|
|
items = list(type_values.items())
|
|
for key, val in items:
|
|
if key.startswith('defs::'):
|
|
new_key = key.split('::')[1]
|
|
new_key = 'slsDetectorDefs::' + new_key
|
|
type_values[new_key] = val
|
|
elif key.startswith('slsDetectorDefs::'):
|
|
new_key = key.split('::')[1]
|
|
new_key = 'defs::' + new_key
|
|
type_values[new_key] = val
|
|
|
|
return json.dumps(type_values, indent=2)
|
|
|
|
|
|
def fix_json():
|
|
with DUMP_PATH.open('r') as f:
|
|
tmp = '[\n'
|
|
for line in f.read().split('\n'):
|
|
if line.startswith('}'):
|
|
tmp += line + ',\n'
|
|
else:
|
|
tmp += line + '\n'
|
|
tmp = tmp[:-3] + '\n]'
|
|
with FIXED_PATH.open('w') as f:
|
|
f.write(tmp)
|
|
|
|
|
|
def generate_bash_autocomplete(output_path=Path(__file__).parent / 'bash_autocomplete.sh', input_path=Path(__file__).parent / 'bash_autocomplete.in.sh'):
|
|
generate_type_values()
|
|
output_file = output_path.open('w')
|
|
template_file = input_path.open('r')
|
|
|
|
def writeline(line):
|
|
output_file.write(line + '\n')
|
|
|
|
class if_block:
|
|
def __init__(self, condition):
|
|
self.condition = condition
|
|
|
|
def __enter__(self):
|
|
output_file.write('if [[ ' + self.condition + ' ]]; then\n')
|
|
|
|
def __exit__(self, type, value, traceback):
|
|
output_file.write('fi\n')
|
|
|
|
class function:
|
|
def __init__(self, name):
|
|
self.name = name
|
|
|
|
def __enter__(self):
|
|
output_file.write(self.name + '() {\n')
|
|
|
|
def __exit__(self, type, value, traceback):
|
|
output_file.write('}\n')
|
|
|
|
command_path = Path(__file__).parent.parent / 'extended_commands.yaml'
|
|
commands = yaml.unsafe_load(command_path.open('r'))
|
|
|
|
for line in template_file:
|
|
if '-- THIS LINE WILL BE REPLACED WITH GENERATED CODE --' not in line:
|
|
output_file.write(line)
|
|
continue
|
|
writeline(f'local SLS_COMMANDS=" {" ".join(commands.keys())} "')
|
|
# generate functions
|
|
for command_name, command in commands.items():
|
|
# added for debugging
|
|
if command_name == 'xxxexptime':
|
|
continue
|
|
with function('__' + command_name):
|
|
writeline('FCN_RETURN=""')
|
|
|
|
actions = ['GET', 'PUT']
|
|
for action in actions:
|
|
if action in command['actions'] and 'args' in command['actions'][action]:
|
|
args = command['actions'][action]['args']
|
|
possible_argc = {}
|
|
for arg in args:
|
|
if arg['argc'] == 0:
|
|
pass
|
|
for i in range(arg['argc']):
|
|
if i + 1 not in possible_argc:
|
|
possible_argc[i + 1] = []
|
|
possible_argc[i + 1].append(arg['arg_types'][i])
|
|
if possible_argc:
|
|
with if_block(f'${{IS_GET}} -eq {"1" if action == "GET" else "0"}'):
|
|
for argc in possible_argc:
|
|
with if_block(f'"${{cword}}" == "{argc + 1}"'):
|
|
if "defs::detectorSettings" in possible_argc[argc]:
|
|
print(argc, command_name, possible_argc[argc])
|
|
choices = get_types(possible_argc[argc])
|
|
|
|
#check if we got choices back or a bash command
|
|
if isinstance(choices, (list,set)):
|
|
writeline(f'FCN_RETURN="{" ".join(sorted(choices))}"')
|
|
else:
|
|
writeline(f'FCN_RETURN="{choices}"')
|
|
if 'special::path' in possible_argc[argc]:
|
|
writeline('IS_PATH=1')
|
|
|
|
writeline('return 0')
|
|
|
|
|
|
|
|
output_file.close()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(description='use parsed c++ code to generate autocomplete snippets')
|
|
parser.add_argument('-f', '--fix', action='store_true', help='fix the parsed ast to make it loadable')
|
|
# parser.add_argument('-p', '--path', type=str, help='output path to the fixed ast', default='ast.json')
|
|
args = parser.parse_known_args()
|
|
if args[0].fix:
|
|
fix_json()
|
|
ret = generate_type_values()
|
|
print(ret)
|