me like nix
0

Configure Feed

Select the types of activity you want to include in your feed.

1{ ... }: { 2 flake.modules.nixos.pi-camera = 3 { pkgs, lib, config, ... }: 4 let 5 cfg = config.pi; 6 7 deviceTree_overlay = _final: prev: { 8 deviceTree = { 9 applyOverlays = prev.callPackage ../hosts/pi-common/overlays/apply-overlays-dtmerge.nix { }; 10 compileDTS = prev.deviceTree.compileDTS; 11 }; 12 }; 13 14 libcamera-rpi = pkgs.libcamera.overrideAttrs (old: { 15 mesonFlags = (old.mesonFlags or [ ]) ++ [ 16 "-Dipas=rpi/vc4,rpi/pisp" 17 "-Dpipelines=rpi/vc4,rpi/pisp" 18 ]; 19 }); 20 21 rpicam-apps = pkgs.stdenv.mkDerivation rec { 22 pname = "rpicam-apps"; 23 version = "1.11.1"; 24 25 src = pkgs.fetchFromGitHub { 26 owner = "raspberrypi"; 27 repo = "rpicam-apps"; 28 rev = "v${version}"; 29 hash = "sha256-hVoKbvWFeramPkHuibJwUgFOPS9v588+K8828a1fNnA="; 30 }; 31 32 nativeBuildInputs = with pkgs; [ 33 meson 34 ninja 35 pkg-config 36 ]; 37 38 buildInputs = [ 39 libcamera-rpi 40 pkgs.libdrm 41 pkgs.libexif 42 pkgs.libjpeg 43 pkgs.libpng 44 pkgs.libtiff 45 pkgs.boost 46 pkgs.ffmpeg 47 ]; 48 49 mesonFlags = [ 50 "-Denable_libav=enabled" 51 "-Denable_drm=enabled" 52 "-Denable_egl=disabled" 53 "-Denable_qt=disabled" 54 "-Denable_opencv=disabled" 55 "-Denable_tflite=disabled" 56 "-Denable_hailo=disabled" 57 ]; 58 59 meta = with lib; { 60 description = "Raspberry Pi camera applications"; 61 homepage = "https://github.com/raspberrypi/rpicam-apps"; 62 license = licenses.bsd2; 63 platforms = [ "aarch64-linux" ]; 64 }; 65 }; 66 in 67 { 68 options.pi = { 69 streamName = lib.mkOption { 70 type = lib.types.str; 71 description = "Name of the camera stream"; 72 }; 73 resolution = { 74 width = lib.mkOption { 75 type = lib.types.int; 76 default = 1920; 77 description = "Camera resolution width"; 78 }; 79 height = lib.mkOption { 80 type = lib.types.int; 81 default = 1080; 82 description = "Camera resolution height"; 83 }; 84 }; 85 framerate = lib.mkOption { 86 type = lib.types.int; 87 default = 30; 88 description = "Camera framerate"; 89 }; 90 deviceTreeFilter = lib.mkOption { 91 type = lib.types.str; 92 description = "Device tree filter pattern"; 93 }; 94 deviceTreeCompatible = lib.mkOption { 95 type = lib.types.str; 96 description = "Device tree compatible string"; 97 }; 98 gpuMem = lib.mkOption { 99 type = lib.types.int; 100 default = 256; 101 description = "GPU memory allocation in MB"; 102 }; 103 cmaMem = lib.mkOption { 104 type = lib.types.int; 105 default = 256; 106 description = "CMA (Contiguous Memory Allocator) size in MB for DMA buffers"; 107 }; 108 flipCamera = lib.mkOption { 109 type = lib.types.bool; 110 default = false; 111 description = "Flip camera image 180 degrees"; 112 }; 113 }; 114 115 config = { 116 # CMA is configured via device tree overlay (cma-256m) 117 # Do NOT use boot.kernelParams cma= as it bypasses the DT node 118 # and prevents /dev/dma_heap/linux,cma from being created 119 120 nix.settings.trusted-users = [ "sean" ]; 121 122 networking.useDHCP = true; 123 nixpkgs.overlays = [ deviceTree_overlay ]; 124 125 boot.supportedFilesystems = lib.mkForce [ 126 "vfat" 127 "ext4" 128 ]; 129 boot.initrd.systemd.enable = false; 130 131 services.openssh = { 132 enable = true; 133 settings = { 134 PasswordAuthentication = false; 135 PermitRootLogin = "no"; 136 }; 137 }; 138 139 users.users.sean = { 140 isNormalUser = true; 141 extraGroups = [ 142 "wheel" 143 "video" 144 ]; 145 openssh.authorizedKeys.keys = [ 146 "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCIqgZ7kedxo+mOW7YG73Vp3zel3h180y3GKvHtRsXfGlpIIvRDy7pgCBQ4AGXYD4y78URQmFohYSAPqCPOPaWcU2un3XG9KvCzEsHmsbskPonitUmCiKvrKkb6oW4jCBtd7AEtBn+AiajAQFtPZ7NN2Df3AmTypvR6Irg7R+nxnfc9NTIHmGvxSDyWcbb4pguL20sctUSqGL6xGh8q/bqhdOThSimM+z9bEUNxK/5rPhwkNniMrp4pJcUrUiAh5/4DiRFG6KT+oeg+/myoz/Z1sPvAs7u/8JDQI4RshRD8Hu0oTkRBN6Hxj478q2SXbeBUZlD6IdjP3RhGpmSecoDdtWqKbpuV3eVRtQtba3KL86GBeV/bugaOdJ1Aud+1SOFJreAAuvxzMMKT+cdQZk6oOPP148DA/No+mDm/2S43lcdCXh79wA6YRAmKQ8jmZxTCtPutrvuZK1rguvvUlEoG/vhdNHh7eDa4Td07V6bjCRPUl8qk/e4M0E3pwsTlZc=" 147 "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOIgEteUEW06dnBHe2z8vNLwz2iMKe8bba6JgMmOUpcBAAAABHNzaDo= sean@framework16" 148 ]; 149 }; 150 151 security.sudo.wheelNeedsPassword = false; 152 153 services.go2rtc = { 154 enable = true; 155 settings = { 156 ffmpeg.bin = "${pkgs.ffmpeg}/bin/ffmpeg"; 157 streams = { 158 "${cfg.streamName}" = "exec:${rpicam-apps}/bin/rpicam-vid -t 0 --width ${toString cfg.resolution.width} --height ${toString cfg.resolution.height} --framerate ${toString cfg.framerate} --codec h264 --inline --autofocus-mode continuous${lib.optionalString cfg.flipCamera " --vflip --hflip"} -o -"; 159 }; 160 }; 161 }; 162 163 services.udev.extraRules = '' 164 SUBSYSTEM=="dma_heap", GROUP="video", MODE="0660" 165 ''; 166 167 systemd.services.go2rtc.serviceConfig = { 168 User = lib.mkForce "root"; 169 SupplementaryGroups = [ "video" ]; 170 }; 171 systemd.services.go2rtc.environment = { 172 LIBCAMERA_IPA_MODULE_PATH = "${libcamera-rpi}/lib/libcamera/ipa"; 173 }; 174 175 environment.systemPackages = [ 176 pkgs.ffmpeg 177 pkgs.libraspberrypi 178 libcamera-rpi 179 rpicam-apps 180 pkgs.v4l-utils 181 ]; 182 183 hardware.deviceTree.filter = cfg.deviceTreeFilter; 184 hardware.deviceTree.overlays = [ 185 { 186 # Increase CMA from 64MB to 256MB via device tree 187 # (cmdline cma= bypasses the DT node and /dev/dma_heap/linux,cma isn't created) 188 name = "cma-256m"; 189 dtsText = '' 190 /dts-v1/; 191 /plugin/; 192 193 / { 194 compatible = "${cfg.deviceTreeCompatible}"; 195 196 fragment@99 { 197 target-path = "/reserved-memory/linux,cma"; 198 __overlay__ { 199 size = <0x10000000>; /* 256MB */ 200 }; 201 }; 202 }; 203 ''; 204 } 205 { 206 name = "imx708-overlay"; 207 dtsText = '' 208 // SPDX-License-Identifier: GPL-2.0-only 209 // Definitions for IMX708 camera module on VC I2C bus 210 /dts-v1/; 211 /plugin/; 212 213 /{ 214 compatible = "${cfg.deviceTreeCompatible}"; 215 216 fragment@0 { 217 target = <&i2c0if>; 218 __overlay__ { 219 status = "okay"; 220 }; 221 }; 222 223 clk_frag: fragment@1 { 224 target = <&cam1_clk>; 225 __overlay__ { 226 status = "okay"; 227 clock-frequency = <24000000>; 228 }; 229 }; 230 231 fragment@2 { 232 target = <&i2c0mux>; 233 __overlay__ { 234 status = "okay"; 235 }; 236 }; 237 238 reg_frag: fragment@3 { 239 target = <&cam1_reg>; 240 cam_reg: __overlay__ { 241 startup-delay-us = <70000>; 242 off-on-delay-us = <30000>; 243 regulator-min-microvolt = <2700000>; 244 regulator-max-microvolt = <2700000>; 245 }; 246 }; 247 248 i2c_frag: fragment@100 { 249 target = <&i2c_csi_dsi>; 250 __overlay__ { 251 #address-cells = <1>; 252 #size-cells = <0>; 253 status = "okay"; 254 255 cam_node: imx708@1a { 256 compatible = "sony,imx708"; 257 reg = <0x1a>; 258 status = "okay"; 259 260 clocks = <&cam1_clk>; 261 clock-names = "inclk"; 262 263 vana1-supply = <&cam1_reg>; 264 vana2-supply = <&cam_dummy_reg>; 265 vdig-supply = <&cam_dummy_reg>; 266 vddl-supply = <&cam_dummy_reg>; 267 268 rotation = <180>; 269 orientation = <2>; 270 271 port { 272 cam_endpoint: endpoint { 273 clock-lanes = <0>; 274 data-lanes = <1 2>; 275 clock-noncontinuous; 276 link-frequencies = 277 /bits/ 64 <450000000>; 278 }; 279 }; 280 }; 281 282 vcm_node: dw9817@c { 283 compatible = "dongwoon,dw9817-vcm"; 284 reg = <0x0c>; 285 status = "okay"; 286 VDD-supply = <&cam1_reg>; 287 }; 288 }; 289 }; 290 291 csi_frag: fragment@101 { 292 target = <&csi1>; 293 csi: __overlay__ { 294 status = "okay"; 295 brcm,media-controller; 296 297 port { 298 csi_ep: endpoint { 299 remote-endpoint = <&cam_endpoint>; 300 clock-lanes = <0>; 301 data-lanes = <1 2>; 302 clock-noncontinuous; 303 }; 304 }; 305 }; 306 }; 307 308 __overrides__ { 309 rotation = <&cam_node>,"rotation:0"; 310 orientation = <&cam_node>,"orientation:0"; 311 media-controller = <&csi>,"brcm,media-controller?"; 312 cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>, 313 <&csi_frag>, "target:0=",<&csi0>, 314 <&clk_frag>, "target:0=",<&cam0_clk>, 315 <&reg_frag>, "target:0=",<&cam0_reg>, 316 <&cam_node>, "clocks:0=",<&cam0_clk>, 317 <&cam_node>, "vana1-supply:0=",<&cam0_reg>, 318 <&vcm_node>, "VDD-supply:0=",<&cam0_reg>; 319 vcm = <&vcm_node>, "status", 320 <0>, "=4"; 321 link-frequency = <&cam_endpoint>,"link-frequencies#0"; 322 }; 323 }; 324 325 &cam_endpoint { 326 remote-endpoint = <&csi_ep>; 327 }; 328 ''; 329 } 330 ]; 331 332 hardware.enableRedistributableFirmware = true; 333 334 sdImage.populateFirmwareCommands = lib.mkAfter '' 335 chmod u+w ./firmware/config.txt 336 cat >> ./firmware/config.txt << EOF 337 338 # Camera support - Pi Camera v3 (IMX708) 339 dtoverlay=imx708 340 gpu_mem=${toString cfg.gpuMem} 341 dtoverlay=cma,cma-${toString cfg.cmaMem} 342 EOF 343 344 if [ -d ${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays ]; then 345 cp -r ${pkgs.raspberrypifw}/share/raspberrypi/boot/overlays ./firmware/ 346 fi 347 ''; 348 349 networking.firewall.allowedTCPPorts = [ 350 22 351 1984 352 8554 353 ]; 354 }; 355 }; 356}