DCS4
Hard ware
This PC is ordered from OriginPC.
| Item | Description |
|---|---|
| CPU | AMD Ryzen 9 9950X3D 16-Core Processor (up to 5.7 GHz) |
| Motherboard | MSI PRO B850-P WIFI7 (WIFI antanna not installed) |
| RAM | 2 x 48 GB DDR5 6000MT/s |
| Cooling | Liquid cool |
| GPU | NVIDIA RTX PRO 2000 Blackwell 16 GB |
| Disk | 1TB M.2 (OS) + 2x 8TB M.2 (storage) |
| network card | Intel X550-T2 10Gbps (2 ports) |
| Fiber Optics | CAEN A3818 Fiber optics adaptor |
CAEN A3818 PCIe CONET2 Controller — Setup on dcs4
Reconstructed from the shell history on dcs4.onenet and verified against the
live system on 2026-09-09. Every command below was actually run on this host.
| Item | Value |
|---|---|
| Host | dcs4.onenet
|
| OS | Ubuntu 24.04.4 LTS (noble) |
| Running kernel | 7.0.0-30-generic
|
| Card | CAEN A3818 (PCIe, 4× CONET2 optical links) |
| PCI address | 05:00.0
|
| PCI ID | 10ee:1015 (Xilinx vendor, CAEN device); subsystem 10ee:0007
|
| Driver | a3818 v1.6.12, installed via DKMS
|
| DKMS source | /usr/src/a3818-1.6.12
|
| Driver tarball | ~/Desktop/CAEN_Digitizer_Libs/a3818_linux_driver-v1.6.12.tar.gz
|
| Manuals | ~/Desktop/CAEN_Manual/A3818/
|
| Device nodes | /dev/a3818_<N> (see #Device node numbering)
|
Current state: the DKMS module is built for kernel 7.0.0-31-generic,
but the machine is running 7.0.0-30-generic. The module is therefore not loaded
and /dev/a3818_* does not exist. See #Module not loaded after a kernel update.
1. Prerequisites
The A3818 driver is an out-of-tree kernel module built by DKMS, so the toolchain and the headers for the running kernel must be present:
sudo apt update
sudo apt install dkms build-essential linux-headers-$(uname -r)
This was the cause of the first failed install attempt in the history — install.sh
was run before dkms and the kernel headers were present, and the dkms build
step aborted. Install these first.
2. Confirm the card is seen by the bus
Before touching the driver, check that the PCIe card enumerates. The A3818 presents itself as a Xilinx memory controller, not as anything named "CAEN":
lspci -nn | grep 10ee
Expected output on this host:
05:00.0 Memory controller [0580]: Xilinx Corporation Device [10ee:1015]
If this line is absent, stop — the problem is hardware/seating/BIOS, not software. No amount of driver work will help.
3. Unpack the driver
The driver ships inside the CAEN library bundle:
cd ~/Desktop/CAEN_Digitizer_Libs
tar -xvf a3818_linux_driver-v1.6.12.tar.gz
cd a3818_linux_driver-v1.6.12
Contents:
| File | Purpose |
|---|---|
src/a3818.c, src/a3818.h |
Driver source |
install.sh |
DKMS install wrapper (the supported path) |
Makefile |
Manual build (make / sudo make install)
|
dkms.conf.in |
DKMS template; install.sh substitutes the version into dkms.conf
|
dkms_post_add.sh |
Writes /etc/udev/rules.d/10-CAEN-A3818.rules
|
dkms_post_remove.sh |
Deletes that udev rule again |
Readme.txt, ReleaseNotes.txt |
CAEN docs |
If a previously-extracted a3818_linux_driver-v1.6.12/ directory is already
present, delete it before extracting (rm -rf a3818_linux_driver-v1.6.12). A stale
tree with a half-written dkms.conf will make install.sh fail in
confusing ways.
4. Install the driver
chmod +x install.sh
sudo ./install.sh
Must be run as root — the script writes to /usr/src and calls dkms.
What install.sh does, in order:
- Generates
dkms.conffromdkms.conf.inwithVERSION=1.6.12. rmmod a3818(ignored if not loaded).dkms uninstall/dkms remove a3818/1.6.12 --allto clear any prior install.- Copies the tree to
/usr/src/a3818-1.6.12. dkms add→dkms build→dkms install --force.modprobe a3818.
Because dkms.conf.in sets AUTOINSTALL=yes, DKMS will rebuild the module
automatically for each new kernel installed by apt from this point on.
Manual (non-DKMS) alternative
Only if DKMS is unavailable. Note this build will not survive a kernel update:
make
sudo make install
# and to reverse it:
sudo make uninstall
5. Verify the module loaded
lsmod | grep a3818
dkms status
dkms status should report the module as installed for the running kernel:
a3818/1.6.12, 7.0.0-31-generic, x86_64: installed
Kernel messages from the probe:
sudo dmesg | grep -i a3818
# CAEN PCIe: N device(s) found.
dkms status prints Deprecated feature: REMAKE_INITRD. This comes
from CAEN's dkms.conf and is harmless — the A3818 module is not needed in the initrd.
The driver also registers a proc entry:
cat /proc/a3818
6. udev rule for non-root access
By default the character devices are root-owned, so CoMPASS and any user-space program using
CAENComm would need sudo. The driver registers a device class named
a3818 and creates nodes a3818_<N> under it, so a udev rule can widen
the permissions.
The rule in use on this host is /etc/udev/rules.d/99-caen-a3818.rules:
sudo nano /etc/udev/rules.d/99-caen-a3818.rules
# CAEN A3818 PCIe CONET2 controller - open access to all local users SUBSYSTEM=="a3818", KERNEL=="a3818_*", MODE="0666"
Reload and re-trigger:
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=a3818
ls -l /dev/a3818_0
Relationship to CAEN's own rule
dkms_post_add.sh writes its own rule at /etc/udev/rules.d/10-CAEN-A3818.rules:
KERNEL=="a3818_[0-9]", MODE="0666" KERNEL=="a3818_[0-9][0-9]", MODE="0666"
and dkms_post_remove.sh deletes it again. Because install.sh runs
dkms remove before dkms add, a re-install cycle can leave this file
missing — and indeed it is not present on dcs4 right now; only the hand-written
99- rule exists. The 99- rule is the more robust of the two (it matches
any index, not just one or two digits), so keeping it is deliberate. If you ever reinstall the
driver and find both files, that is fine — they set the same mode.
MODE="0666" grants read/write on the card to every local user. That is
acceptable on a dedicated DAQ box like dcs4. On a shared machine, prefer
GROUP="caen", MODE="0660" and add DAQ users to a caen group.
7. Device node numbering
The driver computes the minor number, and hence the node name, as:
index = (CardNumber << 6) + (OpticalLink << 3) + V2718Slave /dev/a3818_<index>
| Node | Card | Link | Slave |
|---|---|---|---|
/dev/a3818_0 |
0 | 0 | 0 |
/dev/a3818_8 |
0 | 1 | 0 |
/dev/a3818_16 |
0 | 2 | 0 |
/dev/a3818_24 |
0 | 3 | 0 |
/dev/a3818_64 |
1 | 0 | 0 |
So a single A3818 with its four CONET2 links produces nodes at 0, 8, 16 and 24 (plus the daisy-chain
slave offsets in between). When a CAENComm/CAENDigitizer program asks for "link 0", it opens
/dev/a3818_0.
8. CAEN user-space libraries
The kernel driver alone is not enough — CoMPASS and any DAQ code need the CAEN shared libraries. These are installed by the bundle's own script:
cd ~/Desktop/CAEN_Digitizer_Libs
chmod +x Install_libraries.sh
sudo ./Install_libraries.sh
It installs build dependencies (build-essential, libusb-1.0-0-dev,
qt6-base-dev, libqt6charts6-dev, libcurl4-openssl-dev,
libboost-all-dev, libgl1-mesa-dev) and then builds, in order:
| Library | Version on dcs4 | Installed to |
|---|---|---|
| CAENVMELib | v4.1.3 | /usr/lib/libCAENVME.so
|
| CAENComm | v1.8.0 | /usr/lib/libCAENComm.so
|
| CAENDigitizer | v2.19.0 | /usr/lib/libCAENDigitizer.so
|
| CAEN FELib | v1.3.2 | /usr/local/lib/libCAEN_FELib.so
|
| CAEN Dig2 | v1.8.3 | /usr/local/lib/libCAEN_Dig2.so
|
| CAEN Dig1 (binary) | v1.1.4 | /usr/local/lib/libCAEN_Dig1.so
|
Verify:
ldconfig -p | grep -i caen
Useful flags at the top of Install_libraries.sh:
INSTALL_A4818=false— set true only if the USB A4818 bridge is also in use. Not needed for the A3818.BOOST_PATH=""— point at a manually-extracted Boost if the system Boost is too new forcaen_dig2.sudo ./Install_libraries.sh clean— removes the extracted source directories but keeps the tarballs.
The A3818 kernel driver is deliberately not handled by Install_libraries.sh.
It is installed separately, as in #4. Install the driver.
9. Troubleshooting
Module not loaded after a kernel update
This is the current state of dcs4. Symptoms: lsmod | grep a3818 is empty,
modinfo a3818 says "Module a3818 not found", /dev/a3818_* does not exist —
yet lspci still shows the card.
Cause: DKMS built the module for the newest installed kernel, not the running one:
dkms status
# a3818/1.6.12, 7.0.0-31-generic, x86_64: installed
uname -r
# 7.0.0-30-generic
Two fixes:
# Preferred: reboot into the kernel the module was built for
sudo reboot
# Or build for the currently running kernel (headers for it are installed)
sudo dkms install a3818/1.6.12 -k $(uname -r) --force
sudo modprobe a3818
Confirm afterwards with lsmod | grep a3818 and ls -l /dev/a3818_0.
"Operation not allowed" when inserting the module
Secure Boot is enabled and the kernel is rejecting the unsigned out-of-tree module. Either sign
the module with an enrolled MOK, or disable Secure Boot in the BIOS. See the N.B. in CAEN's
Readme.txt.
dkms build fails
Almost always missing headers for the running kernel:
sudo apt install dkms build-essential linux-headers-$(uname -r)
Then re-run sudo ./install.sh. The build log is at
/var/lib/dkms/a3818/1.6.12/build/make.log.
No /dev/a3818_* even though the module is loaded
The driver only registers the char device if the PCI hardware is found — this is deliberate,
to avoid a kernel crash on cat /proc/devices. Check lspci -nn | grep 10ee
and sudo dmesg | grep -i a3818 for the "CAEN PCIe: N device(s) found." line.
Permission denied opening the card from a user program
The udev rule is missing or was not applied. Re-run:
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=a3818
ls -l /dev/a3818_0 # should be crw-rw-rw-
10. Quick reference
# Is the card on the bus?
lspci -nn | grep 10ee
# Is the driver loaded and built for this kernel?
lsmod | grep a3818
dkms status
uname -r
# Device nodes and permissions
ls -l /dev/a3818_*
cat /proc/a3818
# Reload the module
sudo rmmod a3818 && sudo modprobe a3818
# Reapply udev rules
sudo udevadm control --reload-rules
sudo udevadm trigger --subsystem-match=a3818
# Rebuild for the running kernel
sudo dkms install a3818/1.6.12 -k $(uname -r) --force
# Full reinstall from source
cd ~/Desktop/CAEN_Digitizer_Libs/a3818_linux_driver-v1.6.12 && sudo ./install.sh
# Remove entirely
sudo dkms uninstall a3818/1.6.12
sudo dkms remove a3818/1.6.12 --all
# CAEN user-space libraries
ldconfig -p | grep -i caen
See also
~/Desktop/CAEN_Manual/A3818/— CAEN A3818 hardware manual~/Desktop/CAEN_Digitizer_Libs/UM1934_CAENComm_User_Manual_rev.9.pdf~/Desktop/CAEN_Digitizer_Libs/UM1935_CAENDigitizer Library_rev.22.pdf~/Desktop/CAEN_Digitizer_Libs/UM7715_CAENVMELib_User_Manual_rev.2.pdf
Software
Inventory and setup notes for the analysis / DAQ / monitoring software on
dcs4.onenet. Reconstructed from the shell history and verified against the live
system on 2026-09-09.
Four of the seven packages below are not yet installed. The status column is the short answer; each section gives the install procedure either way. See #Installation status.
Installation status
| Software | Purpose | Version |
|---|---|---|
| CERN ROOT | Analysis framework | 6.36.06 |
| InfluxDB 3 Core | Time-series database | 3.11.2 |
| Grafana | Dashboards | 13.2.1 Enterprise |
| CoMPASS | CAEN turnkey DAQ | v2.6.4 available |
| FSUDAQ | DAQ for 1st-gen CAEN digitizers | — |
| SOLARIS DAQ | DAQ for 2nd-gen CAEN digitizers | — |
| ELOG client | Electronic logbook | 3.1.5 upstream |
The CAEN A3818 driver and user-space libraries that the DAQ programs depend on are documented separately — see the A3818 page.
Dependency map
A3818 kernel driver (v1.6.12, DKMS)
|
+-------------------------+-------------------------+
| | |
CAENVMELib 4.1.3 CAEN FELib 1.3.2 (USB / A4818)
CAENComm 1.8.0 CAEN Dig2 1.8.3
CAENDigitizer 2.19.0 CAEN Dig1 1.1.4
| |
FSUDAQ SOLARIS DAQ ------> ROOT (EventBuilder only)
CoMPASS (bundles its own ROOT + Qt + JDK)
| |
+---------> InfluxDB 3 <--+ ---------> Grafana
+---------> ELOG <--------+
Both FSUDAQ and SOLARIS DAQ can push scaler rates to InfluxDB and post entries to ELOG, which is why those four pieces belong on one page.
CERN ROOT
| Item | Value |
|---|---|
| Version | 6.36.06 |
| Install path | /opt/root_v6.36.06, with /opt/root as a symlink
|
| Distribution | Official pre-built binary, ubuntu24.04-x86_64-gcc13.3
|
| Activated by | source /opt/root/bin/thisroot.sh in ~/.bashrc (line 159)
|
Build dependencies
ROOT is installed from the pre-built binary, so these are not strictly required to run it — but they are needed to compile anything against ROOT, and were installed here:
sudo apt install binutils cmake dpkg-dev g++ gcc libssl-dev git libx11-dev libxext-dev \
libxft-dev libxpm-dev python3 libtbb-dev libvdt-dev libgif-dev
sudo apt install gfortran libpcre3-dev libglu1-mesa-dev libglew-dev libftgl-dev libfftw3-dev \
libcfitsio-dev libgraphviz-dev libavahi-compat-libdnssd-dev libldap2-dev python3-dev \
python3-numpy libxml2-dev libkrb5-dev libgsl-dev qtwebengine5-dev nlohmann-json3-dev \
libmysqlclient-dev libgl2ps-dev liblzma-dev libxxhash-dev liblz4-dev libzstd-dev \
libcurl4-openssl-dev
Install
cd ~/Downloads
tar -xvf root_v6.36.06.Linux-ubuntu24.04-x86_64-gcc13.3.tar.gz
mv root root_v6.36.06
sudo mv root_v6.36.06 /opt/.
cd /opt
sudo ln -s root_v6.36.06 root
The versioned directory plus a root symlink is deliberate: upgrading means
unpacking the new version alongside and re-pointing the symlink, with no change to
~/.bashrc and an instant rollback if the new build misbehaves.
Environment
In ~/.bashrc:
#================================== CERN ROOT
source /opt/root/bin/thisroot.sh
This sets ROOTSYS, PATH, LD_LIBRARY_PATH and
PYTHONPATH. Reload with rebash (alias for source ~/.bashrc).
Verify
root-config --version # 6.36.06
root-config --features
root -l -q # starts and exits cleanly
Features compiled into this build include pyroot, dataframe,
roofit, tmva (with tmva-cpu, tmva-sofie),
fftw3, fitsio, spectrum, unfold,
gdml, opengl, http, sqlite,
fortran and cxx17. Cling and LLVM are the builtin versions.
ELOG client
PSI's Electronic Logbook. Both FSUDAQ and SOLARIS DAQ can post run entries to an ELOG server, using
the elog command-line client. Current upstream version is 3.1.5.
Not installed, and not installable via apt on this machine. FSUDAQ's README says
sudo apt install elog, which was correct on Ubuntu 22.04. The elog
package does not exist in Ubuntu 24.04 (noble) — apt-cache policy elog returns
nothing here even though universe is enabled. It must be built from source.
Build from source
sudo apt install cmake build-essential git
git clone https://gitea.psi.ch/ELOG/elog --recursive
cd elog
mkdir build && cd build
cmake ..
make
This produces two binaries in the build directory:
| Binary | Role |
|---|---|
elog |
Command-line client — this is the one FSUDAQ/SOLARIS need |
elogd |
The logbook server daemon |
There is no make install target; place the binaries manually:
sudo cp elog /usr/local/bin/
# only if this host is also to run the logbook server:
sudo cp elogd /usr/local/sbin/
Upstream uses no release tags — build from master.
dcs4 only needs the client if the logbook lives on another machine. Decide that before
setting up elogd, a config file and a systemd unit.
Client usage
elog -h <host> -p <port> -l <logbook> -u <user> <password> \
-a Author="Ryan" -a Type="Run" -a Run=123 \
"Run 123 started, 4 digitizers armed"
The same host/port/logbook/user/password values go into lines 5–8 of FSUDAQ's
programSettings.txt.
Docs: https://elog.psi.ch/elog/ · PDF manual:
https://elog.psi.ch/elog/pdf/document.pdf
InfluxDB 3 Core
Time-series database, used as the sink for scaler rates and slow-control data from the DAQ, and as Grafana's data source.
There is already a full operations document for this at ~/influx.md —
tokens, databases, writing, querying, deletion limitations, troubleshooting. This section is only
the summary. Read that file for anything beyond the basics: mdless ~/influx.md.
| Item | Value |
|---|---|
| Product | InfluxDB 3 Core 3.11.2 |
| Binary | ~/.influxdb/influxdb3
|
| Data dir | ~/.influxdb (object store: local file)
|
| Node ID | dcs4.onenet-node
|
| HTTP API | http://0.0.0.0:8181
|
| Service | influxdb.service — enabled, active
|
| Runs as | adminrt
|
| Admin token | ~/influx.token (mode 600)
|
| Databases | MUSIC, _internal
|
Install
curl -O https://www.influxdata.com/d/install_influxdb3.sh && sh install_influxdb3.sh
source ~/.bashrc
rm install_influxdb3.sh
influxdb3 create token --admin # save the output to ~/influx.token
Environment
In ~/.bashrc:
#================================== influxDB 3
export PATH="$PATH:/home/phy/adminrt/.influxdb/"
export INFLUXDB3_AUTH_TOKEN=$(sed -n 's/^Token: //p' ~/influx.token)
With INFLUXDB3_AUTH_TOKEN exported, the CLI needs no --token flag.
Service
/etc/systemd/system/influxdb.service:
[Unit]
Description=InfluxDB 3 Core Database Server
Documentation=https://docs.influxdata.com/influxdb3/core/
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=adminrt
Group=adminrt
LimitNOFILE=65536
EnvironmentFile=-/etc/default/influxdb3
ExecStart=/home/phy/adminrt/.influxdb/influxdb3 serve \
--node-id dcs4.onenet-node \
--object-store file \
--data-dir /home/phy/adminrt/.influxdb \
--http-bind 0.0.0.0:8181
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Quick commands
sudo systemctl status influxdb.service
curl -i http://localhost:8181/health # 401 without a token — that means it IS running
influxdb3 show databases
influxdb3 create database MUSIC
influxdb3 write -d MUSIC "testing value=1"
An unauthenticated GET /health returns 401 Unauthorized, not 200. That is
the expected healthy response — it proves the server is up and enforcing auth. Pass
-H "Authorization: Bearer $INFLUXDB3_AUTH_TOKEN" for a 200.
This is InfluxDB 3, not 1.x or 2.x. The daemon is influxdb3 serve, not
influxd, and 1.x/2.x guides do not apply. This matters for FSUDAQ, which was written
against 1.8 — see the warning in #FSUDAQ.
Grafana
Dashboards over the InfluxDB data.
| Item | Value |
|---|---|
| Package | grafana-enterprise 13.2.1 (.deb)
|
| Binary | /usr/sbin/grafana-server
|
| Config | /etc/grafana/grafana.ini
|
| Data | /var/lib/grafana
|
| Share | /usr/share/grafana
|
| Service | grafana-server.service — enabled, active
|
| Web UI | http://dcs4.onenet:3000
|
Install
sudo apt-get install -y adduser libfontconfig1 musl
cd ~/Downloads
wget https://dl.grafana.com/grafana-enterprise/release/13.2.1/grafana-enterprise_13.2.1_33191028959_linux_amd64.deb
sudo dpkg -i grafana-enterprise_13.2.1_33191028959_linux_amd64.deb
sudo systemctl daemon-reload
sudo systemctl enable --now grafana-server.service
sudo systemctl status grafana-server.service
The grafana-enterprise package is the same binary as OSS Grafana; the
enterprise features simply stay locked without a licence. No licence is installed here, so this is
functionally the free build.
Configuration
/etc/grafana/grafana.ini is entirely at defaults — every line is commented out.
That means port 3000, no TLS, and the stock admin/admin credentials with
a change prompt at first login.
Change the admin password at first login. With the config untouched, Grafana is listening
on 0.0.0.0:3000 with default credentials.
Verify
sudo systemctl status grafana-server.service
curl -s http://localhost:3000/api/health
# {"database":"ok","version":"13.2.1", ...}
Connecting to InfluxDB 3
Not yet provisioned — /etc/grafana/provisioning/datasources/ contains only the
stock sample.yaml. To add the data source through the UI:
- Type: InfluxDB
- Query language: SQL (InfluxDB 3 native; not InfluxQL or Flux)
- URL:
http://localhost:8181 - Database:
MUSIC - Token: Ask Ryan.
No need to use HTTP headers
CoMPASS
Source: CAEN SpA. Installed at ~/CoMPASS-v2.6.4, extracted from the tarball kept in ~/Desktop/CAEN_Digitizer_Libs/.
CAEN's multiparametric acquisition program. It is a sealed appliance: unpack, run, and take data — at the cost of being unable to change anything about how the data is processed.
| Version | Bundled JDK | Plotter | Install |
|---|---|---|---|
| v2.6.4, January 2026 | jdk-21.0.2 | Qt 5.15.2 + ROOT 6.28.06 | Extract in place, no compile |
How CoMPASS was installed here
Extract and move. Nothing else.
cd ~/Desktop/CAEN_Digitizer_Libs tar -xvf CoMPASS-v2.6.4.tar.gz mv CoMPASS-v2.6.4 ~/ cd ~/CoMPASS-v2.6.4 ./CoMPASS
install.sh was deliberately not run on this machine. It only does two things, both optional:
- symlinks the launcher to
/usr/local/bin/CoMPASSso it is on$PATH— we run./CoMPASSfrom the folder instead; - copies
a4818.rulesto/etc/udev/rules.dand reloads udev, so an A4818 optical-USB adaptor is reachable without root — irrelevant while the digitizers are on Ethernet.
Run sudo ./install.sh only if you want one of those. Uninstalling is deleting the folder either way; there is no package manager state to unwind.
The older tarballs (CoMPASS-v2.1.1, v2.2.1) are still in CAEN_Digitizer_Libs/. Versions are fully parallel — extract one elsewhere and run it directly if you need to compare behaviour.
The g++-11 problem
This is the one thing that will stop a fresh CoMPASS on Ubuntu 24.04, and the launcher's own version check does not catch it.
Symptom. CoMPASS starts, the main window appears, but the plot window never does. ~/Compass/logs/log.0.txt reports Process CoMPASSPlot has been terminated with exit value 139 (SIGSEGV) followed by a Java IllegalStateException. The DPP server is fine — CAENDPPServerLog.txt shows it binding its ports and accepting the client, then logging a clean Client disconnection when the plotter takes the app down. CoMPASSPlotLog.txt contains only its logger-init line; the plotter dies before writing anything else.
Root cause. The ROOT/cling build bundled in plot/linux/ was compiled on Ubuntu 22.04 against GCC 11, and it hardcodes the compiler name x86_64-linux-gnu-g++-11 to discover the C++ standard-library include paths at runtime:
LC_ALL=C x86_64-linux-gnu-g++-11 -xc++ -E -v /dev/null 2>&1 | sed -n ...
On Ubuntu 24.04 that binary does not exist — only g++ 13.3.0 and /usr/include/c++/13. The pipeline still exits 0, because sed succeeds even though the compiler was not found, so cling never bails out cleanly. It proceeds with an empty include list, builds a VFS overlay entry with 'name': , and segfaults in llvm::vfs::OverlayFileSystem::pushOverlay(), inside plot/linux/lib/libCling.so.
The stack trace in log.0.txt shows the whole chain:
main -> RootApplication::RootApplication() -> TApplication::TApplication() -> TROOT::InitInterpreter() -> CreateInterpreter() [libCling.so] -> cling::Interpreter::Interpreter() -> cling::IncrementalParser::IncrementalParser() -> cling::CIFactory::createCI() -> setupCxxModules(clang::CompilerInstance&) -> collectModuleMaps(...) -> llvm::vfs::OverlayFileSystem::pushOverlay(...) <-- SEGFAULT
Fix.
sudo apt install g++-11
This provides /usr/bin/x86_64-linux-gnu-g++-11 and /usr/include/c++/11, exactly what cling probes for. It installs alongside GCC 13 and does not change the system default compiler.
Why the launcher does not catch this. The CoMPASS script checks g++ -dumpfullversion against a minimum of 11.4.0. GCC 13.3.0 passes that check comfortably, so the launcher proceeds — while the thing cling actually needs, a binary literally named g++-11, is missing. The version check and the runtime dependency are testing different things.
If g++-11 alone does not fix it
ROOTSYS=/opt/root is set in the environment here, and /opt/root/lib gets appended to the LD_LIBRARY_PATH CoMPASS builds for itself. CoMPASS's own plot/linux/lib comes first so it should win, but a separate ROOT install can still feed the wrong etc/ modulemaps into collectModuleMaps. Next test:
env -u ROOTSYS ./CoMPASS
Launcher preflight checks
The CoMPASS script refuses to start rather than failing halfway, and each check prints its own reason. All of these currently pass on this machine.
| Requirement | Minimum | How it is checked |
|---|---|---|
| Architecture | x86-64 | uname -m must contain 64
|
| Java | 21 | Bundled JDK, version parsed from -version
|
| g++ | 11.4.0 | g++ -dumpfullversion, compared field by field
|
| glibc | 2.34 | strings on the libc that CAENDPPServer links
|
| glibcxx | 3.4.30 | strings on the libstdc++ that CoMPASSPlot links
|
CoMPASS is three processes, not one
What looks like a single application is a Java front end talking over local TCP to a native back end, plus a separate plotting binary. Knowing this is what makes the logs readable — and it is why a plotter crash leaves a perfectly healthy digitizer log.
| Process | Role | Endpoint |
|---|---|---|
compass-v2.6.4.jar |
Java 21 GUI, run configuration, orchestration | — |
CAENDPPServer |
Native digitizer control and readout | 127.0.0.1:56342 control127.0.0.1:56343 data
|
CoMPASSPlot |
Qt5 + ROOT histogram and waveform display | — |
Those ports are set by the launcher via -Ddpp.server.* flags, and the server is spawned by the JVM (dpp.server.launch=true). If a stale CAENDPPServer is holding 56342, a new CoMPASS will not come up — check ~/Compass/logs/CAENDPPServerPID and kill it.
Library collision. server/linux/ ships CAEN's whole stack — libCAENDigitizer, libCAEN_Dig2, libCAEN_FELib, libCAENComm, libCAENVME — and prepends that directory to LD_LIBRARY_PATH. It is deliberately insulated from the system CAEN libraries that FSUDAQ and SOLARIS_DAQ link against, so the two can disagree on version without either breaking. It also means a system library upgrade does nothing for CoMPASS.
CoMPASS files and logs
The working directory is ~/Compass/, created on first run, and separate from the install directory.
| Path | Contents |
|---|---|
~/Compass/config/ |
Saved project and board configurations |
~/Compass/data/ |
Acquired runs |
~/Compass/logs/log.N.txt |
Java front-end log, rotated; log.0.txt is current — start here
|
~/Compass/logs/CAENDPPServerLog.txt |
Native server — board and link errors |
~/Compass/logs/CAENDPPServerPID |
PID of the running native server |
~/Compass/logs/CoMPASSPlotLog.txt |
Plotter, including ROOT complaints |
Documentation ships in the install folder rather than online: UM5960_Compass_UserManual_rev27.pdf is the reference manual and GD6300_Compass_QuickStart_rev27.pdf the getting-started guide. Older revisions (rev19–rev23) sit in ~/Desktop/CAEN_Manual/, filed per board. releasenotes.txt carries the full changelog.
FSUDAQ
Source: github.com/goluckyryan/FSUDAQ. Cloned to ~/FSUDAQ.
A Qt6 acquisition system for first-generation CAEN digitizers, with a half-second scope, full register control, and an online analysis layer you are expected to write against.
| Boards | Firmware | Binary | Data format |
|---|---|---|---|
| x725, x725S, x730, V1740 | PHA, PSD, QDC | FSUDAQ_Qt6 |
.fsu
|
Everything on the digitizer is reachable from the settings panel except LVDS. The scope redraws every 500 ms, waveforms can be saved, and each channel carries its own 1D histogram — off by default, switched on in the Online Histograms panel, with the binning persisted to singleSpectaSetting.txt under the raw data path.
FSUDAQ dependencies
The CAEN libraries must be downloaded and installed by hand; the rest come from apt.
| Component | Minimum | Needed for |
|---|---|---|
| CAENVMELib | 3.3 (4.0+ for A5818) | VME access layer |
| CAENComm | 1.5.3 | Link abstraction |
| CAENDigitizer | 2.17.1 | Board control |
| CAEN A3818 driver | 1.6.8 | PCIe optical card |
| CAENUSBdrv | 1.5.5 | V57xx over USB |
| Qt6 + Charts | — | GUI and plots |
| libcurl | — | InfluxDB writes |
| elog | 3.1.3+ | Logbook entries |
sudo apt install qt6-base-dev libqt6charts6-dev libcurl4-openssl-dev elog
QCustomPlot is vendored in the repository, so it is not an external dependency.
Building FSUDAQ
cd ~/FSUDAQ qmake6 FSUDAQ_Qt6.pro # regenerates the Makefile make -j$(nproc) ./FSUDAQ
Re-run qmake6 whenever the .pro changes — notably after adding an analyzer. For a debug build, uncomment QMAKE_CXXFLAGS += -g and the two -O0 lines in the .pro; the program installs an abort handler that writes a core dump, which needs ulimit -c unlimited and a writable core_pattern to land anywhere useful.
Optical link handling
A4818 cabling order. Connect the optical fibre before powering the digitizers on. If a fibre is unplugged and reconnected during a session, the digitizers must be power-cycled — reconnecting alone will not restore the link.
A Raspberry Pi 5 with 8 GB and an A4818 is a tested configuration; all the CAEN libraries build for ARM. On Pi, substitute qt6-chart-dev for libqt6charts6-dev, and install elog by hand or skip it.
FSUDAQ settings and data
programSettings.txt sits beside the binary and is read line by line — position is the only key, so blank lines are meaningful placeholders and must be kept. The copy in ~/FSUDAQ is currently blank throughout, so no data path, InfluxDB or elog is configured.
| # | Field | Effect if empty |
|---|---|---|
| 1 | raw data path | Can still run ACQ, but cannot save a run |
| 2 | InfluxDB IP | InfluxDB logging disabled |
| 3 | database name | |
| 4 | InfluxDB token (v2.0+) | |
| 5 | elog IP | elog disabled |
| 6 | elog logbook | |
| 7 | elog user | |
| 8 | elog password |
With no settings file at all, FSUDAQ still starts and still discovers every digitizer on the optical link. Degradation is graceful and per-feature.
What lands in the data path
| File | Purpose |
|---|---|
*.fsu |
Raw acquired data |
*.bin |
Digitizer settings snapshot for the run |
RunTimestamp.dat |
Start/stop times and comments for every run |
RunTimestamp.csv |
The same, for a spreadsheet |
lastRun.sh |
Last-run values exported for shell scripts |
singleSpectaSetting.txt |
Per-channel histogram binning |
Compiled-in limits
| Limit | Value |
|---|---|
| Digitizers | 16 (4 ports × 4 boards) |
| Channels | 64 |
| Record length | 0x3FFF × 8 |
| Max file size | 2 GB |
| Buffer per channel | 10,000 events |
| Traces per event | 5 |
| Scope refresh | 200 ms |
| Scaler refresh | 1,000 ms |
Keyboard control
The panels are fully keyboard-drivable, which matters when the DAQ box is on a KVM at the far end of a hall.
| Key | Action |
|---|---|
F4 |
Open the focused drop-down |
Tab / Ctrl+Tab |
Next / previous element |
Space |
Press the focused button |
↑ / ↓ |
Increment / decrement a number |
Alt+Tab |
Switch between DAQ windows |
Field colour is state, not decoration: blue means the value has been typed but not yet pushed to the board; red means the board rejected it.
FSUDAQ online analyzers
Read this before debugging empty spectra. No events are built when FSUDAQ starts. The MultiBuilder only begins once an online analyzer has been created and opened — and once it has, event building continues even if you close the analyzer window. An empty coincidence spectrum usually means nobody opened an analyzer, not that the physics is wrong.
MultiBuilder correlates hits across several digitizers. It builds forward in the usual way, and also backward — from the most recent data back through a fixed number of events — which is what lets the online plots stay responsive at high rate instead of lagging behind the front of the buffer.
Above that sit 1D and 2D histograms with graphical cuts that can be drawn, named, and renamed, and whose rates can be pushed to InfluxDB.
Analyzers in the repository
| Header | Purpose |
|---|---|
Analyser.h |
Base class — subclass this |
SplitPoleAnalyzer.h |
Reference example: a 2D and a 1D histogram, plus cut rates to InfluxDB |
CoincidentAnalyzer.h |
Coincidence conditions |
MUSICAnalyzer.h |
MUSIC detector |
NeutronGamma.h |
n/γ pulse-shape discrimination |
EncoreAnalyzer.h |
Encore array |
RAISOR.h |
RAISOR separator |
Isotope.h, Cross.h |
Mass table (mass20.txt) and kinematics helpers
|
Adding your own analyzer
Derive from Analyser.h, then wire it into four places — the analyzer will not appear in the menu until all four are done:
- Add the source file to
FSUDAQ_Qt6.pro. - Include the header at the top of
FSUDAQ.cpp. - Add an entry to the
onlineAnalyzerListvector, also at the top ofFSUDAQ.cpp. - Handle it in
FSUDAQ::OpenAnalyzer().
qmake6 FSUDAQ_Qt6.pro make
FSUDAQ known issues
These are documented upstream and are worth reading as operating procedure rather than as a bug list.
Aggregation settings will hang the board
Correlated registers. Aggregate Organization, Events per Aggregate and Record Length constrain one another. Invalid combinations are accepted by the panel and then send the digitizer into an unrecoverable state. When using the scope, Agg/Read must stay below 512.
For PHA firmware, Events-per-Aggregate is recomputed through the CAEN API before ACQ starts, but that calculation assumes the current rate — if the trigger rate changes substantially mid-experiment, it needs setting again by hand. Trapezoid scaling and the fine-gain register are likewise computed at ACQ start.
Everything else
| Symptom | Cause / action |
|---|---|
| Negative trigger or accept rate | Buffer arriving out of time order. A digitizer settings problem, not a program bug — reprogram the board. |
| Pile-up rate looks wrong | Inaccurate above roughly 60 kHz input. |
| GUI stalls | Database access is slow. Disable InfluxDB. |
| Loaded settings look incomplete | Expected. Loading restores channel settings and some board settings only. |
| V1740D QDC: ReadData error, ACQ stops | When the first channel group is enabled, channel 0 must also be enabled. |
| V1740 QDC record length behaves oddly | Record length is a board-level setting, but readout is per group. |
EventBuilder crashes offline |
Known: very high trigger rates in the data. |
SOLARIS_DAQ
Source: github.com/goluckyryan/SOLARIS_DAQ. Cloned to ~/SOLARIS_DAQ.
Built for the SOLARIS solenoidal spectrometer at FRIB and the x2730-series digitizers. Second-generation boards speak Ethernet and a REST-like endpoint model rather than VME registers, and the program is structured around that difference.
| Boards | Firmware | Max digitizers | Data format |
|---|---|---|---|
| VX2730, VX2740, VX2745 | DPP-PHA, DPP-PSD | 20 | .sol
|
The digitizer control classes are deliberately independent of the Qt layer, so the same core can be driven from the auxiliary command-line tools without dragging in a GUI.
Core, independent of Qt
| File | Role |
|---|---|
ClassDigitizer2Gen.h/cpp |
Connection, configuration, readout, file I/O |
Hit.h |
Decoded event structure |
RawDecoder.h |
Unpacks the raw endpoint blob into hits |
DigiParameters.h |
Register definitions for both firmwares |
RingBuffer.h |
Lock-free circular buffer for per-channel spectra |
Qt layer
| File | Role |
|---|---|
mainwindow.h/cpp |
Digitizer management, run control, scalers |
digiSettingsPanel.h/cpp |
Board and channel register editor |
scope.h/cpp |
Waveform display |
SingleSpectra.h/cpp |
Per-channel energy spectra |
SOLARISpanel.h/cpp |
SOLARIS detector mapping and configuration |
CustomThreads.h |
ReadDataThread and TimingThread
|
ClassElog.cpp, ClassInfluxDB.cpp |
Logbook entries and scaler-rate logging |
Building SOLARIS_DAQ
cd ~/SOLARIS_DAQ qmake6 SOLARIS_DAQ.pro make -j$(nproc) ./SOLARIS_DAQ
Missing header. CAENDig2.h is not installed to the system include path by the CAEN Dig2 package. Copy it out of the source tree before the first build:
sudo cp caen_dig2-vXXXX/include/CAENDig2.h /usr/local/include/
Tested against V2740 and V2745 DPP-PHA-1G and DPP-PSD-1G, and VX2730 DPP-PSD from firmware 2025052203.
SOLARIS readout formats
Chosen through SetDataFormat(). Each step down the table drops metadata in exchange for bandwidth, and the choice is the single biggest lever on sustainable rate.
| Format | ID | Carries |
|---|---|---|
ALL |
0x00 |
All metadata, 2 analog probes, 4 digital probes |
OneTrace |
0x01 |
1 analog probe + energy, timestamp, flags |
NoTrace |
0x02 |
Energy, timestamp, flags — no waveform |
Minimum |
0x03 |
Channel, energy, timestamp |
MiniWithFineTime |
0x04 |
As above plus fine timestamp |
Raw |
0x0A |
Undecoded blob, unpacked in software |
What a decoded hit holds
| Field | Width | Units |
|---|---|---|
| channel | 6 bit | — |
| energy | 16 bit | ADC |
| energy_short | 16 bit | ADC — PSD only |
| timestamp | 48 bit | ns |
| fine_timestamp | 10 bit | ps |
| flags, high / low priority | 8 / 12 bit | — |
| analog probes ×2 | 18 bit/sample | — |
| digital probes ×4 | 1 bit/sample | — |
What SOLARIS_DAQ pushes to InfluxDB
Six measurements, in two groups. Points accumulate in one buffer and are flushed as a single HTTP POST per tick, so a 64-channel board sends 128 points every 2 s in one request. No timestamps are sent on any point — the server stamps them at write time.
Continuous, one batch every 2 s
| Measurement | Tags | Field | Source |
|---|---|---|---|
Rate |
Bd=<serial>, Ch=<NN> |
value |
PHA::CH::SelfTrgRate, read straight off the board
|
AccpRate |
Bd=<serial>, Ch=<NN> |
value |
Computed in software — see below |
FileSize |
— | value |
Sum of GetTotalFilesSize() across all digitizers, in bytes
|
Ch is zero-padded to two digits (mainwindow.cpp:1372). The 2 s cadence is TimingThread's default of 20 × 100 ms — the SetWaitTimeSec call at mainwindow.cpp:78 is commented out, so it is never overridden. FileSize is additionally gated on the Save Run checkbox (mainwindow.cpp:1380).
Event-driven
| Measurement | Tags | Fields | Fires on |
|---|---|---|---|
ProgramStart |
— | value=1 |
InfluxDB setup succeeding — doubles as the write test |
ProgramStart |
— | value=0 |
Program exit |
StartStop |
— | value=1 or 0 |
Run start / stop; also scope open, and the scope's ACQ toggle |
RunID |
start=1 |
value=<runID>, expName, comment |
Run start |
RunID |
start=0 |
value=<runID>, expName, comment |
Run stop, new experiment, experiment switch |
Spaces in comments are replaced with underscores before writing.
Two gates that silently stop the rate data
The Scaler window must be open. UpdateScalar() begins with if( scalar->isVisible() == false ) return; (mainwindow.cpp:1318), before any InfluxDB work happens. Close that window and Rate, AccpRate and FileSize stop dead — with no warning, and with RunID and StartStop still flowing normally because they sit on separate code paths. A Grafana panel can therefore go flat while the run looks perfectly healthy.
The second gate is scalarOutputInflux, set true at run start and false at run stop (mainwindow.cpp:525, 589), so the continuous group only flows during a run.
How AccpRate differs from Rate
Rate is the firmware's self-trigger rate register, and does not apply the coincidence condition.
AccpRate is derived (mainwindow.cpp:1346-1350):
(ChannelSavedCount delta) * 1e9 / (ChannelRealtime delta)
but only when the realtime delta exceeds 1e9 ns and the saved count actually increased. Otherwise it is forced to 0 — so expect genuine zeros on the first tick or two after starting, and on any quiet channel, rather than a gap in the series.
A VX2730 quirk sits immediately above it: ChannelRealtime is divided by 4 because the register is not in ns on that model.
Setup preconditions
SetupInflux() (mainwindow.cpp:2460) refuses to connect unless all of the following hold. If any fails, the influx object is deleted and nothing is ever pushed:
- Both
DatabaseIPandDatabaseNameare non-empty. TestingConnection()succeeds.- If the server reports version > 1, a token is set. The configuration here is
apiv3_…againstlocalhost:8181, so this branch is live and the token is mandatory. - The database already exists. It is matched against the list returned by
CheckDatabases(). DespiteCreateDatabase()existing inClassInfluxDB, it is never called —MUSIChas to be there beforehand.
One latent inconsistency, which cannot bite with current hardware: the register-read loop clamps to MaxNumberOfChannel (64), but the InfluxDB loop at mainwindow.cpp:1371 iterates GetNChannels() unclamped. Every x2730-series board is 64 channels or fewer, so the two agree today; a wider board would read past the haha[] array.