Recently we started our first experiments with Raspberry Pi using GPIO. Inspired by the existing access libraries and extensions for GPIO functions, we wanted to write our own implementation for security reasons. This article will give you an insight on why we pursued our own implementation and how we finally realised it.
What is Raspberry Pi
The Raspberry Pi is a Single Board Computer with the size of a credit card. This computer was developed in UK by the Raspberry Pi Foundation.
The Raspberry Pi has a Broadcom BCM2835 system on a chip (SoC), which includes an ARM1176JZF-S 700 MHz processor (The firmware includes a number of „Turbo“ modes so that the user can attempt overclocking, up-to 1 GHz, without affecting the warranty), VideoCore IV GPU and is shipped with 512 megabytes of RAM. It doesn’t include a built-in hard disk or solid-state drive, but it uses an SD card for booting and long-term storage.
We run the RaspberryPi with Raspbian “wheezy” Linux distribution (Downloaded from RaspberryPi Webpage).
GPIO on the Raspberry Pi (rpi)
GPIO (General Purpose Input/Output) is a part of Raspberry Pi.
On the Raspberry Pi there is a connector which permits you to access some pins of the GPIO:
The configuration and read/write operations to the GPIO are realised with the help of special registers in the memory address space. In the ARM CPU MMU (memory management unit) they are mapped from the VideoCore CPU Bus address MMU 0x7E200000 to the physical address 0x20200000 in the physical address space.
There are register to set the modus of the I/O pins (IN, OUT, PWM or other special modes like SPI), set output pins on/off, enable pullup/pulldown resistors, read input pins, set interrupts for input and some other functions. (for more details see Broadcom BCM2835 datasheet)
To access the register the /dev/mem device will be used! The /dev/mem gives access to the complete address space of the Linux System, so you can manipulate every other program that uses the memory (every running program will do this). For this reason only the root user can get write access to /dev/mem under Linux.
Therefore python, nodejs, php extension or libraries need to run as root user with open file descriptor to /dev/mem.
Why not using GPIO in Application with external access
This is a really big security issue if you run a services which is accessible from the web. So if there are some security holes in nodejs, PHP or Pyhton the intruder get direct access to the complete memory of the running system! They can manipulate everything.
The idea to prevent this is to use a small c server with a unix socket interface.
Concept of GPIO Unix Socket Server
For fast prototyping we use the wiringPi Library in the server implementation with the pin mapping from this library.
GPIO pin | wiringPi pin | function |
---|---|---|
17 | 0 | in/out |
18 | 1 | in/out |
(Rev1) 21 / (Rev2) 27 | 2 | in/out/PWM |
22 | 3 | in/out |
23 | 4 | in/out |
24 | 5 | in/out |
25 | 6 | in/out |
(Rev1)0/(Rev2)2 | 8 | in/out/((Rev1)SDA0/(Rev2)SDA1)(I²C) |
(Rev1)1/(Rev2)3 | 9 | in/out/((Rev1)SCL0/(Rev2)SCL1)(I²C) |
8 | 10 | in/out/CE0 (SPI Chipselect) |
7 | 11 | in/out/CE1 (SPI Chipselect) |
10 | 12 | in/out/MOSI (SPI) |
9 | 13 | in/out/MISO (SPI) |
11 | 14 | in/out/SCLK (SPI) |
14 | 15 | in/out/TxD |
15 | 16 | in/out/RxD |
This is a small c program which can run as daemon and reads the name of the unix socket file to create from the command line. We also create a pid file. With this precondition we can start the server on boot up time with a simple startup script.
Communication
The implementation has in this version a simple unix socket protocol with following ascii commands and responses:
- Read pin value
- READ {pinnumber}
- {pinnumber} {value}
- READ {pinnumber}
- Write value to output pin
- WRITE {pinnumber} {value}
- Ok
- WRITE {pinnumber} {value}
- Set Modus of the pin
- MODE {pinnumber} {modus}
- Ok
- MODE {pinnumber} {modus}
- Read status of all pins
- READALL
-
0 17 GPIO 0 {value}1 18 GPIO 1 {value}2 21 GPIO 2 {value}3 22 GPIO 3 {value}4 23 GPIO 4 {value}5 24 GPIO 5 {value}6 25 GPIO 6 {value}7 4 GPIO 7 {value}8 0 SDA {value}9 1 SCL {value}10 8 CE0 {value}11 7 CE1 {value}12 10 MOSI {value}13 9 MISO {value}14 11 SCLK {value}15 14 TxD {value}16 15 RxD {value}
-
- READALL
The {value} can be 0 or 1
The {pinnumber} is a wriningPi pin number, see the table above.
The {modus} can be IN or OUT
You can get the source code from the git repo github/ironpinguin/rpi-gpiod
Nodejs accessing sample
Here is a simple sample accessing the unix socket to read gpio
var net = require('net');
var socketPath = "/home/pi/nodeexample.sock";
var unixSocket = net.connect({path: socketPath},
function() {
console.log("socket open");
unixSocket.setEncoding('ascii');
});
unixSocket.on('data', function(data) {
console.log(data);
});
unixSocket.on('end', function() {
console.log("socket closed");
});
var socketCommand = "READALL";
unixSocket.write(socketCommand);
open todos
We want to extend the small server with following function in the next steps
- implement interrupt usage with this code for input pins.
- refactor the code so it can serve multiple unix socket connections
- extend protocol with identifier for every incoming command and the response
- extend protocol to register interrupts for pins
Schreibe einen Kommentar