├── t └── 0-load-module.t ├── MANIFEST ├── lib ├── RPi │ ├── GPIO │ │ └── Pin.pm6 │ ├── GPIO.pm6 │ └── Wiring.pm6 └── RPi.pm6 ├── META.info ├── bin └── example-1.p6 └── README.md /t/0-load-module.t: -------------------------------------------------------------------------------- 1 | use Test; 2 | use RPi; 3 | 4 | plan 1; 5 | 6 | ok(1, 'Module loaded'); 7 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | META.info 2 | MANIFEST 3 | lib/RPi.pm6 4 | lib/RPi 5 | lib/RPi/Device 6 | lib/RPi/Device/DS18B20 7 | lib/RPi/Device/DS18B20/Sensor.pm6 8 | lib/RPi/Device/DS18B20.pm6 9 | lib/RPi/GPIO 10 | lib/RPi/GPIO/Pin.pm6 11 | lib/RPi/GPIO.pm6 12 | lib/RPi/Wiring.pm6 13 | bin/example-1.p6 14 | t/0-load-module.t 15 | README.md 16 | -------------------------------------------------------------------------------- /lib/RPi/GPIO/Pin.pm6: -------------------------------------------------------------------------------- 1 | class RPi::GPIO::Pin { 2 | use RPi::Wiring; 3 | 4 | has Int $.id; 5 | has RPiPinMode $!mode; 6 | 7 | method mode(RPiPinMode $mode) { 8 | $!mode = $mode; 9 | RPi::Wiring::set-pin-mode(self.id, $mode) 10 | } 11 | 12 | method write(RPiPinValue $value) { 13 | RPi::Wiring::digital-write(self.id, $value) 14 | } 15 | 16 | method read() returns Int { 17 | return RPi::Wiring::digital-read(self.id) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /META.info: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "RPi", 3 | "version" : "0.1.1", 4 | "description" : "RPi - An interface to the Raspberry Pi's GPIO and other peripherals", 5 | "author" : "Cory Spencer", 6 | "provides" : { 7 | "RPi" : "lib/RPi.pm6", 8 | "RPi::Wiring" : "lib/RPi/Wiring.pm6", 9 | "RPi::GPIO" : "lib/RPi/GPIO.pm6", 10 | "RPi::GPIO::Pin" : "lib/RPi/GPIO/Pin.pm6" 11 | }, 12 | "test-depends" : [ "Test" ], 13 | "depends" : [ "POSIX" ], 14 | "source-url" : "https://github.com/cspencer/perl6-raspberry-pi.git" 15 | } -------------------------------------------------------------------------------- /bin/example-1.p6: -------------------------------------------------------------------------------- 1 | #! env perl6 2 | 3 | use RPi; 4 | 5 | MAIN: { 6 | # List of the pins we're using. 7 | my @pin-ids = (8, 9, 7, 0); 8 | 9 | # Create a new RPi object. 10 | my $rpi = RPi.new(); 11 | 12 | # Indicate we're going to use the WiringPi numbering scheme. 13 | $rpi.gpio(mode => WIRING); 14 | 15 | # Drop privileges from 'root' to the 'pi' user. 16 | $rpi.drop-privileges('pi', 'pi'); 17 | 18 | # Get a list of all the GPIO pins. 19 | my @pins = $rpi.gpio.pins; 20 | 21 | # Clear all the pins by setting them to HIGH. 22 | for @pins -> $pin { 23 | $pin.mode(OUTPUT); 24 | $pin.write(HIGH); 25 | } 26 | 27 | # Walk through the list of pins we're using, turning them on and 28 | # off for half a second. 29 | for 1..10 -> $i { 30 | for @pin-ids -> $p { 31 | my $pin = @pins[$p]; 32 | 33 | $pin.write(LOW); 34 | $rpi.delay(500); 35 | $pin.write(HIGH); 36 | } 37 | } 38 | 39 | # Restore the GPIO pins to their original state. 40 | $rpi.gpio.cleanup(); 41 | } 42 | -------------------------------------------------------------------------------- /lib/RPi.pm6: -------------------------------------------------------------------------------- 1 | class RPi { 2 | use RPi::Wiring; 3 | use RPi::GPIO; 4 | use POSIX; 5 | 6 | has RPi::GPIO $!gpio; 7 | 8 | method drop-privileges(Str $user, Str $group) returns Bool { 9 | return self.set-group($group) && self.set-user($user) 10 | } 11 | 12 | method set-user(Str $user) returns Bool { 13 | # Retrieve the passwd struct for the provided username. 14 | my $user-info = getpwnam($user); 15 | 16 | # Throw an exception if we weren't able to retrieve the passwd struct 17 | # for the provided username. 18 | die "Unknown user: $user" if ! $user-info.defined; 19 | 20 | # Set the UID. 21 | my $res = setuid($user-info.uid); 22 | die "Couldn't set user to: $user. Are you running as root?" 23 | if $res == -1; 24 | 25 | return True; 26 | } 27 | 28 | method set-group(Str $group) returns Bool { 29 | # Retrieve the group struct for the provided group. 30 | my $group-info = getgrnam($group); 31 | 32 | # Throw an exception if we weren't able to retrieve the group struct 33 | # for the provided group. 34 | die "Unknown group: $group" if ! $group-info.defined; 35 | 36 | # Set the GID. 37 | my $res = setgid($group-info.gid); 38 | die "Couldn't set group to: $group. Are you running as root?" 39 | if $res == -1; 40 | 41 | return True; 42 | } 43 | 44 | method gpio(RPiGPIOMode :$mode = BCM) { 45 | return (! $!gpio.defined) ?? ($!gpio = RPi::GPIO.new(mode => $mode)) !! $!gpio; 46 | } 47 | 48 | method delay(Int $milliseconds where $milliseconds >= 0) { 49 | return RPi::Wiring::delay-milliseconds($milliseconds) 50 | } 51 | 52 | method revision() returns Int { 53 | return RPi::Wiring::board-revision(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /lib/RPi/GPIO.pm6: -------------------------------------------------------------------------------- 1 | class RPi::GPIO { 2 | use RPi::GPIO::Pin; 3 | use RPi::Wiring; 4 | use NativeCall; 5 | use POSIX; 6 | 7 | has RPiGPIOMode $.mode; 8 | 9 | has @.pins; 10 | has %!initial-state; 11 | 12 | submethod BUILD(:$mode) { 13 | my $uid = getuid(); 14 | 15 | # The GPIO setup routines must be run as the root user. 16 | die "RPi must be initialized as root" if ($uid != 0); 17 | 18 | my @pins; 19 | given $mode { 20 | when WIRING { 21 | # Use the simplified pin numbering scheme implemented by the WiringPi library. 22 | RPi::Wiring::setup(); 23 | given RPi::Wiring::board-revision() { 24 | when 1 { @pins = 0..16 }; 25 | when 2 { @pins = (flat 0..16, 21..31) }; 26 | } 27 | } 28 | 29 | when BCM { 30 | # Use the Broadcom GPIO pin numberings. 31 | RPi::Wiring::setup-gpio(); 32 | do given RPi::Wiring::board-revision() { 33 | when 1 { @pins = (flat 0, 1, 4, 7..11, 14, 15, 17, 18, 21..25) }; 34 | when 2 { @pins = (flat 2, 3, 4, 7..11, 14, 15, 17, 18, 22..25) }; 35 | } 36 | } 37 | } 38 | 39 | @!pins = @pins.map: { RPi::GPIO::Pin.new(id => $_) }; 40 | $!mode = $mode; 41 | 42 | # Preserve the initial state of the GPIO pins so that they can be restored upon 43 | # exit, if requested. 44 | %!initial-state = @!pins.map: { ($_.id => $_.read()) }; 45 | } 46 | 47 | 48 | method read(RPi::GPIO::Pin $pin) returns Int { 49 | return $pin.read(); 50 | } 51 | 52 | method write(RPi::GPIO::Pin $pin, RPiPinValue $value) { 53 | $pin.value($value); 54 | } 55 | 56 | method cleanup() { 57 | # Restore the initial state of the GPIO pins. 58 | for keys %!initial-state -> $pin { 59 | RPi::Wiring::digital-write(+$pin, %!initial-state{$pin}); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/RPi/Wiring.pm6: -------------------------------------------------------------------------------- 1 | enum RPiGPIOMode ; 2 | enum RPiPinMode ; 3 | enum RPiPinValue ; 4 | enum RPiEdgeMode ; 5 | 6 | package RPi::Wiring { 7 | use NativeCall; 8 | 9 | # Setup Functions 10 | our sub setup() returns int32 is native('wiringPi') is symbol('wiringPiSetup') { * }; 11 | our sub setup-gpio() returns int32 is native('wiringPi') is symbol('wiringPiSetupGpio') { * }; 12 | our sub setup-physical() returns int32 is native('wiringPi') is symbol('wiringPiSetupPhys') { * }; 13 | our sub setup-sysclass() returns int32 is native('wiringPi') is symbol('wiringPiSetupSys') { * }; 14 | 15 | # Core Functions 16 | our sub set-pin-mode(int32, int32) is native('wiringPi') is symbol('pinMode') { * }; 17 | our sub set-pull-up-down(int32, int32) is native('wiringPi') is symbol('pullUpDnControl') { * }; 18 | our sub digital-write (int32, int32) is native('wiringPi') is symbol('digitalWrite') { * }; 19 | our sub digital-read (int32) returns int32 is native('wiringPi') is symbol('digitalRead') { * }; 20 | our sub analog-write (int32, int32) is native('wiringPi') is symbol('analogWrite') { * }; 21 | our sub analog-read (int32) returns int32 is native('wiringPi') is symbol('analogRead') { * }; 22 | our sub pwm-write (int32, int32) is native('wiringPi') is symbol('pwmWrite') { * }; 23 | 24 | our sub board-revision() returns int32 is native('wiringPi') is symbol('piBoardRev') { * }; 25 | 26 | our sub milliseconds-since-setup returns uint32 is native('wiringPi') is symbol('millis') { * }; 27 | our sub microseconds-since-setup returns uint32 is native('wiringPi') is symbol('micros') { * }; 28 | 29 | our sub delay-milliseconds(uint32) is native('wiringPi') is symbol('delay') { * }; 30 | our sub delay-microseconds(uint32) is native('wiringPi') is symbol('delayMicroseconds') { * }; 31 | our &delay = &delay-milliseconds; 32 | 33 | # Interrupts 34 | our sub interrupt-handler(int32, int32, &callback ()) is native('wiringPi') is symbol('wiringPiISR') { * }; 35 | } 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Perl 6 - RPi 2 | ============ 3 | An interface to the Raspberry Pi's GPIO and other peripherals 4 | 5 | Overview 6 | -------- 7 | 8 | RPi is a Perl 6 interface to the Raspberry Pi's GPIO and other peripherals. It is still very early in development and should not be considered remotely stable or suitable for a production environment. 9 | 10 | Installation 11 | ------------ 12 | 13 | To use the RPi packages, you will require a Raspberry Pi, the WiringPi libraries, and an installation of a Perl 6 compiler. 14 | 15 | The WiringPi libraries should be installed before installing the Perl 6 modules. To install WiringPi, as the root user, run the following: 16 | 17 | ~# apt-get install wiringpi 18 | 19 | The Perl 6 compiler can be installed easily using the rakudobrew installer. You can find its installation documentation here: 20 | 21 | https://github.com/tadzik/rakudobrew 22 | 23 | Once rakudobrew has been installed, build the Panda package manager with: 24 | 25 | ~$ rakudobrew build-panda 26 | 27 | Panda will allow you to easily download and install the RPi package, as well as its dependencies. Once Panda has been installed, you should be able to download the RPi module using with: 28 | 29 | ~$ panda RPi 30 | 31 | Usage 32 | ----- 33 | 34 | # Load the RPi module. 35 | use RPi; 36 | 37 | # Create a new RPi object. 38 | my $rpi = RPi.new(); 39 | 40 | # Indicate we're going to use the WiringPi numbering scheme. 41 | $rpi.gpio(mode => WIRING); 42 | 43 | # Drop privileges from 'root' to the 'pi' user. 44 | $rpi.drop-privileges('pi', 'pi'); 45 | 46 | # Get a list of all the GPIO pins. 47 | my @pins = $rpi.gpio.pins; 48 | 49 | # Clear all the pins by setting them to HIGH. 50 | for @pins -> $pin { 51 | # Indicate we want to use the pin for OUTPUT. 52 | $pin.mode(OUTPUT); 53 | # Set the pin to HIGH. 54 | $pin.write(HIGH); 55 | } 56 | 57 | # Walk through the list of pins we're using, turning them on and 58 | # off for half a second. 59 | for 1..10 -> $i { 60 | for @pins -> $pin { 61 | # Set the pin to LOW. 62 | $pin.write(LOW); 63 | # Sleep for 500ms. 64 | $rpi.delay(500); 65 | # Set the pin to HIGH 66 | $pin.write(HIGH); 67 | } 68 | } 69 | 70 | # Restore the GPIO pins to their original state. 71 | $rpi.gpio.cleanup(); 72 | 73 | Supported Devices 74 | ----------------- 75 | 76 | * RPi::Device::DS18B20 - Module for the DS18B20 family of temperature sensors. 77 | 78 | Author 79 | ------ 80 | 81 | Cory Spencer --------------------------------------------------------------------------------