From faf049f607dfbcbbc8ab389081d0f03ef9f7b869 Mon Sep 17 00:00:00 2001 From: Piotr Jarosik Date: Sat, 9 Apr 2022 16:08:26 +0200 Subject: [PATCH 1/4] Exposed us4OEM main firmware and tx firmware version. --- api/python/arrus/devices/us4oem.py | 20 ++++++++++++++++++++ api/python/arrus/devices/us4r.py | 19 +++++++++++++++++++ api/python/wrappers/core.i | 6 +++--- arrus/core/api/devices/us4r/Us4R.h | 2 +- 4 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 api/python/arrus/devices/us4oem.py diff --git a/api/python/arrus/devices/us4oem.py b/api/python/arrus/devices/us4oem.py new file mode 100644 index 000000000..9b7f5e6f2 --- /dev/null +++ b/api/python/arrus/devices/us4oem.py @@ -0,0 +1,20 @@ +from arrus.devices.device import Device, DeviceId, DeviceType + +DEVICE_TYPE = DeviceType("Us4OEM") + + +class Us4OEM(Device): + + def __init__(self, handle): + self._handle = handle + self._device_id = DeviceId(DEVICE_TYPE, + self._handle.getDeviceId().getOrdinal()) + + def get_device_id(self) -> DeviceId: + return self._device_id + + def get_firmware_version(self) -> int: + return self._handle.getFirmwareVersion() + + def get_tx_firmware_version(self) -> int: + return self._handle.getTxFirmwareVersion() \ No newline at end of file diff --git a/api/python/arrus/devices/us4r.py b/api/python/arrus/devices/us4r.py index 317e6b7a6..4f40c5f4b 100644 --- a/api/python/arrus/devices/us4r.py +++ b/api/python/arrus/devices/us4r.py @@ -7,6 +7,7 @@ from arrus.devices.device import Device, DeviceId, DeviceType import arrus.exceptions import arrus.devices.probe +from arrus.devices.us4oem import Us4OEM import arrus.metadata import arrus.kernels import arrus.kernels.kernel @@ -105,6 +106,24 @@ def sampling_frequency(self): def n_us4oems(self): return self._handle.getNumberOfUs4OEMs() + def get_us4oem(self, ordinal: int): + return Us4OEM(self._handle.getUs4OEM(ordinal)) + + @property + def firmware_version(self): + result = {} + # Us4OEMs + us4oem_ver = [] + for i in range(self.n_us4oems): + dev = self.get_us4oem(i) + ver = { + "main": dev.get_firmware_version(), + "tx": dev.get_tx_firmware_version() + } + us4oem_ver.append(ver) + result["Us4OEM"] = us4oem_ver + return result + def set_kernel_context(self, kernel_context): self._current_sequence_context = kernel_context diff --git a/api/python/wrappers/core.i b/api/python/wrappers/core.i index 6d212698c..885eb0e60 100644 --- a/api/python/wrappers/core.i +++ b/api/python/wrappers/core.i @@ -63,6 +63,7 @@ namespace std { #include "arrus/core/api/io/settings.h" #include "arrus/core/api/session/Session.h" #include "arrus/core/api/common/logging.h" +#include "arrus/core/api/devices/us4r/Us4OEM.h" #include "arrus/core/api/devices/us4r/Us4R.h" #include "arrus/core/api/ops/us4r/TxRxSequence.h" @@ -225,6 +226,7 @@ std::shared_ptr getFifoLockFreeBuffer(arrus::sessi #include "arrus/core/api/devices/DeviceId.h" #include "arrus/core/api/devices/Device.h" #include "arrus/core/api/devices/DeviceWithComponents.h" +#include "arrus/core/api/devices/us4r/Us4OEM.h" #include "arrus/core/api/devices/us4r/Us4R.h" #include "arrus/core/api/devices/probe/ProbeModelId.h" #include "arrus/core/api/devices/probe/Probe.h" @@ -244,8 +246,6 @@ using namespace arrus::devices; %include "arrus/core/api/devices/probe/Probe.h" - - %inline %{ arrus::devices::Us4R *castToUs4r(arrus::devices::Device *device) { auto ptr = dynamic_cast(device); @@ -254,7 +254,7 @@ arrus::devices::Us4R *castToUs4r(arrus::devices::Device *device) { } return ptr; } -// TODO(pjarosik) remote the bellow functions when possible +// TODO(pjarosik) remove the bellow functions when possible unsigned short getNumberOfElements(const arrus::devices::ProbeModel &probe) { const auto &nElements = probe.getNumberOfElements(); diff --git a/arrus/core/api/devices/us4r/Us4R.h b/arrus/core/api/devices/us4r/Us4R.h index 569e4690d..12b35b95d 100644 --- a/arrus/core/api/devices/us4r/Us4R.h +++ b/arrus/core/api/devices/us4r/Us4R.h @@ -35,7 +35,7 @@ class Us4R : public DeviceWithComponents { * @param ordinal ordinal number of the us4oem to get * @return a handle to the us4oem module */ - virtual Us4OEM::RawHandle getUs4OEM(Ordinal ordinal) = 0; + virtual Us4OEM* getUs4OEM(Ordinal ordinal) = 0; /** * Returns a handle to an adapter identified by given ordinal number. From bf3dd3e57873f962546ce94198ce5a7911f507c8 Mon Sep 17 00:00:00 2001 From: Piotr Jarosik Date: Sun, 10 Apr 2022 17:58:33 +0200 Subject: [PATCH 2/4] Made it possible to register buffer overflow callback and configure internal processing buffers. --- api/python/arrus/framework.py | 37 ++++++++++++++++++++++++++++++- api/python/arrus/utils/imaging.py | 37 ++++++++++++++++++++++++++----- api/python/wrappers/core.i | 23 +++++++++++++++++++ 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/api/python/arrus/framework.py b/api/python/arrus/framework.py index 17d87909a..515663b77 100644 --- a/api/python/arrus/framework.py +++ b/api/python/arrus/framework.py @@ -14,7 +14,22 @@ def __init__(self, callback_fn): def run(self, element): try: self._callback_fn(element) - except: + except Exception as e: + print(e) + traceback.print_exc() + + +class OnBufferOverflowCallback(arrus.core.OnBufferOverflowCallbackWrapper): + + def __init__(self, callback_fn): + super().__init__() + self._callback_fn = callback_fn + + def run(self): + try: + self._callback_fn() + except Exception as e: + print(e) traceback.print_exc() @@ -66,6 +81,8 @@ def __init__(self, buffer_handle): self._buffer_handle = buffer_handle self._callbacks = [] self._register_internal_callback() + self._on_buffer_overflow_callbacks = [] + self._register_internal_buffer_overflow_callback() self.elements = self._wrap_elements() self.n_elements = len(self.elements) @@ -81,6 +98,14 @@ def append_on_new_data_callback(self, callback): """ self._callbacks.append(callback) + def append_on_buffer_overflow_callback(self, callback): + """ + Register callback that will be called when buffer overflow occurs. + + :param callback: callback function to register + """ + self._on_buffer_overflow_callbacks.append(callback) + def _register_internal_callback(self): self._callback_wrapper = OnNewDataCallback(self._callback) arrus.core.registerOnNewDataCallbackFifoLockFreeBuffer( @@ -92,6 +117,16 @@ def _callback(self, element): for cbk in self._callbacks: cbk(py_element) + def _on_buffer_overflow_callback(self): + for cbk in self._on_buffer_overflow_callbacks: + cbk() + + def _register_internal_buffer_overflow_callback(self): + self._overflow_callback_wrapper = OnBufferOverflowCallback( + self._on_buffer_overflow_callback) + arrus.core.registerOnBufferOverflowCallback( + self._buffer_handle, self._overflow_callback_wrapper) + def _wrap_elements(self): return [DataBufferElement(self._buffer_handle.getElement(i)) for i in range(self._buffer_handle.getNumberOfElements())] diff --git a/api/python/arrus/utils/imaging.py b/api/python/arrus/utils/imaging.py index bb872dada..4bdf32883 100644 --- a/api/python/arrus/utils/imaging.py +++ b/api/python/arrus/utils/imaging.py @@ -81,7 +81,8 @@ def get_bmode_imaging(sequence, grid, placement="/GPU:0", EnvelopeDetection(), Transpose(axes=(0, 2, 1)), ScanConversion(x_grid, z_grid), - LogCompression() + Mean(axis=0), + LogCompression(), ), placement=placement) elif isinstance(sequence, arrus.ops.imaging.PwiSequence) \ @@ -192,16 +193,24 @@ def __init__(self, input_buffer, const_metadata, processing): # Initialize pipeline. self.cp = cp self.input_buffer = self.__register_buffer(input_buffer) - self.gpu_buffer = Buffer(n_elements=2, shape=const_metadata.input_shape, + default_buffer = ProcessingBuffer(size=2, type="locked") + + in_buffer_spec = processing.input_buffer + out_buffer_spec = processing.output_buffer + in_buffer_spec = in_buffer_spec if in_buffer_spec is not None else default_buffer + out_buffer_spec = out_buffer_spec if out_buffer_spec is not None else default_buffer + + self.gpu_buffer = Buffer(n_elements=in_buffer_spec.size, + shape=const_metadata.input_shape, dtype=const_metadata.dtype, math_pkg=cp, - type="locked") + type=in_buffer_spec.type) self.pipeline = processing.pipeline self.data_stream = cp.cuda.Stream(non_blocking=True) self.processing_stream = cp.cuda.Stream(non_blocking=True) self.out_metadata = processing.pipeline.prepare(const_metadata) - self.out_buffers = [Buffer(n_elements=2, shape=m.input_shape, + self.out_buffers = [Buffer(n_elements=out_buffer_spec.size, shape=m.input_shape, dtype=m.dtype, math_pkg=np, - type="locked") + type=out_buffer_spec.type) for m in self.out_metadata] # Wait for all the initialization done in by the Pipeline. cp.cuda.Stream.null.synchronize() @@ -224,6 +233,9 @@ def __init__(self, input_buffer, const_metadata, processing): self.metadata_extractor = ExtractMetadata() self.metadata_extractor.prepare(const_metadata) self.input_buffer.append_on_new_data_callback(self.process) + if processing.on_buffer_overflow_callback is not None: + self.input_buffer.append_on_buffer_overflow_callback( + processing.on_buffer_overflow_callback) @property def outputs(self): @@ -508,15 +520,28 @@ def set_placement(self, device): self.filter_pkg = pkgs['filter_pkg'] +@dataclasses.dataclass(frozen=True) +class ProcessingBuffer: + size: int + type: str + # TODO: placement + + class Processing: """ A description of complete data processing run in the arrus.utils.imaging. """ - def __init__(self, pipeline, callback=None, extract_metadata=False): + def __init__(self, pipeline, callback=None, extract_metadata=False, + input_buffer: ProcessingBuffer=None, + output_buffer: ProcessingBuffer=None, + on_buffer_overflow_callback=None): self.pipeline = pipeline self.callback = callback self.extract_metadata = extract_metadata + self.input_buffer = input_buffer + self.output_buffer = output_buffer + self.on_buffer_overflow_callback = on_buffer_overflow_callback class Lambda(Operation): diff --git a/api/python/wrappers/core.i b/api/python/wrappers/core.i index 885eb0e60..04a3da2a2 100644 --- a/api/python/wrappers/core.i +++ b/api/python/wrappers/core.i @@ -183,6 +183,29 @@ void registerOnNewDataCallbackFifoLockFreeBuffer(const std::shared_ptrregisterOnNewDataCallback(actualCallback); } + +class OnBufferOverflowCallbackWrapper { +public: + OnBufferOverflowCallbackWrapper() {} + virtual void run() const {} + virtual ~OnBufferOverflowCallbackWrapper() {} +}; + +void registerOnBufferOverflowCallback(const std::shared_ptr &buffer, OnBufferOverflowCallbackWrapper& callback) { + auto fifolockfreeBuffer = std::static_pointer_cast(buffer); + ::arrus::framework::OnOverflowCallback actualCallback = [&]() { + PyGILState_STATE gstate = PyGILState_Ensure(); + try { + callback.run(); + } catch(const std::exception &e) { + std::cerr << "Exception: " << e.what() << std::endl; + } catch(...) { + std::cerr << "Unhandled exception" << std::endl; + } + PyGILState_Release(gstate); + }; + fifolockfreeBuffer->registerOnOverflowCallback(actualCallback); +} %}; // ------------------------------------------ SESSION From 6c1841f4190e13c7a348f2df7152de55109d46cc Mon Sep 17 00:00:00 2001 From: Piotr Jarosik Date: Sun, 10 Apr 2022 23:20:43 +0200 Subject: [PATCH 3/4] Cast us4OEM firmware version to unsigned value. --- api/python/arrus/devices/us4oem.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/api/python/arrus/devices/us4oem.py b/api/python/arrus/devices/us4oem.py index 9b7f5e6f2..e32758ae9 100644 --- a/api/python/arrus/devices/us4oem.py +++ b/api/python/arrus/devices/us4oem.py @@ -1,3 +1,4 @@ +import ctypes from arrus.devices.device import Device, DeviceId, DeviceType DEVICE_TYPE = DeviceType("Us4OEM") @@ -14,7 +15,7 @@ def get_device_id(self) -> DeviceId: return self._device_id def get_firmware_version(self) -> int: - return self._handle.getFirmwareVersion() + return ctypes.c_ulong(self._handle.getFirmwareVersion()).value def get_tx_firmware_version(self) -> int: - return self._handle.getTxFirmwareVersion() \ No newline at end of file + return ctypes.c_ulong(self._handle.getTxFirmwareVersion()).value \ No newline at end of file From 4826cc9b7a7b9654a43d8754edefb2bfc30cb693 Mon Sep 17 00:00:00 2001 From: Piotr Jarosik Date: Mon, 11 Apr 2022 08:32:54 +0200 Subject: [PATCH 4/4] Save the us4OEM firmware version as hex string in Python. --- api/python/arrus/devices/us4r.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/python/arrus/devices/us4r.py b/api/python/arrus/devices/us4r.py index 4f40c5f4b..f7b7f1398 100644 --- a/api/python/arrus/devices/us4r.py +++ b/api/python/arrus/devices/us4r.py @@ -117,8 +117,8 @@ def firmware_version(self): for i in range(self.n_us4oems): dev = self.get_us4oem(i) ver = { - "main": dev.get_firmware_version(), - "tx": dev.get_tx_firmware_version() + "main": f"{dev.get_firmware_version():x}", + "tx": f"{dev.get_tx_firmware_version():x}" } us4oem_ver.append(ver) result["Us4OEM"] = us4oem_ver