From bf2e311eaa9ea37b4898da78a0e6ba9dd596e85a Mon Sep 17 00:00:00 2001 From: Naxdy <naxdy@naxdy.org> Date: Sat, 2 Nov 2024 12:53:35 +0100 Subject: [PATCH] gpio: implement pwm functions --- flake.lock | 51 +--------------------- flake.nix | 122 ++++++++++++++++++++++++++++++---------------------- package.nix | 78 +++++++++++++++++++++++++++++++++ src/gpio.rs | 48 +++++++++++++++++++++ src/lib.rs | 2 +- 5 files changed, 198 insertions(+), 103 deletions(-) create mode 100644 package.nix diff --git a/flake.lock b/flake.lock index 57ec184..650b4f2 100644 --- a/flake.lock +++ b/flake.lock @@ -37,24 +37,6 @@ "type": "github" } }, - "naersk": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1721727458, - "narHash": "sha256-r/xppY958gmZ4oTfLiHN0ZGuQ+RSTijDblVgVLFi1mw=", - "owner": "nix-community", - "repo": "naersk", - "rev": "3fb418eaf352498f6b6c30592e3beb63df42ef11", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "naersk", - "type": "github" - } - }, "nixpkgs": { "locked": { "lastModified": 1729880355, @@ -72,19 +54,6 @@ } }, "nixpkgs_2": { - "locked": { - "lastModified": 1728888510, - "narHash": "sha256-nsNdSldaAyu6PE3YUA+YQLqUDJh+gRbBooMMekZJwvI=", - "path": "/nix/store/xnjw9gmfmpppdj6bxpw6cfkspc3h6xwl-source", - "rev": "a3c0b3b21515f74fd2665903d4ce6bc4dc81c77c", - "type": "path" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_3": { "locked": { "lastModified": 1730137625, "narHash": "sha256-9z8oOgFZiaguj+bbi3k4QhAD6JabWrnv7fscC/mt0KE=", @@ -104,9 +73,7 @@ "inputs": { "fenix": "fenix", "flake-utils": "flake-utils", - "naersk": "naersk", - "nixpkgs": "nixpkgs_3", - "wiringop": "wiringop" + "nixpkgs": "nixpkgs_2" } }, "rust-analyzer-src": { @@ -140,22 +107,6 @@ "repo": "default", "type": "github" } - }, - "wiringop": { - "flake": false, - "locked": { - "lastModified": 1728531008, - "narHash": "sha256-jVfNb0YqaYFd2r5zupy8C1Q1jDAfetPRVKbhtyMBLtg=", - "owner": "orangepi-xunlong", - "repo": "wiringOP", - "rev": "d7bb9d97db265476e6afa8186f2406642e6946be", - "type": "github" - }, - "original": { - "owner": "orangepi-xunlong", - "repo": "wiringOP", - "type": "github" - } } }, "root": "root", diff --git a/flake.nix b/flake.nix index 0de33b2..79f00e8 100644 --- a/flake.nix +++ b/flake.nix @@ -6,64 +6,82 @@ fenix.url = "github:nix-community/fenix"; - naersk.url = "github:nix-community/naersk"; - - wiringop = { - url = "github:orangepi-xunlong/wiringOP"; - flake = false; - }; - flake-utils.url = "github:numtide/flake-utils"; }; - outputs = { self, nixpkgs, fenix, naersk, wiringop, flake-utils }: flake-utils.lib.eachDefaultSystem (system: + outputs = { self, nixpkgs, fenix, flake-utils }: let - target = "aarch64-unknown-linux-gnu"; - pkgs = import nixpkgs { - inherit system; - overlays = [ - fenix.overlays.default - ]; + mkWiringOp = { fetchFromGitHub, lib }: fetchFromGitHub { + owner = "orangepi-xunlong"; + repo = "wiringOP"; + rev = "d7bb9d97db265476e6afa8186f2406642e6946be"; + hash = "sha256-jVfNb0YqaYFd2r5zupy8C1Q1jDAfetPRVKbhtyMBLtg="; + }; + in + flake-utils.lib.eachDefaultSystem + (system: + let + target = "aarch64-unknown-linux-gnu"; + pkgs = import nixpkgs { + inherit system; + overlays = [ + fenix.overlays.default + ]; + }; + + devToolchain = with fenix.packages.${system}; combine [ + stable.cargo + stable.rustc + stable.clippy + stable.rustfmt + targets.${target}.stable.rust-std + ]; + + CARGO_BUILD_TARGET = target; + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = + let + inherit (pkgs.pkgsCross.aarch64-multiplatform.stdenv) cc; + in + "${cc}/bin/${cc.targetPrefix}cc"; + + wiringop-headers = pkgs.runCommandLocal "wiringOP-headers" { } '' + mkdir -p $out/include + cp ${wiringop}/wiringPi/*.h $out/include + ''; + + wiringop = pkgs.callPackage mkWiringOp { }; + + LIBCLANG_PATH = "${pkgs.llvmPackages_18.clang-unwrapped.lib}/lib"; + in + { + devShells.default = + pkgs.mkShell { + nativeBuildInputs = [ + devToolchain + pkgs.llvmPackages_18.clang + ]; + + buildInputs = [ + wiringop-headers + pkgs.libxcrypt + ]; + + WIRINGOP_PATH = "${wiringop}"; + + inherit LIBCLANG_PATH CARGO_BUILD_TARGET CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER; + }; + }) // { + overlays.default = final: prev: { + wiringop = final.callPackage (import ./package.nix) { srcAll = final.callPackage mkWiringOp { }; }; }; - devToolchain = with fenix.packages.${system}; combine [ - stable.cargo - stable.rustc - stable.clippy - stable.rustfmt - targets.${target}.stable.rust-std - ]; - - CARGO_BUILD_TARGET = target; - CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER = + packages.aarch64-linux.default = let - inherit (pkgs.pkgsCross.aarch64-multiplatform.stdenv) cc; + pkgs = import nixpkgs { + system = "aarch64-linux"; + overlays = [ self.overlays.default ]; + }; in - "${cc}/bin/${cc.targetPrefix}cc"; - - wiringop-headers = pkgs.runCommandLocal "wiringOP-headers" { } '' - mkdir -p $out/include - cp ${wiringop}/wiringPi/*.h $out/include - ''; - - LIBCLANG_PATH = "${pkgs.llvmPackages_18.clang-unwrapped.lib}/lib"; - in - { - devShells.default = - pkgs.mkShell { - nativeBuildInputs = [ - devToolchain - pkgs.llvmPackages_18.clang - ]; - - buildInputs = [ - wiringop-headers - pkgs.libxcrypt - ]; - - WIRINGOP_PATH = "${wiringop}"; - - inherit LIBCLANG_PATH CARGO_BUILD_TARGET CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER; - }; - }); + pkgs.wiringop; + }; } diff --git a/package.nix b/package.nix new file mode 100644 index 0000000..a0ad504 --- /dev/null +++ b/package.nix @@ -0,0 +1,78 @@ +{ lib +, stdenv +, symlinkJoin +, srcAll +, libxcrypt +}: +let + version = "master"; + + mkSubProject = + { subprj + , # The only mandatory argument + buildInputs ? [ ] + , src ? srcAll + , extraPreInstall ? "" + , + }: + stdenv.mkDerivation (finalAttrs: { + pname = "wiringpi-${subprj}"; + inherit version src; + sourceRoot = "${src.name}/${subprj}"; + inherit buildInputs; + # Remove (meant for other OSs) lines from Makefiles + preInstall = '' + sed -i "/chown root/d" Makefile + sed -i "/chmod/d" Makefile + '' + extraPreInstall; + makeFlags = [ + "DESTDIR=${placeholder "out"}" + "PREFIX=" + # On NixOS we don't need to run ldconfig during build: + "LDCONFIG=echo" + ]; + }); + + passthru = { + src = srcAll; + inherit mkSubProject; + wiringPi = mkSubProject { + subprj = "wiringPi"; + buildInputs = [ libxcrypt ]; + }; + devLib = mkSubProject { + subprj = "devLib"; + buildInputs = [ passthru.wiringPi ]; + }; + wiringPiD = mkSubProject { + subprj = "wiringPiD"; + buildInputs = [ + libxcrypt + passthru.wiringPi + passthru.devLib + ]; + }; + gpio = mkSubProject { + subprj = "gpio"; + extraPreInstall = '' + mkdir -p $out/bin + ''; + buildInputs = [ + libxcrypt + passthru.wiringPi + passthru.devLib + ]; + }; + }; +in +symlinkJoin { + name = "wiringop-${version}"; + inherit passthru; + paths = builtins.attrValues { + inherit (passthru) + wiringPi + devLib + wiringPiD + gpio; + }; +} diff --git a/src/gpio.rs b/src/gpio.rs index c041caa..06a18c0 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -147,6 +147,54 @@ impl Pin { } } + pub fn pwm_write(&mut self, value: i32) -> Result<(), GpioError> { + ensure_library_setup!(); + + self.ensure_pin_mode(PinMode::PwmOutput)?; + + unsafe { + ffi::pwmWrite(self.pin_id, value); + } + + Ok(()) + } + + pub fn pwm_set_tone(&mut self, freq: i32) -> Result<(), GpioError> { + ensure_library_setup!(); + + self.ensure_pin_mode(PinMode::PwmOutput)?; + + unsafe { + ffi::pwmToneWrite(self.pin_id, freq); + } + + Ok(()) + } + + pub fn pwm_set_range(&mut self, range: u32) -> Result<(), GpioError> { + ensure_library_setup!(); + + self.ensure_pin_mode(PinMode::PwmOutput)?; + + unsafe { + ffi::pwmSetRange(self.pin_id, range); + } + + Ok(()) + } + + pub fn pwm_set_clock(&mut self, divisor: i32) -> Result<(), GpioError> { + ensure_library_setup!(); + + self.ensure_pin_mode(PinMode::PwmOutput)?; + + unsafe { + ffi::pwmSetClock(self.pin_id, divisor); + } + + Ok(()) + } + pub fn get_gpio_mode(&mut self) -> Result<PinMode, GpioError> { ensure_library_setup!(); diff --git a/src/lib.rs b/src/lib.rs index b9f9ec0..fb59486 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,4 +12,4 @@ macro_rules! ensure_library_setup { }; } -static LIBRARY_SETUP_COMPLETE: Lazy<bool> = Lazy::new(|| unsafe { ffi::wiringPiSetupGpio() == 0 }); +static LIBRARY_SETUP_COMPLETE: Lazy<bool> = Lazy::new(|| unsafe { ffi::wiringPiSetup() == 0 });