~andrew/qmk

qmk/flake.nix -rw-r--r-- 8.9 KiB
cb94b838Andrew Reisner update charybdis keymap. a month ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
{
  description = "QMK Userspace - Personal keyboard firmware configurations";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";

    # Upstream QMK firmware (for Ploopyco and other standard keyboards)
    qmk-firmware = {
      url = "git+https://github.com/qmk/qmk_firmware?submodules=1";
      flake = false;
    };

    # BastardKB QMK fork (for Charybdis RP2040/Splinky UF2 builds)
    bastardkb-qmk-firmware = {
      url = "git+https://github.com/Bastardkb/bastardkb-qmk?ref=refs/heads/bkb-master&submodules=1";
      flake = false;
    };

    # ZSA fork of QMK firmware (for Voyager, Moonlander, Planck EZ, Ergodox EZ)
    zsa-qmk-firmware = {
      url = "git+https://github.com/zsa/qmk_firmware?submodules=1";
      flake = false;
    };

    # Holykeebs fork of QMK firmware (for Keyball keyboards)
    keyball-qmk-firmware = {
      url = "git+https://github.com/holykeebs/qmk_firmware?submodules=1";
      flake = false;
    };
  };

  outputs = { self, nixpkgs, flake-utils, qmk-firmware, zsa-qmk-firmware, keyball-qmk-firmware, bastardkb-qmk-firmware }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs {
          inherit system;
          config.allowUnfree = true;
        };

        # Common QMK build dependencies
        qmkBuildInputs = with pkgs; [
          # AVR toolchain (for ATmega-based keyboards like Ploopyco)
          pkgsCross.avr.buildPackages.gcc
          avrdude

          # ARM toolchain (for ARM-based keyboards like Voyager, Keyball)
          gcc-arm-embedded

          # Build tools
          gnumake
          git
          which
          diffutils
          util-linux

          # Python with QMK dependencies
          (python3.withPackages (ps: with ps; [
            pip
            setuptools
            wheel
            pillow
            qmk
            hid
            pyusb
            hjson
            jsonschema
            milc
            pygments
            dotty-dict
            intelhex
          ]))

          # Additional dependencies
          libusb1
          dfu-programmer
          dfu-util
          teensy-loader-cli
          qmk
        ];

        # Helper to link userspace into QMK firmware
        setupUserspace = qmkSrc: pkgs.runCommand "qmk-with-userspace" {} ''
          mkdir -p "$out"
          # Dereference symlinks from source snapshot so overlay writes stay in $out.
          cp -rL ${qmkSrc}/. "$out"
          chmod -R u+w "$out"
          # Recreate overlay roots as writable real directories.
          for d in keyboards users layouts; do
            rm -rf "$out/$d"
            mkdir -p "$out/$d"
            if [ -d "${qmkSrc}/$d" ]; then
              cp -rL "${qmkSrc}/$d"/. "$out/$d/"
            fi
          done
          chmod -R u+w "$out/keyboards" "$out/users" "$out/layouts"

          # Link keyboards from userspace
          if [ -d "${self}/keyboards" ]; then
            for kb in "${self}"/keyboards/*; do
              [ -e "$kb" ] || continue
              kbname=$(basename "$kb")
              if [ -d "$out/keyboards/$kbname" ]; then
                # Merge with existing keyboard (copy keymaps)
                cp -r "$kb"/. "$out/keyboards/$kbname/"
              else
                # New keyboard, copy entirely
                cp -r "$kb" "$out/keyboards/"
              fi
            done
          fi

          # Link users directory
          if [ -d "${self}/users" ]; then
            mkdir -p "$out/users"
            cp -r "${self}/users"/. "$out/users/"
          fi

          # Link layouts
          if [ -d "${self}/layouts" ]; then
            for layout in "${self}"/layouts/*; do
              [ -e "$layout" ] || continue
              layoutname=$(basename "$layout")
              mkdir -p "$out/layouts/$layoutname"
              cp -r "$layout"/. "$out/layouts/$layoutname/"
            done
          fi
        '';

        # QMK sources with userspace integrated
        qmkUpstream = setupUserspace qmk-firmware;
        qmkZsa = setupUserspace zsa-qmk-firmware;
        qmkKeyball = setupUserspace keyball-qmk-firmware;
        qmkBastard = setupUserspace bastardkb-qmk-firmware;

        # Build a QMK firmware
        buildFirmware = { name, keyboard, keymap, qmkSource }:
          pkgs.stdenv.mkDerivation {
            pname = "qmk-${name}";
            version = "0.1.0";

            src = qmkSource;

            nativeBuildInputs = qmkBuildInputs;

            buildPhase = ''
              runHook preBuild

              # QMK needs a writable home directory
              export HOME="$NIX_BUILD_TOP/home"
              mkdir -p $HOME

              # Build the firmware
              make ${keyboard}:${keymap} \
                UF2CONV="${pkgs.python3}/bin/python3 util/uf2conv.py"

              runHook postBuild
            '';

            installPhase = ''
              runHook preInstall

              mkdir -p $out
              # Copy all generated firmware files
              find . -maxdepth 1 \( -name "*.hex" -o -name "*.bin" -o -name "*.uf2" \) \
                -exec cp {} $out/ \;

              runHook postInstall
            '';

            # Don't try to strip firmware files
            dontStrip = true;
            dontPatchELF = true;
            dontFixup = true;
          };

        # Define keyboard builds
        keyboards = {
          # ZSA Voyager - uses ZSA QMK fork
          voyager-pers = buildFirmware {
            name = "voyager-pers";
            keyboard = "zsa/voyager";
            keymap = "pers";
            qmkSource = qmkZsa;
          };

          voyager-ball = buildFirmware {
            name = "voyager-ball";
            keyboard = "zsa/voyager";
            keymap = "ball";
            qmkSource = qmkZsa;
          };

          voyager-mod = buildFirmware {
            name = "voyager-mod";
            keyboard = "zsa/voyager";
            keymap = "mod";
            qmkSource = qmkZsa;
          };

          # Keyball39 - uses holykeebs QMK fork
          keyball39-init = buildFirmware {
            name = "keyball39-init";
            keyboard = "keyball/keyball39";
            keymap = "init";
            qmkSource = qmkKeyball;
          };

          # BastardKB Charybdis (RP2040 Splinky) - uses BastardKB QMK fork
          charybdis-init = buildFirmware {
            name = "charybdis-init";
            keyboard = "bastardkb/charybdis/4x6";
            keymap = "init";
            qmkSource = qmkBastard;
          };

          # Ploopyco Trackball - uses upstream QMK

          ploopyco-trackball-rev1_005-pers = buildFirmware {
            name = "ploopyco-trackball-rev1_005-pers";
            keyboard = "ploopyco/trackball/rev1_005";
            keymap = "pers";
            qmkSource = qmkUpstream;
          };

          ploopyco-trackball-rev1_007-pers = buildFirmware {
            name = "ploopyco-trackball-rev1_007-pers";
            keyboard = "ploopyco/trackball/rev1_007";
            keymap = "pers";
            qmkSource = qmkUpstream;
          };
        };

      in {
        # Individual keyboard packages
        packages = keyboards // {
          # Build all keyboards
          all = pkgs.symlinkJoin {
            name = "qmk-all-keyboards";
            paths = builtins.attrValues keyboards;
          };

          default = self.packages.${system}.all;
        };

        # Development shell with QMK tooling
        devShells.default = pkgs.mkShell {
          buildInputs = qmkBuildInputs ++ (with pkgs; [
            # Additional dev tools
            qmk
          ]);

          shellHook = ''
            echo "QMK Userspace Development Environment"
            echo ""
            echo "Available keyboards:"
            echo "  ZSA (use zsa/qmk_firmware):"
            echo "    - zsa/voyager:pers"
            echo "    - zsa/voyager:ball"
            echo "    - zsa/voyager:mod"
            echo ""
            echo "  Keyball (use holykeebs/qmk_firmware):"
            echo "    - keyball/keyball39:init"
            echo ""
            echo "  BastardKB (use BastardKB qmk fork):"
            echo "    - bastardkb/charybdis/4x6:init"
            echo ""
            echo "  Ploopyco (use upstream qmk_firmware):"
            echo "    - ploopyco/trackball/rev1_005:pers"
            echo "    - ploopyco/trackball/rev1_007:pers"
            echo ""
            echo "Build with: nix build .#<keyboard-name>"
            echo "  e.g.: nix build .#voyager-pers"
            echo "        nix build .#keyball39-init"
            echo "        nix build .#charybdis-init"
            echo "        nix build .#all"
            echo ""
          '';
        };

        # Apps for flashing firmware
        apps = {
          flash-voyager = flake-utils.lib.mkApp {
            drv = pkgs.writeShellScriptBin "flash-voyager" ''
              ${pkgs.wally-cli}/bin/wally-cli ${self.packages.${system}.voyager-pers}/*.bin
            '';
          };
        };
      }
    );
}