SuperMUSR Bridge (adc120-bridge-v2)

Software running on the SuperMUSR DAQ box (ADC120 digitizer, Xilinx Zynq UltraScale+, Ubuntu 24.04 ARM64 rootfs) that bridges the FPGA firmware with the rest of the acquisition pipeline: it reads waveforms via DMA, builds the Flatbuffer messages, publishes them to ZMQ and Kafka, and exposes a control and housekeeping channel over ZMQ.

Package name on the NI Packages portal: supermusr-bridge.


What it does

  • Acquisition. A dedicated thread (acquisition_thread) waits for a waveform to be ready, reads the DMA, lays out the samples per channel (8 x dgtz.pre + dgtz.post, 1 sample = 1 ns at 1 GS/s) and pushes the frame to an internal queue.
  • Processing. A dedicated thread (processing_thread) drains the queue, optionally applies zero suppression channel by channel, serializes the frame via Flatbuffer (DigitizerAnalogTraceMessage v2) and fans the same buffer out to every registered push service.
  • Push services. The same serialized buffer is sent to:
    • ZMQ waveforms (zmq, port zmq.streaming_port)
    • ZMQ events (zmq_data, port zmq.streaming_events_port)
    • Kafka waveforms (kafka, topic kafka.topic)
    • Kafka events (kafka_events, topic kafka_events.topic)
  • Control / Housekeeping. A ZMQ server on zmq.control_port executes commands (start_acquisition, stop_acquisition, configure_dgtz, get_hk, get_waveforms, …) and serves every *.* parameter registered in adc120_brdige.cpp through params.add_param(...).
  • Software zero suppression (from 9.5.10.0): per-channel gate with threshold + hysteresis, samples outside the gate forced to 0. The frame size does not change; combined with Kafka-side compression (compression.type=lz4|zstd) the compression ratio goes up by orders of magnitude. Parameters under zs.*, counters under zs.probes.* (bytes in/out/serializer, windows per event, 1 s throughput). Full details in the release notes.
  • Software signal emulator (from 9.5.11.0): generates realistic SiPM
    • scintillator frames (validated against SuperMUSR run2 Module1) so the full pipeline (ZS, serializer, ZMQ, Kafka) can be exercised without beam. Two modes: overwrite (real DMA/trigger/status packet, samples overwritten) and replace (self-paced via swemu.frame_rate, fake status packet, works even with hardware.enabled=false). Lives alongside the FPGA emulator (dgtz.emu.*), parameters under swemu.*.
  • ZMQ waveform throttle (from 9.5.12.0): zmq.frame_rate_limit caps the rate of waveforms forwarded to the ZMQ streaming socket without touching Kafka. Useful for GUI slow-monitor during full-rate acquisition.

Supported hardware

  • DAQ board: ADC120 (SuperMUSR digitizer), 8 ADC channels, 12 bit, 1 GS/s.
  • SoC: Xilinx Zynq UltraScale+ (xczu*).
  • Target OS: Ubuntu 24.04 ARM64 (nibuntu-arm-64-24-04-isis), sysroot supermusr-root-fs.
  • Base board: up to 2 SuperMUSR staves, HV, LVDS sync, LEMO, I2C.

Intended to run as a service on the DAQ box, usually started as sudo chrt --fifo 99 ./zmq_adc120 /ni/config/default.cfg so it gets SCHED_FIFO priority (see the note at the top of adchal.cpp).


Repository layout

PathContents
zmq_adc120/src/C++17 sources: adc120_brdige.cpp (main + parameter registration), adchal.cpp/h (HAL, acquisition, processing, ZS, swemu), zero_suppression.h (ZS algorithm), signal_emulator.cpp/h + pulse_template.inc (software emulator), flatbufferserializers.cpp/h, kafkaproducer.cpp/h, zmqstreamerserver.cpp/h, processing.cpp/h (CPU-side processing: spectra, deconvolution), …
zmq_adc120/src/schemas/Generated Flatbuffer headers, pulled from the supermusr-flat-buffers package
zmq_adc120/src/lib_userspace_dma_driver/Xilinx DMA userspace driver
zmq_adc120/Release/Output of the Eclipse CDT headless build
zmq_adc120/Debug/Debug build, same layout
.ni/nipkg.ymlPackage descriptor for the supermusr-bridge NI Package
.ni/pippolina.ymlRelease policy consumed by pippolina
.gitlab-ci.yml, .gitlab-ci/release.ymlBuild + release pipeline
compile-cicd.shBuild job script (pulls deps, runs Eclipse headless)
CHANGELOG.mdRelease history
default.cfgSample configuration

Build

Local (aarch64 cross-compile)

Prerequisites:

  • aarch64-linux-gnu-g++ cross toolchain
  • Eclipse CDT headless (the zmq_adc120 project)
  • Ubuntu 24.04 ARM sysroot in /sharedVolume/sysroot-24 (hard-coded in Release/src/subdir.mk)
  • flatbuffers headers available (-I$(HOME)/projects/flatbuffers/include or /sharedVolume/flatbuffers/include)
  • Flatbuffer schema headers from the supermusr-flat-buffers package in zmq_adc120/src/schemas/

Build:

./compile-cicd.sh
# -> zmq_adc120/Release/zmq_adc120

The script pulls the sysroot and the flatbuffers package from the internal catalog (still via nirelease for now), copies the Flatbuffer headers into src/schemas/ and runs Eclipse CDT headless against zmq_adc120/Release.

GitLab pipeline (build + release)

Any protected tag triggers:

  1. pippolina-pre-pipeline — waits for the pippolina lock (the release orchestrator, 24 h timeout).
  2. build_eclipse — image registry.lanni/apps/eclipse-2021-09-cpp-arm-aarch-18, runs ./compile-cicd.sh, produces zmq_adc120.tar.gz (which contains zmq_adc120/Release/zmq_adc120).
  3. release — cicd-catalogs/ni-release-catalog/ni-release-generic component, reads .ni/nipkg.yml and publishes the tar.gz on NI Packages under the supermusr-bridge package slug. It also creates the GitLab release, with the description built from the CHANGELOG.md diff between the previous tag and the current one.

Tag format: date-4-dot (YYYY.M.D.N, e.g. 2026.10.22.1). Any tag containing -STAGING lands on the staging channel of the portal.

Tags are protected (rule 202* for Maintainers only) so the protected NIPKG_CICD_TOKEN variable is exposed to the release job.


Runtime configuration

  • JSON file read at startup (default.cfg or the one passed as argv[1]), loaded into cfg_class by configuration.cpp. Holds ZMQ ports, Kafka brokers, channel map, hardware enable flag, stave version, ...
  • Runtime parameters over the ZMQ control port, one command per parameter. Everything is registered in adc120_brdige.cpp via params.add_param(...).

Main namespaces:

NamespaceScope
dgtz.*Trigger, pre/post, polarity, FPGA emulator, HW probes
mp.*Multiphoton: gain, offset, thresholds, spectrum
trg.*, in.*External trigger, input offset, channel map
stave.*, BIAS.*Stave control and HV bias
base.*LEMO, sync, LVDS, base-board T0 source
sw_process.*Software processing (spectra, deconvolution, filters)
zs.*Software zero suppression (from 9.5.10.0)
swemu.*Software signal emulator (from 9.5.11.0)
zmq.*ZMQ waveform throttle (from 9.5.12.0)
system.*sw version, SN, IP, system metrics

Probes (*.probes.*) are read-only and are also aggregated in the JSON returned by the get_hk command, under data.probes.*.


SuperMUSR Bridge icon

SuperMUSR Bridge

Bridge software for the SuperMUSR ADC120 DAQ box (Zynq UltraScale+, Ubuntu 24 ARM64): reads waveforms via DMA, applies optional software zero suppression, serializes to Flatbuffer and streams them to ZMQ and Kafka. Includes a ZMQ control server, housekeeping and a software signal emulator for pipeline testing without beam.

License: