├── .gitignore ├── scripts ├── gcc-sysroot └── config ├── .gitmodules ├── examples ├── flashing_lights.rs └── software_pwm.rs ├── Cargo.toml ├── LICENSE ├── .travis.yml ├── README.md └── src ├── bindings.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /Cargo.lock 3 | -------------------------------------------------------------------------------- /scripts/gcc-sysroot: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | arm-linux-gnueabihf-gcc --sysroot=$HOME/pi-tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/arm-bcm2708hardfp-linux-gnueabi/sysroot "$@" -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "wiringPi"] 2 | path = wiringPi 3 | url = git@github.com:WiringPi/WiringPi.git 4 | [submodule "WiringOP"] 5 | path = WiringOP 6 | url = https://github.com/zhaolei/WiringOP.git 7 | -------------------------------------------------------------------------------- /scripts/config: -------------------------------------------------------------------------------- 1 | [target.arm-unknown-linux-gnueabihf] 2 | ar = "arm-linux-gnueabihf-ar" 3 | linker = "gcc-sysroot" 4 | 5 | [target.armv7-unknown-linux-gnueabihf] 6 | ar = "arm-linux-gnueabihf-ar" 7 | linker = "gcc-sysroot" 8 | -------------------------------------------------------------------------------- /examples/flashing_lights.rs: -------------------------------------------------------------------------------- 1 | extern crate wiringpi; 2 | 3 | use wiringpi::pin::Value::{High, Low}; 4 | use std::time::Duration; 5 | use std::thread; 6 | 7 | fn main() { 8 | //Setup WiringPi with its own pin numbering order 9 | let pi = wiringpi::setup(); 10 | 11 | //Use WiringPi pin 0 as output 12 | let pin = pi.output_pin(0); 13 | 14 | loop { 15 | //Set pin 0 to high and wait one second 16 | pin.digital_write(High); 17 | thread::sleep(Duration::from_millis(1000)); 18 | 19 | //Set pin 0 to low and wait one second 20 | pin.digital_write(Low); 21 | thread::sleep(Duration::from_millis(1000)); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "wiringpi" 3 | version = "0.2.4" 4 | authors = ["Erik Hedvall "] 5 | build = "build.rs" 6 | exclude = ["cross*", "scripts/*", "wiringPi/**/*.o", "wiringPi/examples/**", "wiringPi/pins/**", "WiringOP/**/*.o", "WiringOP/examples/**", "WiringOP/pins/**", "examples/*", ".travis.yml"] 7 | description = "An API wrapper for WiringPi, implementing the most important functions and provides a bit of type system convenience. See README.md for Raspberry Pi build instructions." 8 | documentation = "https://docs.rs/wiringpi/0.2.4/wiringpi/" 9 | repository = "https://github.com/Ogeon/rust-wiringpi" 10 | readme = "README.md" 11 | keywords = ["wiringpi", "wiring", "raspberry", "pi", "bindings"] 12 | license = "MIT" 13 | 14 | [features] 15 | #Build patched version or wiringpi for Orange PI 16 | orangepi = [] 17 | development = [] 18 | 19 | strict = [] 20 | 21 | [dependencies] 22 | libc = "0.2" 23 | 24 | [build-dependencies] 25 | cc = "1.0.4" 26 | glob = "0.2.11" 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/software_pwm.rs: -------------------------------------------------------------------------------- 1 | extern crate wiringpi; 2 | 3 | use wiringpi::pin::Value::High; 4 | use std::time::Duration; 5 | use std::thread; 6 | 7 | fn main() { 8 | // Setup wiringPi in GPIO mode (with original BCM numbering order) 9 | let pi = wiringpi::setup_gpio(); 10 | 11 | // Use pins 23 and 25 as software PWM output 12 | // (note that the only hardware PWM pin is 18) 13 | let mut alice = pi.soft_pwm_pin(23); 14 | let bob = pi.soft_pwm_pin(25); 15 | 16 | // Use a duty cycle of 0.5 on both pins 17 | alice.pwm_write(50); 18 | bob.pwm_write(50); 19 | 20 | thread::sleep(Duration::from_millis(2000)); 21 | 22 | // Switch `alice` (pin 23) to output mode and turn it on 23 | let alice_out = alice.into_output(); 24 | alice_out.digital_write(High); 25 | // Change the duty cycle of `bob` to 1 26 | bob.pwm_write(100); 27 | 28 | // Both pins now output the same signal, `alice` via software PWM, 29 | // `bob` via constant output 30 | 31 | thread::sleep(Duration::from_millis(2000)); 32 | 33 | // Switch `alice_out` (pin 23) back to software PWM mode 34 | alice = alice_out.into_soft_pwm(); 35 | alice.pwm_write(50); 36 | bob.pwm_write(50); 37 | 38 | thread::sleep(Duration::from_millis(2000)); 39 | 40 | alice.pwm_write(0); 41 | bob.pwm_write(0); 42 | } 43 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | os: 3 | - linux 4 | dist: trusty 5 | sudo: false 6 | 7 | # Build for all chains since Rust 1.8.0 (not available for prior versions) 8 | env: 9 | - RUST=nightly 10 | - RUST=beta 11 | - RUST=stable 12 | 13 | # Install rust 14 | install: 15 | - curl https://sh.rustup.rs -sSf | sh -s -- -y 16 | - export PATH="$HOME/.cargo/bin:$PATH" 17 | - rustup toolchain install $RUST 18 | - rustup default $RUST 19 | - rustup target add arm-unknown-linux-gnueabihf 20 | - rustup target add armv7-unknown-linux-gnueabihf 21 | - rustc -V 22 | - cargo -V 23 | - cp scripts/config ~/.cargo/config 24 | - git clone https://github.com/raspberrypi/tools.git ~/pi-tools 25 | - cp scripts/gcc-sysroot ~/pi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin 26 | - chmod +x ~/pi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/gcc-sysroot 27 | - export PATH="$HOME/pi-tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH" 28 | 29 | script: 30 | - cargo build --target=arm-unknown-linux-gnueabihf -v --features strict 31 | - cargo build --target=arm-unknown-linux-gnueabihf -v --features "orangepi strict" 32 | - cargo build --target=arm-unknown-linux-gnueabihf -v --example flashing_lights 33 | - cargo build --target=arm-unknown-linux-gnueabihf -v --features orangepi --example flashing_lights 34 | 35 | - cargo build --target=armv7-unknown-linux-gnueabihf -v --features strict 36 | - cargo build --target=armv7-unknown-linux-gnueabihf -v --features "orangepi strict" 37 | - cargo build --target=armv7-unknown-linux-gnueabihf -v --example flashing_lights 38 | - cargo build --target=armv7-unknown-linux-gnueabihf -v --features orangepi --example flashing_lights 39 | 40 | # development mode 41 | - cargo build -v --features development 42 | - cargo build -v --features development --example flashing_lights 43 | 44 | - cargo doc -v 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WiringPi Bindings for Rust 2 | 3 | An API wrapper for [WiringPi](http://wiringpi.com/) to make it accessible 4 | using Rust. It implements the most important functions and provides a bit of 5 | type system convenience. 6 | 7 | Add the following lines to your `Cargo.io` to use `rust-wiringpi`: 8 | 9 | ```toml 10 | [dependencies] 11 | wiringpi = "0.2" 12 | ``` 13 | 14 | ## Online Documentation 15 | 16 | [Released](https://docs.rs/wiringpi/0.2.4/wiringpi/) 17 | 18 | [Master branch](http://ogeon.github.io/docs/rust-wiringpi/master/wiringpi/index.html) 19 | 20 | ## Example: Flashing Light 21 | 22 | ```Rust 23 | extern crate wiringpi; 24 | 25 | use wiringpi::pin::Value::{High, Low}; 26 | use std::{thread, time}; 27 | 28 | fn main() { 29 | //Setup WiringPi with its own pin numbering order 30 | let pi = wiringpi::setup(); 31 | 32 | //Use WiringPi pin 0 as output 33 | let pin = pi.output_pin(0); 34 | 35 | let interval = time::Duration::from_millis(1000); 36 | 37 | loop { 38 | //Set pin 0 to high and wait one second 39 | pin.digital_write(High); 40 | thread::sleep(interval); 41 | 42 | //Set pin 0 to low and wait one second 43 | pin.digital_write(Low); 44 | thread::sleep(interval); 45 | } 46 | } 47 | ``` 48 | 49 | ## Cross Compiling Using Cargo 50 | 51 | Follow this [guide](https://hackernoon.com/compiling-rust-for-the-raspberry-pi-49fdcd7df658). 52 | 53 | ``` 54 | cargo build --target=arm-unknown-linux-gnueabihf # Older models 55 | cargo build --target=armv7-unknown-linux-gnueabihf # Newer models 56 | ``` 57 | 58 | ## Orange Pi support 59 | 60 | `rust-wiringpi` can also wrap the WiringOP library for the Orange Pi SBC boards. 61 | This can be enabled with the `orangepi` feature: 62 | 63 | ```toml 64 | [dependencies.wiringpi] 65 | version = "0.2" 66 | features = ["orangepi"] 67 | ``` 68 | 69 | ## Development Mode 70 | 71 | In development mode, `rust-wiringpi` is compiled as a rust-native library excluding the original WiringPi. 72 | And binding functions are replaced by dummy functions that output simple logs to stdout. 73 | With this mode, you can build and debug your project on platforms that does not support WiringPi. 74 | 75 | Development mode will be turned on automatically on non-arm targets, but can be turned on manually 76 | on arm targets as well 77 | 78 | ```shell 79 | # build 80 | $ cargo build --features wiringpi/development 81 | 82 | # run 83 | $ cargo run --features wiringpi/development 84 | 85 | [wiringpi] `wiringPiSetup` called 86 | [wiringpi] `pinMode` called with: 0, 1 87 | [wiringpi] `digitalWrite` called with: 0, 1 88 | [wiringpi] `digitalWrite` called with: 0, 0 89 | ... 90 | ``` 91 | -------------------------------------------------------------------------------- /src/bindings.rs: -------------------------------------------------------------------------------- 1 | /* automatically generated by rust-bindgen */ 2 | 3 | #![allow(dead_code, 4 | non_camel_case_types, 5 | non_upper_case_globals, 6 | non_snake_case)] 7 | #[repr(C)] 8 | #[derive(Copy, Clone)] 9 | #[derive(Debug)] 10 | pub struct wiringPiNodeStruct { 11 | pub pinBase: ::libc::c_int, 12 | pub pinMax: ::libc::c_int, 13 | pub fd: ::libc::c_int, 14 | pub data0: ::libc::c_uint, 15 | pub data1: ::libc::c_uint, 16 | pub data2: ::libc::c_uint, 17 | pub data3: ::libc::c_uint, 18 | pub pinMode: ::std::option::Option, 24 | pub pullUpDnControl: ::std::option::Option, 30 | pub digitalRead: ::std::option::Option ::libc::c_int>, 35 | pub digitalWrite: ::std::option::Option, 41 | pub pwmWrite: ::std::option::Option, 47 | pub analogRead: ::std::option::Option ::libc::c_int>, 52 | pub analogWrite: ::std::option::Option, 58 | pub next: *mut wiringPiNodeStruct, 59 | } 60 | impl ::std::default::Default for wiringPiNodeStruct { 61 | fn default() -> Self { unsafe { ::std::mem::zeroed() } } 62 | } 63 | 64 | macro_rules! binding_functions { 65 | ( $( pub fn $name:ident ( $( $arg_name:ident: $arg_type:ty ),* ) -> $return_type:ty ; $return_value:expr ; )* ) => { 66 | #[cfg(not(feature = "development"))] 67 | #[link(name = "wiringpi", kind = "static")] 68 | extern "C" { 69 | $( 70 | pub fn $name($($arg_name: $arg_type),*) -> $return_type; 71 | )* 72 | } 73 | 74 | $( 75 | #[cfg(feature = "development")] 76 | pub unsafe fn $name($($arg_name: $arg_type),*) -> $return_type { 77 | let args: Vec = vec![$(format!("{:?}", $arg_name)),*]; 78 | 79 | if args.is_empty() { 80 | println!("[wiringpi] `{}` called", stringify!($name)); 81 | } else { 82 | println!("[wiringpi] `{}` called with: {}", stringify!($name), args.join(", ")); 83 | } 84 | 85 | $return_value 86 | } 87 | )* 88 | }; 89 | } 90 | 91 | binding_functions! { 92 | pub fn wiringPiSetup() -> ::libc::c_int; 0; 93 | pub fn wiringPiSetupSys() -> ::libc::c_int; 0; 94 | pub fn wiringPiSetupGpio() -> ::libc::c_int; 0; 95 | pub fn wiringPiSetupPhys() -> ::libc::c_int; 0; 96 | pub fn pinModeAlt(pin: ::libc::c_int, mode: ::libc::c_int) -> (); (); 97 | pub fn pinMode(pin: ::libc::c_int, mode: ::libc::c_int) -> (); (); 98 | pub fn pullUpDnControl(pin: ::libc::c_int, pud: ::libc::c_int) -> (); (); 99 | pub fn digitalRead(pin: ::libc::c_int) -> ::libc::c_int; 0; 100 | pub fn digitalWrite(pin: ::libc::c_int, value: ::libc::c_int) -> (); (); 101 | pub fn pwmWrite(pin: ::libc::c_int, value: ::libc::c_int) -> (); (); 102 | pub fn analogRead(pin: ::libc::c_int) -> ::libc::c_int; 0; 103 | pub fn analogWrite(pin: ::libc::c_int, value: ::libc::c_int) -> (); (); 104 | pub fn wiringPiSetupPiFace() -> ::libc::c_int; 0; 105 | pub fn wiringPiSetupPiFaceForGpioProg() -> ::libc::c_int; 0; 106 | pub fn piBoardRev() -> ::libc::c_int; 0; 107 | pub fn piBoardId(model: *mut ::libc::c_int, rev: *mut ::libc::c_int, 108 | mem: *mut ::libc::c_int, maker: *mut ::libc::c_int, 109 | overVolted: *mut ::libc::c_int) -> (); (); 110 | pub fn wpiPinToGpio(wpiPin: ::libc::c_int) -> ::libc::c_int; 0; 111 | pub fn physPinToGpio(physPin: ::libc::c_int) -> ::libc::c_int; 0; 112 | pub fn setPadDrive(group: ::libc::c_int, value: ::libc::c_int) -> (); (); 113 | pub fn getAlt(pin: ::libc::c_int) -> ::libc::c_int; 0; 114 | pub fn pwmToneWrite(pin: ::libc::c_int, freq: ::libc::c_int) -> (); (); 115 | pub fn digitalWriteByte(value: ::libc::c_int) -> (); (); 116 | pub fn digitalReadByte() -> ::libc::c_uint; 0; 117 | pub fn pwmSetMode(mode: ::libc::c_int) -> (); (); 118 | pub fn pwmSetRange(range: ::libc::c_uint) -> (); (); 119 | pub fn pwmSetClock(divisor: ::libc::c_int) -> (); (); 120 | pub fn gpioClockSet(pin: ::libc::c_int, freq: ::libc::c_int) -> (); (); 121 | pub fn waitForInterrupt(pin: ::libc::c_int, mS: ::libc::c_int) 122 | -> ::libc::c_int; 0; 123 | pub fn wiringPiISR(pin: ::libc::c_int, mode: ::libc::c_int, 124 | function: ::std::option::Option) 125 | -> ::libc::c_int; 0; 126 | pub fn piThreadCreate(fn_: 127 | ::std::option::Option 130 | *mut ::libc::c_void>) 131 | -> ::libc::c_int; 0; 132 | pub fn piLock(key: ::libc::c_int) -> (); (); 133 | pub fn piUnlock(key: ::libc::c_int) -> (); (); 134 | pub fn piHiPri(pri: ::libc::c_int) -> ::libc::c_int; 0; 135 | pub fn delay(howLong: ::libc::c_uint) -> (); (); 136 | pub fn delayMicroseconds(howLong: ::libc::c_uint) -> (); (); 137 | pub fn millis() -> ::libc::c_uint; 0; 138 | pub fn micros() -> ::libc::c_uint; 0; 139 | pub fn softPwmCreate(pin: ::libc::c_int, value: ::libc::c_int, 140 | range: ::libc::c_int) -> ::libc::c_int; 0; 141 | pub fn softPwmWrite(pin: ::libc::c_int, value: ::libc::c_int) -> (); (); 142 | pub fn softPwmStop(pin: ::libc::c_int) -> (); (); 143 | } 144 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![doc(html_root_url = "http://ogeon.github.io/docs/rust-wiringpi/master/")] 2 | 3 | #![cfg_attr(feature = "strict", deny(warnings))] 4 | 5 | extern crate libc; 6 | 7 | use std::marker::PhantomData; 8 | 9 | use pin::{Pin, Pwm, GpioClock, RequiresRoot}; 10 | 11 | macro_rules! impl_pins { 12 | ($($name:ident),+) => ( 13 | $( 14 | #[derive(Clone, Copy)] 15 | pub struct $name; 16 | 17 | impl Pin for $name {} 18 | )+ 19 | ) 20 | } 21 | 22 | macro_rules! impl_pwm { 23 | ($($name:ident: $pwm:expr),+) => ( 24 | $( 25 | impl Pwm for $name { 26 | #[inline] 27 | fn pwm_pin() -> PwmPin<$name> { 28 | PwmPin::new($pwm) 29 | } 30 | } 31 | )+ 32 | ) 33 | } 34 | 35 | macro_rules! impl_clock { 36 | ($($name:ident: $pwm:expr),+) => ( 37 | $( 38 | impl GpioClock for $name { 39 | #[inline] 40 | fn clock_pin() -> ClockPin<$name> { 41 | ClockPin::new($pwm) 42 | } 43 | } 44 | )+ 45 | ) 46 | } 47 | 48 | macro_rules! require_root { 49 | ($($name:ident),+) => ( 50 | $( 51 | impl RequiresRoot for $name {} 52 | )+ 53 | ) 54 | } 55 | 56 | mod bindings; 57 | 58 | pub mod thread { 59 | use bindings; 60 | use libc; 61 | 62 | ///This attempts to shift your program (or thread in a multi-threaded 63 | ///program) to a higher priority and enables a real-time scheduling. 64 | /// 65 | ///The priority parameter should be from 0 (the default) to 99 (the 66 | ///maximum). This won’t make your program go any faster, but it will give 67 | ///it a bigger slice of time when other programs are running. The priority 68 | ///parameter works relative to others – so you can make one program 69 | ///priority 1 and another priority 2 and it will have the same effect as 70 | ///setting one to 10 and the other to 90 (as long as no other programs are 71 | ///running with elevated priorities) 72 | /// 73 | ///The return value is `true` for success and `false` for error. If an 74 | ///error is returned, the program should then consult the _errno_ global 75 | ///variable, as per the usual conventions. 76 | /// 77 | ///_Note_: Only programs running as root can change their priority. If 78 | ///called from a non-root program then nothing happens. 79 | pub fn priority(priority: u8) -> bool { 80 | unsafe { 81 | bindings::piHiPri(priority as libc::c_int) >= 0 82 | } 83 | } 84 | } 85 | 86 | pub mod pin { 87 | use bindings; 88 | use libc; 89 | use self::Value::{Low, High}; 90 | 91 | use std::marker::PhantomData; 92 | 93 | const INPUT: libc::c_int = 0; 94 | const OUTPUT: libc::c_int = 1; 95 | const PWM_OUTPUT: libc::c_int = 2; 96 | const GPIO_CLOCK: libc::c_int = 3; 97 | //const SOFT_PWM_OUTPUT: libc::c_int = 4; 98 | //const SOFT_TONE_OUTPUT: libc::c_int = 5; 99 | //const PWM_TONE_OUTPUT: libc::c_int = 6; 100 | 101 | ///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin. 102 | /// 103 | ///It takes the board revision into account. 104 | pub fn wpi_to_gpio_number(wpi_number: u16) -> u16 { 105 | unsafe { 106 | bindings::wpiPinToGpio(wpi_number as libc::c_int) as u16 107 | } 108 | } 109 | 110 | ///This returns the BCM_GPIO pin number of the supplied physical pin on 111 | ///the P1 connector. 112 | pub fn phys_to_gpio_number(phys_number: u16) -> u16 { 113 | unsafe { 114 | bindings::physPinToGpio(phys_number as libc::c_int) as u16 115 | } 116 | } 117 | 118 | impl_pins!(WiringPi, Gpio, Phys, Sys); 119 | impl_pwm!(WiringPi: 1, Gpio: 18, Phys: 12); 120 | impl_clock!(WiringPi: 7, Gpio: 4, Phys: 7); 121 | require_root!(WiringPi, Gpio, Phys); 122 | 123 | pub trait Pin {} 124 | 125 | pub trait Pwm: RequiresRoot + Sized { 126 | fn pwm_pin() -> PwmPin; 127 | } 128 | 129 | pub trait GpioClock: RequiresRoot + Sized { 130 | fn clock_pin() -> ClockPin; 131 | } 132 | 133 | pub trait RequiresRoot: Pin {} 134 | 135 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 136 | pub enum Value { 137 | Low = 0, 138 | High 139 | } 140 | 141 | #[derive(Debug, Clone, Copy)] 142 | pub enum Edge { 143 | ///No setup is performed, it is assumed the trigger has already been set up previosuly 144 | Setup = 0, 145 | Falling = 1, 146 | Rising = 2, 147 | Both = 3 148 | } 149 | 150 | #[derive(Debug, Clone, Copy)] 151 | pub enum Pull { 152 | Off = 0, 153 | Down, 154 | Up 155 | } 156 | 157 | #[derive(Debug, Clone, Copy)] 158 | pub enum PwmMode { 159 | MarkSpace = 0, 160 | Balanced 161 | } 162 | 163 | pub struct InputPin(libc::c_int, PhantomData); 164 | 165 | impl InputPin

{ 166 | pub fn new(pin: libc::c_int) -> InputPin

{ 167 | unsafe { 168 | bindings::pinMode(pin, INPUT); 169 | } 170 | 171 | InputPin(pin, PhantomData) 172 | } 173 | 174 | #[inline] 175 | pub fn number(&self) -> libc::c_int { 176 | let &InputPin(number, _) = self; 177 | number 178 | } 179 | 180 | ///This function returns the value read at the given pin. 181 | /// 182 | ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin. 183 | pub fn digital_read(&self) -> Value { 184 | let value = unsafe { 185 | bindings::digitalRead(self.number()) 186 | }; 187 | 188 | if value == 0 { 189 | Low 190 | } else { 191 | High 192 | } 193 | } 194 | 195 | ///This returns the value read on the supplied analog input pin. You 196 | ///will need to register additional analog modules to enable this 197 | ///function for devices such as the Gertboard, quick2Wire analog 198 | ///board, etc. 199 | pub fn analog_read(&self) -> u16 { 200 | unsafe { 201 | bindings::analogRead(self.number()) as u16 202 | } 203 | } 204 | 205 | /// This will register an "Interrupt" to be called when the pin changes state 206 | /// Note the quotes around Interrupt, because the current implementation in the C 207 | /// library seems to be a dedicated thread that polls the gpio device driver, 208 | /// and this callback is called from that thread synchronously, so it's not something that 209 | /// you would call a real interrupt in an embedded environement. 210 | /// 211 | /// The callback function does not need to be reentrant. 212 | /// 213 | /// The callback must be an actual function (not a closure!), and must be using 214 | /// the extern "C" modifier so that it can be passed to the wiringpi library, 215 | /// and called from C code. 216 | /// 217 | /// Unfortunately the C implementation does not allow userdata to be passed around, 218 | /// so the callback must be able to determine what caused the interrupt just by the 219 | /// function that was invoked. 220 | /// 221 | /// See https://github.com/Ogeon/rust-wiringpi/pull/28 for 222 | /// ideas on how to work around these limitations if you find them too constraining. 223 | /// 224 | /// ``` 225 | /// use wiringpi; 226 | /// 227 | /// extern "C" fn change_state() { 228 | /// println!("Look ma, I'm being called from an another thread"); 229 | /// } 230 | /// 231 | /// fn main() { 232 | /// let pi = wiringpi::setup(); 233 | /// let pin = pi.output_pin(0); 234 | /// 235 | /// pin.register_isr(Edge::Falling, Some(change_state)); 236 | /// 237 | /// thread::sleep(60000); 238 | /// } 239 | /// 240 | /// ``` 241 | /// 242 | /// 243 | pub fn register_isr(&self, edge: Edge, f: Option) { 244 | unsafe { 245 | bindings::wiringPiISR(self.number(), edge as i32, f); 246 | } 247 | } 248 | } 249 | 250 | impl InputPin

{ 251 | ///This sets the pull-up or pull-down resistor mode on the given pin. 252 | /// 253 | ///Unlike the Arduino, the BCM2835 has both pull-up an down internal 254 | ///resistors. The parameter pud should be; `Off`, (no pull up/down), 255 | ///`Down` (pull to ground) or `Up` (pull to 3.3v) 256 | pub fn pull_up_dn_control(&self, pud: Pull) { 257 | unsafe { 258 | bindings::pullUpDnControl(self.number(), pud as libc::c_int); 259 | } 260 | } 261 | 262 | pub fn into_output(self) -> OutputPin

{ 263 | let InputPin(number, _) = self; 264 | OutputPin::new(number) 265 | } 266 | 267 | pub fn into_soft_pwm(self) -> SoftPwmPin

{ 268 | let InputPin(number, _) = self; 269 | SoftPwmPin::new(number) 270 | } 271 | } 272 | 273 | impl InputPin

{ 274 | pub fn into_pwm(self) -> PwmPin

{ 275 | let InputPin(number, _) = self; 276 | PwmPin::new(number) 277 | } 278 | } 279 | 280 | impl InputPin

{ 281 | pub fn into_clock(self) -> ClockPin

{ 282 | let InputPin(number, _) = self; 283 | ClockPin::new(number) 284 | } 285 | } 286 | 287 | /// A pin with software controlled PWM output. 288 | /// 289 | /// Due to limitations of the chip only one pin is able to do 290 | /// hardware-controlled PWM output. The `SoftPwmPin`s on the 291 | /// other hand allow for all GPIOs to output PWM signals. 292 | /// 293 | /// The pulse width of the signal will be 100μs with a value range 294 | /// of [0,100] \(where `0` is a constant low and `100` is a 295 | /// constant high) resulting in a frequenzy of 100 Hz. 296 | /// 297 | /// **Important**: In order to use software PWM pins *wiringPi* 298 | /// has to be setup in GPIO mode via `setup_gpio()`. 299 | pub struct SoftPwmPin(libc::c_int, PhantomData); 300 | 301 | impl SoftPwmPin

{ 302 | /// Configures the given `pin` to output a software controlled PWM 303 | /// signal. 304 | pub fn new(pin: libc::c_int) -> SoftPwmPin

{ 305 | unsafe { 306 | bindings::softPwmCreate(pin, 0, 100); 307 | } 308 | 309 | SoftPwmPin(pin, PhantomData) 310 | } 311 | 312 | #[inline] 313 | pub fn number(&self) -> libc::c_int { 314 | let &SoftPwmPin(number, _) = self; 315 | number 316 | } 317 | 318 | /// Sets the duty cycle. 319 | /// 320 | /// `value` has to be in the interval [0,100]. 321 | pub fn pwm_write(&self, value: libc::c_int) { 322 | unsafe { 323 | bindings::softPwmWrite(self.number(), value); 324 | } 325 | } 326 | 327 | /// Stops the software handling of this pin. 328 | /// 329 | /// _Note_: In order to control this pin via software PWM again 330 | /// it will need to be recreated using `new()`. 331 | pub fn pwm_stop(self) { 332 | unsafe { 333 | bindings::softPwmStop(self.number()); 334 | } 335 | } 336 | 337 | pub fn into_input(self) -> InputPin

{ 338 | let SoftPwmPin(number, _) = self; 339 | self.pwm_stop(); 340 | InputPin::new(number) 341 | } 342 | 343 | pub fn into_output(self) -> OutputPin

{ 344 | let SoftPwmPin(number, _) = self; 345 | self.pwm_stop(); 346 | OutputPin::new(number) 347 | } 348 | 349 | } 350 | 351 | impl SoftPwmPin

{ 352 | pub fn into_pwm(self) -> PwmPin

{ 353 | let SoftPwmPin(number, _) = self; 354 | self.pwm_stop(); 355 | PwmPin::new(number) 356 | } 357 | } 358 | 359 | impl SoftPwmPin

{ 360 | pub fn into_clock(self) -> ClockPin

{ 361 | let SoftPwmPin(number, _) = self; 362 | self.pwm_stop(); 363 | ClockPin::new(number) 364 | } 365 | } 366 | 367 | pub struct OutputPin(libc::c_int, PhantomData); 368 | 369 | impl OutputPin

{ 370 | pub fn new(pin: libc::c_int) -> OutputPin

{ 371 | unsafe { 372 | bindings::pinMode(pin, OUTPUT); 373 | } 374 | 375 | OutputPin(pin, PhantomData) 376 | } 377 | 378 | #[inline] 379 | pub fn number(&self) -> libc::c_int { 380 | let &OutputPin(number, _) = self; 381 | number 382 | } 383 | 384 | ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output. 385 | pub fn digital_write(&self, value: Value) { 386 | unsafe { 387 | bindings::digitalWrite(self.number(), value as libc::c_int); 388 | } 389 | } 390 | 391 | ///This writes the given value to the supplied analog pin. You will 392 | ///need to register additional analog modules to enable this function 393 | ///for devices such as the Gertboard. 394 | pub fn analog_write(&self, value: u16) { 395 | unsafe { 396 | bindings::analogWrite(self.number(), value as libc::c_int); 397 | } 398 | } 399 | 400 | } 401 | 402 | impl OutputPin

{ 403 | pub fn into_soft_pwm(self) -> SoftPwmPin

{ 404 | let OutputPin(number, _) = self; 405 | SoftPwmPin::new(number) 406 | } 407 | } 408 | 409 | impl OutputPin

{ 410 | pub fn into_input(self) -> InputPin

{ 411 | let OutputPin(number, _) = self; 412 | InputPin::new(number) 413 | } 414 | } 415 | 416 | impl OutputPin

{ 417 | pub fn into_pwm(self) -> PwmPin

{ 418 | let OutputPin(number, _) = self; 419 | PwmPin::new(number) 420 | } 421 | } 422 | 423 | impl OutputPin

{ 424 | pub fn into_clock(self) -> ClockPin

{ 425 | let OutputPin(number, _) = self; 426 | ClockPin::new(number) 427 | } 428 | } 429 | 430 | ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual. 431 | pub struct PwmPin(libc::c_int, PhantomData); 432 | 433 | impl PwmPin

{ 434 | pub fn new(pin: libc::c_int) -> PwmPin

{ 435 | unsafe { 436 | bindings::pinMode(pin, PWM_OUTPUT); 437 | } 438 | 439 | PwmPin(pin, PhantomData) 440 | } 441 | 442 | #[inline] 443 | pub fn number(&self) -> libc::c_int { 444 | let &PwmPin(number, _) = self; 445 | number 446 | } 447 | 448 | pub fn into_input(self) -> InputPin

{ 449 | let PwmPin(number, _) = self; 450 | InputPin::new(number) 451 | } 452 | 453 | pub fn into_output(self) -> OutputPin

{ 454 | let PwmPin(number, _) = self; 455 | OutputPin::new(number) 456 | } 457 | 458 | pub fn into_soft_pwm(self) -> SoftPwmPin

{ 459 | let PwmPin(number, _) = self; 460 | SoftPwmPin::new(number) 461 | } 462 | 463 | ///Writes the value to the PWM register for the given pin. 464 | /// 465 | ///The value must be between 0 and 1024. 466 | pub fn write(&self, value: u16) { 467 | unsafe { 468 | bindings::pwmWrite(self.number(), value as libc::c_int); 469 | } 470 | } 471 | 472 | ///The PWM generator can run in 2 modes – "balanced" and "mark:space". 473 | /// 474 | ///The mark:space mode is traditional, however the default mode in the 475 | ///Pi is "balanced". You can switch modes by supplying the parameter: 476 | ///`Balanced` or `MarkSpace`. 477 | pub fn set_mode(&self, mode: PwmMode) { 478 | unsafe { 479 | bindings::pwmSetMode(mode as libc::c_int); 480 | } 481 | } 482 | 483 | ///This sets the range register in the PWM generator. The default is 1024. 484 | pub fn set_range(&self, value: u16) { 485 | unsafe { 486 | bindings::pwmSetRange(value as libc::c_uint); 487 | } 488 | } 489 | 490 | ///This sets the divisor for the PWM clock. 491 | pub fn set_clock(&self, value: u16) { 492 | unsafe { 493 | bindings::pwmSetClock(value as libc::c_int); 494 | } 495 | } 496 | } 497 | 498 | pub struct ClockPin(libc::c_int, PhantomData); 499 | 500 | impl ClockPin

{ 501 | pub fn new(pin: libc::c_int) -> ClockPin

{ 502 | unsafe { 503 | bindings::pinMode(pin, GPIO_CLOCK); 504 | } 505 | 506 | ClockPin(pin, PhantomData) 507 | } 508 | 509 | #[inline] 510 | pub fn number(&self) -> libc::c_int { 511 | let &ClockPin(number, _) = self; 512 | number 513 | } 514 | 515 | pub fn into_input(self) -> InputPin

{ 516 | let ClockPin(number, _) = self; 517 | InputPin::new(number) 518 | } 519 | 520 | pub fn into_output(self) -> OutputPin

{ 521 | let ClockPin(number, _) = self; 522 | OutputPin::new(number) 523 | } 524 | 525 | pub fn into_soft_pwm(self) -> SoftPwmPin

{ 526 | let ClockPin(number, _) = self; 527 | SoftPwmPin::new(number) 528 | } 529 | 530 | ///Set the freuency on a GPIO clock pin. 531 | pub fn frequency(&self, freq: u16) { 532 | unsafe { 533 | bindings::gpioClockSet(self.number(), freq as libc::c_int); 534 | } 535 | } 536 | } 537 | } 538 | 539 | ///This initialises the wiringPi system and assumes that the calling program 540 | ///is going to be using the **wiringPi** pin numbering scheme. 541 | /// 542 | ///This is a simplified numbering scheme which provides a mapping from virtual 543 | ///pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers. 544 | ///See the pins page for a table which maps the **wiringPi** pin number to the 545 | ///Broadcom GPIO pin number to the physical location on the edge connector. 546 | /// 547 | ///This function needs to be called with root privileges. 548 | pub fn setup() -> WiringPi { 549 | unsafe { bindings::wiringPiSetup(); } 550 | WiringPi(PhantomData) 551 | } 552 | 553 | ///This is identical to `setup()`, however it allows the calling programs to 554 | ///use the Broadcom GPIO pin numbers directly with no re-mapping. 555 | /// 556 | ///This function needs to be called with root privileges. 557 | pub fn setup_gpio() -> WiringPi { 558 | unsafe { bindings::wiringPiSetupGpio(); } 559 | WiringPi(PhantomData) 560 | } 561 | 562 | ///This is identical to `setup()`, however it allows the calling programs to 563 | ///use the physical pin numbers _on the P1 connector only_. 564 | /// 565 | ///This function needs to be called with root privileges. 566 | pub fn setup_phys() -> WiringPi { 567 | unsafe { bindings::wiringPiSetupPhys(); } 568 | WiringPi(PhantomData) 569 | } 570 | 571 | ///This initialises the wiringPi system but uses the /sys/class/gpio interface 572 | ///rather than accessing the hardware directly. 573 | /// 574 | ///This can be called as a non-root user provided the GPIO pins have been 575 | ///exported before-hand using the gpio program. Pin number in this mode is the 576 | ///native Broadcom GPIO numbers. 577 | /// 578 | ///_Note_: In this mode you can only use the pins which have been exported via 579 | ///the /sys/class/gpio interface. You must export these pins before you call 580 | ///your program. You can do this in a separate shell-script, or by using the 581 | ///system() function from inside your program. 582 | /// 583 | ///Also note that some functions have no effect when using this mode as 584 | ///they’re not currently possible to action unless called with root 585 | ///privileges. 586 | pub fn setup_sys() -> WiringPi { 587 | unsafe { bindings::wiringPiSetupSys(); } 588 | WiringPi(PhantomData) 589 | } 590 | 591 | ///This returns the board revision of the Raspberry Pi. 592 | /// 593 | ///It will be either 1 or 2. Some of the BCM_GPIO pins changed number and 594 | ///function when moving from board revision 1 to 2, so if you are using 595 | ///BCM_GPIO pin numbers, then you need to be aware of the differences. 596 | pub fn board_revision() -> i32 { 597 | unsafe { 598 | bindings::piBoardRev() 599 | } 600 | } 601 | 602 | pub struct WiringPi(PhantomData); 603 | 604 | impl WiringPi

{ 605 | pub fn input_pin(&self, pin: u16) -> pin::InputPin

{ 606 | let pin = pin as libc::c_int; 607 | pin::InputPin::new(pin) 608 | } 609 | 610 | pub fn output_pin(&self, pin: u16) -> pin::OutputPin

{ 611 | let pin = pin as libc::c_int; 612 | pin::OutputPin::new(pin) 613 | } 614 | 615 | ///This returns a number representing the number if milliseconds since 616 | ///your program called one of the setup functions. 617 | /// 618 | ///It returns an unsigned 32-bit number which wraps after 49 days. 619 | pub fn millis(&self) -> u32 { 620 | unsafe { 621 | bindings::millis() 622 | } 623 | } 624 | 625 | ///This returns a number representing the number if microseconds since 626 | ///your program called one of the setup functions. 627 | /// 628 | ///It returns an unsigned 32-bit number which wraps after 71 minutes. 629 | pub fn micros(&self) -> u32 { 630 | unsafe { 631 | bindings::micros() 632 | } 633 | } 634 | 635 | ///This writes the 8-bit byte supplied to the first 8 GPIO pins. It’s the 636 | ///fastest way to set all 8 bits at once to a particular value, although 637 | ///it still takes two write operations to the Pi’s GPIO hardware. 638 | pub fn digital_write_byte(&self, byte: u8) { 639 | unsafe { 640 | bindings::digitalWriteByte(byte as libc::c_int); 641 | } 642 | } 643 | } 644 | 645 | impl WiringPi

{ 646 | pub fn pwm_pin(&self) -> pin::PwmPin

{ 647 | Pwm::pwm_pin() 648 | } 649 | } 650 | 651 | impl WiringPi

{ 652 | pub fn clock_pin(&self) -> pin::ClockPin

{ 653 | GpioClock::clock_pin() 654 | } 655 | } 656 | 657 | impl WiringPi

{ 658 | pub fn soft_pwm_pin(&self, pin: u16) -> pin::SoftPwmPin

{ 659 | let pin = pin as libc::c_int; 660 | pin::SoftPwmPin::new(pin) 661 | } 662 | } 663 | --------------------------------------------------------------------------------