Digilent WaveForms & Adept on NixOS - Unable to Connect Device

The past few days, I have been trying to get WaveForms up and Running on NixOS (Linux distro with declarative builds). So far, the dynamically linked libraries are working, including those from and for the Adept Runtime. The udev rules are also functional and the device is recognized as

Bus 005 Device 002: ID 1443:7003 Digilent Digilent USB Device

which seems to be the AD3 which I am using. However, when I try to connect to my device with WaveForms, the AD3 is not detected. I am now trying to figure out further hidden requirements of WaveForms / Adept that are required to connect to devices. Any help is appreciated and I am willing to share my nix derivation if anyone is interested.

It seems this issue is rather complex since the software comes in two parts:

These two parts of the software interface via a set of libraries contained by the Adept package. Each part itself has additional resources that it comes packaged with. So far, all dynamically linked executables are functional and the WaveForms GUI opens as intended. However, connecting to a device is not possible. Also, it should be noted that the software is only available as .deb packages. This poses the following questions:

  • Which files do the programs require static read access to? Where do they have to be located and is it ok if they are linked?
  • Does WaveForms require read access to shared resources that belong to Adept? How about the other way around?
  • Which files do the programs require static write access to?
  • Does either of both require access to certain system services?
  • Do the two of them truly only interact via the libraries or are there other forms of interaction that need to be available?
  • Are there any unmet non-linked dependencies or missing software?

I think I remember using Waveforms on the AUR a long time ago, might be worth looking into how they do it.

1 Like

Solution (only works for x86_64 (amd64) architecture but can be modified for arm64):

0. Prep:

Download WaveForms and Adept amd64 Debian packages from the Digilent website. We extract the .deb file and repackage it for NixOS.

Preload them into the nix store using

nix-prefetch-url file://path/to/file.deb

If you are using a different version, you will have to update the derivations accordingly including re-calculation of the hash value. You can use

nix-hash --flat --base64 --type sha256 path/to/file.deb

This will also be necessary in case Digilent changes the executable without changing the version number.

You will also need to change the .nix file locations based on where you put them in a few places.

1. Install the udev rule:

Use the following derivation:

{
  pkgs,
  stdenv,
  ...
}: stdenv.mkDerivation rec {
  pname = "digilent-usb-rules";
  version = "0.0";

  dontUnpack = true;

  src = pkgs.writeText "52-digilent-usb.rules" ''
    ATTR{idVendor}=="1443", MODE:="666"
    ACTION=="add", ATTR{idVendor}=="0403", ATTR{manufacturer}=="Digilent", MODE:="666", RUN+="${pkgs.callPackage path/to/adept.nix { }}/bin/dftdrvdtch %s{busnum} %s{devnum}"
  '';

  installPhase = ''
    mkdir -p $out/lib/udev/rules.d;
    cp $src $out/lib/udev/rules.d/52-digilent-usb.rules;
  '';
}

Which we add to the NixOS system config:

services.udev.packages = [
  ( pkgs.callPackage path/to/digilent-usb-rules.nix { } )
];

2. Repackage and patch Adept:

Use the following derivation:

{
  lib,
  pkgs,
  stdenv,
  ...
}: stdenv.mkDerivation rec {
  pname = "Adept";
  version = "2.30.1";

  meta = {
    description = "Communicate with Digilent system boards";
    homepage = "https://digilent.com/reference/software/adept/start";
    license = lib.licenses.unfree;
    platforms = [ "x86_64-linux" ];
  };

  src = pkgs.requireFile rec {
    name = "digilent.adept.runtime_${version}_amd64.deb";
    hash = "sha256-5eUdJkDC/zTvO0NvO983g4EgsVFg1z37q4LpB3O2s3I=";
    message = ''
      Please download Adept ${version} 64-bit .deb and add it to the nix store using
      nix-prefetch-url file://$PWD/${name}.deb
    '';
  };

  nativeBuildInputs = with pkgs; [
    autoPatchelfHook
    binutils
  ];

  buildInputs = with pkgs; [
    stdenv.cc.cc.lib

    avahi
    libusb1
    openssl
  ];

  unpackPhase = ''
    ar x $src
    tar -xf data.tar.gz
  '';

  installPhase = ''
    mkdir -p $out/bin $out/lib/digilent $out/share
    cp -r usr/lib/udev/* $out/bin
    cp -r usr/lib/digilent/adept/* $out/lib
    cp -r usr/share/* $out/share
  '';
}

3. Repackage and patch WaveForms

Use the following derivation:

{
  lib,
  pkgs,
  stdenv,
  ...
}: let
  waveforms = stdenv.mkDerivation rec {
    pname = "WaveForms";
    version = "3.25.1";

    meta = {
      description = "WaveForms is the virtual instrument suite for Digilent Test and Measurement devices";
      homepage = "https://digilent.com/reference/software/waveforms/waveforms-3/start";
      license = lib.licenses.unfree;
      platforms = [ "x86_64-linux" ];
    };

    src = pkgs.requireFile rec {
      name = "digilent.waveforms_${version}_amd64.deb";
      hash = "sha256-0peaq3JskgKkihxdKzFFMVExccC2L6Lyou3NKSAnJ9M=";
      message = ''
        Please download WaveForms ${version} 64-bit .deb and add it to the nix store using
        nix-prefetch-url file://$PWD/${name}.deb
      '';
    };

    nativeBuildInputs = with pkgs; [
      autoPatchelfHook
      binutils
      qt6.wrapQtAppsHook
      zstd
    ];

    buildInputs = with pkgs; [
      stdenv.cc.cc.lib
      ( pkgs.callPackage ./adept.nix { } )

      qt6.qtbase
      qt6.qtconnectivity
      qt6.qtdeclarative
      qt6.qtmultimedia
      qt6.qtserialport
    ];

    unpackPhase = ''
      ar x $src
      tar -xf data.tar.zst
    '';

    installPhase = ''
      mkdir -p $out/bin $out/lib $out/share
      cp -r usr/bin/* $out/bin
      cp -r usr/lib/* $out/lib
      cp -r usr/share/* $out/share
    '';
  };
in pkgs.buildFHSEnv {
  name = "waveforms";

  targetPkgs = pkgs: with pkgs; [
    pipewire

    waveforms
    ( pkgs.callPackage path/to/adept.nix { } )
  ];

  runScript = "waveforms";
}

We use an FHS environment for WaveForms since simply patching the elf-header of WaveForms does not seem to suffice, which points toward a static library call.