mirror of
https://github.com/slsdetectorgroup/slsDetectorPackage.git
synced 2025-12-18 10:31:18 +01:00
readout speed added to json and h5 master files. Also fixed master file inconsistencies Sserver binaries - update server binaries because readoutspeed needs to be sent to receiver with rx_hostname command API - added const to Detector class set/getburstmode Python - updated python bindings (burstmode const and roi arguments) Cmd generation - added pragma once in Caller.in.h as Caller is included in test files m3: num channels due to #counters < 3 * workaround for m3 for messed up num channels (client always assumes all counters enabled and adds them to num channels), fix for hdf5 g2: exptime master file inconsistency - exptime didnt match because of round of when setting burst mode (sets to a different clk divider) - so updating actual time for all timers (exptime, period, subexptime etc, ) in Module class, get timer values from detector when setting it and then send to receiver to write in master file ctb image size incorrect: - write actual size into master file and not the reserved size (digital reduces depending on dbit list and dbit offset) - added a calculate ctb image size free function in generalData.h that is used there as well as for the tests. master file inconsistencies - refactored master attributes writing using templates - names changed to keep it consistent between json and hdf5 master file (Version, Pixels, Exposure Times, GateDelays, Acquisition Period, etc.) - datatypes changed to keep it simple where possible: imageSize, dynamicRange, tengiga, quad, readnrows, analog, analogsamples, digital, digitalsamples, dbitreorder, dbitoffset, transceivermask, transeiver, transceiversamples, countermask, gates =>int - replacing "toString" with arrays, objects etc for eg for scan, rois, etc. - json header always written (empty dataset or empty brackets) - hdf5 needs const char* so have to convert strings to it, but taking care that strings exist prior to push_back - master attributes (redundant string literals->error prone tests for master file - suppressed deprecated functions in rapidjson warnings just for the tests - added slsREceiverSoftware/src to allow access to receiver_defs.h to test binary/hdf5 version - refactored acquire tests by moving all the acquire tests from individual detector type files to a single one=test-Caller-acquire.cpp - set some default settings (loadBasicSettings) for a basic acquire at load config part for the test_simulator python scripts. so minimum number of settings for detector to be set for any acquire tests. - added tests to test master files for json and hdf5= test-Caller-master-attributes.cpp - added option to add '-m' markers for tests using test_simulator python script
246 lines
7.5 KiB
Python
246 lines
7.5 KiB
Python
# SPDX-License-Identifier: LGPL-3.0-or-other
|
|
# Copyright (C) 2021 Contributors to the SLS Detector Package
|
|
"""
|
|
This file is used to auto generate Python bindings for the
|
|
sls::Detector class. The tool needs the libclang bindings
|
|
to be installed.
|
|
|
|
When the Detector API is updated this file should be run
|
|
manually.
|
|
"""
|
|
from clang import cindex
|
|
import subprocess
|
|
import argparse
|
|
import sys
|
|
import time
|
|
import ctypes.util, re # to check libclang version
|
|
from pathlib import Path
|
|
from parse import system_include_paths, clang_format_version
|
|
|
|
REDC = "\033[91m"
|
|
GREENC = "\033[92m"
|
|
YELLOWC = "\033[93m"
|
|
ENDC = "\033[0m"
|
|
|
|
def yellow(msg):
|
|
return f"{YELLOWC}{msg}{ENDC}"
|
|
|
|
def red(msg):
|
|
return f"{REDC}{msg}{ENDC}"
|
|
|
|
|
|
def green(msg):
|
|
return f"{GREENC}{msg}{ENDC}"
|
|
|
|
|
|
def check_libclang_version(required="12"):
|
|
# Use already-loaded libclang, or let cindex resolve it
|
|
lib = ctypes.CDLL(cindex.Config.library_file or ctypes.util.find_library("clang"))
|
|
|
|
# Get version string
|
|
lib.clang_getClangVersion.restype = ctypes.c_void_p
|
|
version_ptr = lib.clang_getClangVersion()
|
|
version_str = ctypes.cast(version_ptr, ctypes.c_char_p).value.decode()
|
|
|
|
# Parse and check version
|
|
match = re.search(r"version\s+(\d+)", version_str)
|
|
if not match or match.group(1) != required:
|
|
msg = red(f"libclang version {match.group(1) if match else '?'} found, but version {required} required. Bye!")
|
|
print(msg)
|
|
sys.exit(1)
|
|
msg = green(f"Found libclang version {required}")
|
|
print(msg)
|
|
|
|
|
|
def check_clang_format_version(required_version):
|
|
if (ver := clang_format_version()) != required_version:
|
|
msg = red(
|
|
f"Clang format version {required_version} required, detected: {ver}. Bye!"
|
|
)
|
|
print(msg)
|
|
sys.exit(1)
|
|
else:
|
|
msg = green(f"Found clang-format version {ver}")
|
|
print(msg)
|
|
|
|
|
|
def check_for_compile_commands_json(path):
|
|
# print(f"Looking for compile data base in: {path}")
|
|
compile_data_base_file = path / "compile_commands.json"
|
|
if not compile_data_base_file.exists():
|
|
msg = red(f"No compile_commands.json file found in {path}. Bye!")
|
|
print(msg)
|
|
sys.exit(1)
|
|
else:
|
|
msg = green(f"Found: {compile_data_base_file}")
|
|
print(msg)
|
|
|
|
|
|
default_build_path = "/home/l_frojdh/sls/build/"
|
|
fpath = "../../slsDetectorSoftware/src/Detector.cpp"
|
|
|
|
|
|
m = []
|
|
ag = []
|
|
lines = []
|
|
ag2 = []
|
|
cn = []
|
|
|
|
|
|
def get_arguments(node):
|
|
args = [a.type.spelling for a in node.get_arguments()]
|
|
args = [
|
|
"py::arg() = Positions{}" if item == "sls::Positions" else "py::arg()"
|
|
for item in args
|
|
]
|
|
args = ", ".join(args)
|
|
if args:
|
|
args = f", {args}"
|
|
return args
|
|
|
|
|
|
def get_arguments_with_default(node):
|
|
args = []
|
|
for arg in node.get_arguments():
|
|
tokens = [t.spelling for t in arg.get_tokens()]
|
|
# print(tokens)
|
|
if "=" in tokens:
|
|
if arg.type.spelling == "sls::Positions": # TODO! automate
|
|
args.append("py::arg() = Positions{}")
|
|
else:
|
|
args.append("py::arg()" + "".join(tokens[tokens.index("=") :]))
|
|
else:
|
|
args.append("py::arg()")
|
|
args = ", ".join(args)
|
|
if args:
|
|
args = f", {args}"
|
|
return args
|
|
|
|
|
|
def get_fdec(node):
|
|
args = [a.type.spelling for a in node.get_arguments()]
|
|
if node.result_type.spelling:
|
|
return_type = node.result_type.spelling
|
|
else:
|
|
return_type = "void"
|
|
|
|
if node.is_const_method():
|
|
const = "const"
|
|
else:
|
|
const = ""
|
|
args = ", ".join(args)
|
|
args = f"({return_type}(Detector::*)({args}){const})"
|
|
return args
|
|
|
|
|
|
def time_return_lambda(node, args):
|
|
names = ['a', 'b', 'c', 'd']
|
|
fa = [a.type.spelling for a in node.get_arguments()]
|
|
ca = ','.join(f'{arg} {n}' for arg, n in zip(fa, names))
|
|
na = ','.join(names[0:len(fa)])
|
|
s = f'CppDetectorApi.def("{node.spelling}",[](sls::Detector& self, {ca}){{ auto r = self.{node.spelling}({na}); \n return std::vector<sls::Duration>(r.begin(), r.end()); }}{args});'
|
|
return s
|
|
|
|
|
|
def visit(node):
|
|
|
|
loc = node.location
|
|
# skip if ndoe is outside project directory
|
|
if loc.file and not str(loc.file).startswith(str(cargs.build_path.parent)):
|
|
return
|
|
|
|
'''
|
|
# to see which file was causing the error (not in Detector.h, so skipping others in the above code)
|
|
try:
|
|
kind = node.kind
|
|
except ValueError as e:
|
|
loc = node.location
|
|
file_name = loc.file.name if loc.file else "<unknown file>"
|
|
msg = yellow(f"\nWarning: skipping node with unknown CursorKind id {node._kind_id} at {file_name}:{loc.line}:{loc.column}")
|
|
print(msg)
|
|
return
|
|
'''
|
|
|
|
if node.kind == cindex.CursorKind.CLASS_DECL:
|
|
if node.displayname == "Detector":
|
|
for child in node.get_children():
|
|
# Skip assignment operators
|
|
if child.kind == cindex.CursorKind.CXX_METHOD and child.spelling == "operator=":
|
|
continue
|
|
if (
|
|
child.kind == cindex.CursorKind.CXX_METHOD
|
|
and child.access_specifier == cindex.AccessSpecifier.PUBLIC
|
|
):
|
|
m.append(child)
|
|
args = get_arguments_with_default(child)
|
|
fs = get_fdec(child)
|
|
lines.append(
|
|
f'CppDetectorApi.def("{child.spelling}",{fs} &Detector::{child.spelling}{args});'
|
|
)
|
|
if cargs.verbose:
|
|
print(f"&Detector::{child.spelling}{args})")
|
|
cn.append(child)
|
|
|
|
for child in node.get_children():
|
|
visit(child)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"-p",
|
|
"--build_path",
|
|
help="Path to the build database",
|
|
type=Path,
|
|
default=default_build_path,
|
|
)
|
|
parser.add_argument(
|
|
"-v",
|
|
"--verbose",
|
|
help="more output",
|
|
action="store_true",
|
|
)
|
|
cargs = parser.parse_args()
|
|
|
|
check_libclang_version("12")
|
|
check_clang_format_version(12)
|
|
check_for_compile_commands_json(cargs.build_path)
|
|
|
|
print("Parsing functions in Detector.h - ", end="", flush=True)
|
|
t0 = time.perf_counter()
|
|
# parse functions
|
|
db = cindex.CompilationDatabase.fromDirectory(cargs.build_path)
|
|
index = cindex.Index.create()
|
|
args = db.getCompileCommands(fpath)
|
|
args = list(iter(args).__next__().arguments)[0:-1]
|
|
args = args + "-x c++ --std=c++11".split()
|
|
syspath = system_include_paths("clang++")
|
|
incargs = ["-I" + inc for inc in syspath]
|
|
args = args + incargs
|
|
tu = index.parse(fpath, args=args)
|
|
visit(tu.cursor)
|
|
print(green("OK"))
|
|
print(f"Parsing took {time.perf_counter()-t0:.3f}s")
|
|
|
|
print("Read detector_in.cpp - ", end="")
|
|
with open("../src/detector_in.cpp") as f:
|
|
data = f.read()
|
|
s = "".join(lines)
|
|
s += ";"
|
|
text = data.replace("[[FUNCTIONS]]", s)
|
|
warning = "/* WARINING This file is auto generated any edits might be overwritten without warning */\n\n"
|
|
print(green("OK"))
|
|
print("Writing to detector.cpp - ", end="")
|
|
with open("../src/detector.cpp", "w") as f:
|
|
f.write(warning)
|
|
f.write(text)
|
|
print(green("OK"))
|
|
|
|
# run clang format on the output
|
|
print("Running clang format on generated source -", end="")
|
|
subprocess.run(["clang-format", "../src/detector.cpp", "-i"])
|
|
print(green(" OK"))
|
|
|
|
print("Changes since last commit:")
|
|
subprocess.run(["git", "diff", "../src/detector.cpp"])
|