let
    mozillaOverlay = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
    pkgs = import <nixpkgs> {overlays = [mozillaOverlay];};
in with pkgs;
let
    migen = callPackage ./nix/migen.nix {};
    openocd = callPackage ./nix/openocd.nix {};
    rustPlatform = callPackage ./nix/rustPlatform.nix {};
    itm = callPackage ./nix/itm.nix {inherit rustPlatform;};

    runOpenOcdBlock = writeShellScriptBin "run-openocd-block" ''
        openocd -f openocd/openocd.cfg
    '';

    openocdFlash = writeShellScriptBin "openocd-flash" ''
        openocd -f openocd/openocd.cfg -f openocd/main.cfg
    '';

    publishMqtt = writeShellScriptBin "publish-mqtt" ''
        mosquitto_pub -h localhost -t $1 -m "$2" -d
    '';

    openOCDFlashCustomised = writeShellScriptBin "openocd-flash-customised" ''
        python3 flash.py $1 $2 $3 $4
        openocd -f openocd/openocd.cfg \
                -c "init 
                    reset init 
                    halt 
                    stm32h7x mass_erase 1 
                    flash write_image erase target/thumbv7em-none-eabihf/release/humpback-dds 
                    flash write_image flash_config.bin 0x08100000 bin 
                    reset run 
                    shutdown"
    '';

in
    stdenv.mkDerivation {
        name = "Humpback-DDS";
        buildInputs = with rustPlatform.rust; [
            (pkgs.python3.withPackages(ps: [ migen ]))
            pkgs.yosys
            pkgs.nextpnr
            pkgs.icestorm
            pkgs.gdb
            pkgs.mosquitto
            openocd
            rustc
            cargo
            itm
            runOpenOcdBlock
            openocdFlash
            publishMqtt
            openOCDFlashCustomised
        ];
    }