From 2213535a3a2d85ff97bd31d2e70e131947f3958d Mon Sep 17 00:00:00 2001 From: Naxdy <naxdy@naxdy.org> Date: Tue, 29 Oct 2024 13:54:42 +0100 Subject: [PATCH] init --- .envrc | 1 + .gitignore | 8 ++ Cargo.lock | 318 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 12 ++ build.rs | 54 +++++++++ ffi/wrapper.h | 1 + flake.lock | 163 ++++++++++++++++++++++++++ flake.nix | 69 +++++++++++ src/ffi.rs | 6 + src/gpio.rs | 36 ++++++ src/lib.rs | 2 + 11 files changed, 670 insertions(+) create mode 100644 .envrc create mode 100644 .gitignore create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 build.rs create mode 100644 ffi/wrapper.h create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 src/ffi.rs create mode 100644 src/gpio.rs create mode 100644 src/lib.rs diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5c9d904 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/.direnv +/target +/result +/result-* +.vscode + +/build + diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..fe7e318 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,318 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cc" +version = "1.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" +dependencies = [ + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.161" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "syn" +version = "2.0.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5023162dfcd14ef8f32034d8bcd4cc5ddc61ef7a247c024a33e24e1f24d21b56" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "wiringop-rs" +version = "0.1.0" +dependencies = [ + "bindgen", + "cc", + "glob", + "thiserror", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f2ae784 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "wiringop-rs" +version = "0.1.0" +edition = "2021" + +[dependencies] +thiserror = "1.0.65" + +[build-dependencies] +cc = "1.1.31" +glob = "0.3.1" +bindgen = "0.70.1" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..ce6231a --- /dev/null +++ b/build.rs @@ -0,0 +1,54 @@ +use std::{ + env::{self, set_current_dir}, + fs, + path::PathBuf, +}; + +fn main() { + fs::create_dir_all("build").expect("could not create build path"); + + let int_path = PathBuf::from("build") + .canonicalize() + .expect("cannot canonicalize path"); + + set_current_dir(int_path.clone()).expect("failed to change current directory"); + + let wiringop_path = PathBuf::from( + env::var("WIRINGOP_PATH").expect("could not retrieve wiringOP path from env"), + ) + .canonicalize() + .expect("cannot canonicalize path"); + + let mut cc = cc::Build::new(); + + cc.files( + glob::glob(&format!("{}/wiringPi/*.c", wiringop_path.to_str().unwrap())) + .unwrap() + .filter_map(|e| e.ok()), + ) + .include(format!("{}/wiringPi/", wiringop_path.to_str().unwrap())); + + let target = std::env::var("TARGET").unwrap(); + + if target.starts_with("aarch64") { + cc.flag("-O2"); + } + + cc.static_flag(true).compile("wiringop"); + + let builder = bindgen::Builder::default() + .header("../ffi/wrapper.h") + .detect_include_paths(true); + + let bindings = builder + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) + .generate() + .expect("unable to generate bindings"); + + let out_path = PathBuf::from(env::var("OUT_DIR").expect("failed to get out dir for bindings")) + .join("bindings.rs"); + + bindings + .write_to_file(out_path) + .expect("couldn't write bindings"); +} diff --git a/ffi/wrapper.h b/ffi/wrapper.h new file mode 100644 index 0000000..2b75d0c --- /dev/null +++ b/ffi/wrapper.h @@ -0,0 +1 @@ +#include <wiringPi.h> diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..57ec184 --- /dev/null +++ b/flake.lock @@ -0,0 +1,163 @@ +{ + "nodes": { + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1730183653, + "narHash": "sha256-dcJGcoDgNBxTagW8kECwBKsRBA1ZITtQ+p3N6KHg5ps=", + "owner": "nix-community", + "repo": "fenix", + "rev": "dc19afc39af5f5e69fca78ebae59170e61017df8", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "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, + "narHash": "sha256-RP+OQ6koQQLX5nw0NmcDrzvGL8HDLnyXt/jHhL1jwjM=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "18536bf04cd71abd345f9579158841376fdd0c5a", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "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=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "64b80bfb316b57cdb8919a9110ef63393d74382a", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "fenix": "fenix", + "flake-utils": "flake-utils", + "naersk": "naersk", + "nixpkgs": "nixpkgs_3", + "wiringop": "wiringop" + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1730123801, + "narHash": "sha256-11FMcPraLSKuvfFF4OzmKWSKE5zXAzFqZOi3k/8/HFg=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "cf8f950baab30f335917b177536d2d73e0aaa1ae", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "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", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..0de33b2 --- /dev/null +++ b/flake.nix @@ -0,0 +1,69 @@ +{ + description = "Rust library for interacting with wiringOP (Orange Pi fork of wiringPi)"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-24.05"; + + 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: + 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 + ''; + + 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; + }; + }); +} diff --git a/src/ffi.rs b/src/ffi.rs new file mode 100644 index 0000000..04d76a4 --- /dev/null +++ b/src/ffi.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/src/gpio.rs b/src/gpio.rs new file mode 100644 index 0000000..f53d9a9 --- /dev/null +++ b/src/gpio.rs @@ -0,0 +1,36 @@ +use std::sync::Mutex; + +use thiserror::Error; + +use crate::ffi; + +static PINS_HANDED_OUT: Mutex<Vec<i32>> = Mutex::new(Vec::new()); + +#[derive(Error, Debug)] +pub enum PinRetrievalError { + #[error("pin {0} has already been retrieved")] + AlreadyRetrieved(i32), +} + +pub struct Pin { + pin_id: i32, +} + +impl Pin { + pub fn new(pin_id: i32) -> Result<Self, PinRetrievalError> { + let can_retrieve = !PINS_HANDED_OUT + .lock() + .expect("failed to obtain pin list lock") + .contains(&pin_id); + + if can_retrieve { + Ok(Self { pin_id }) + } else { + Err(PinRetrievalError::AlreadyRetrieved(pin_id)) + } + } + + pub fn get_gpio_mode(&mut self) -> i32 { + unsafe { ffi::orangepi_get_gpio_mode(self.pin_id) } + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..ea4a206 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,2 @@ +mod ffi; +pub mod gpio;