unosquare/raspberryio

Name: raspberryio

Owner: Unosquare Labs

Description: The Raspberry Pi's IO Functionality in an easy-to-use API for Mono/.NET/C#

Created: 2016-11-20 14:47:41.0

Updated: 2018-05-24 22:22:28.0

Pushed: 2018-05-10 20:57:03.0

Homepage: https://unosquare.github.io/raspberryio

Size: 8998

Language: C#

GitHub Committers

UserMost Recent Commit# Commits

Other Committers

UserEmailMost Recent Commit# Commits

README

NuGet Analytics Build status Build Status

RaspberryIO - Pi's hardware access from .NET

:star: Please star this project if you find it useful!

The Raspberry Pi's IO Functionality in an easy-to-use API for .NET (Mono/.NET Core). Our mission is to make .NET a first-class citizen in the Python-centric community of Raspberry Pi developers.

Table of contents

Features

This library enables developers to use the various Raspberry Pi's hardware modules:

Please note you program needs to be run with `sudo. Example ``sudo mono myprogram.exe``` in order to work correctly.

This library depends on the wonderful `WiringPilibrary available [here](http://wiringpi.com/). You do not need to install this library yourself. The ``RaspberryIO``` assembly will automatically extract the compiled binary of the library in the same path as the entry assembly.

Peripherals

We offer an additional package with helpful classes to use peripherals, many of them are from pull requests from our contributors. The current set of peripherals supported are:

Installation

Install basic Raspberry.IO package: NuGet version

Install-Package Unosquare.Raspberry.IO

Install Raspberry.IO Peripherals package: NuGet version

Install-Package Unosquare.RaspberryIO.Peripherals
Running the latest version of Mono

It is recommended that you install the latest available release of Mono because what is available in the Raspbian repo is quite old (3.X). These commands were tested using Raspbian Jessie. The version of Mono that is installed at the time of this writing is:

 JIT compiler version 5.4.1.6 (tarball Wed Nov  8 21:42:16 UTC 2017)

The commands to get Mono installed are the following:

For Debian Wheezy
 apt-get update
 apt-get upgrade
 apt-get install mono-complete
 apt-get install dirmngr
 apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
 "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
 apt-get update
 apt-get dist-upgrade
For Debian Stretch
 apt-get update
 apt-get upgrade
 apt-get install mono-complete
 apt-get install dirmngr
 apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF
 "deb http://download.mono-project.com/repo/debian stretch main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list
 apt-get update
 apt-get dist-upgrade

Now, verify your version of Mono by running `mono --version`. Version 4.6 and above should be good enough.

Handy Notes

In order to setup Wi-Fi, run: sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

A good file should look like this:

try=US
_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
te_config=1

ork={
ssid="your_real_wifi_ssid"
scan_ssid=1
psk="your_real_password"

And then restart the services as follows:

 systemctl daemon-reload
 systemctl restart dhcpcd

You can also configure most boot options by running: sudo raspi-config

Running .NET Core 2

This project can also run in .NET Core 2.

Run the following commands to install .NET Core 2.

date Ubuntu 16.04
 apt-get -y update

stall the packages necessary for .NET Core
 apt-get -y install libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libcurl4-openssl-dev libssl-dev uuid-dev

wnload the latest binaries for .NET Core 2 
 https://dotnetcli.blob.core.windows.net/dotnet/Runtime/release/2.0.0/dotnet-runtime-latest-linux-arm.tar.gz

ke a directory for .NET Core to live in
r ~/dotnet

zip the binaries into the directory you just created
-xvf dotnet-runtime-latest-linux-arm.tar.gz -C ~/dotnet

w add the path to the dotnet executable to the environment path
is ensures the next time you log in, the dotnet exe is on your path
home/pi/dotnet
 "PATH=\$PATH:/home/pi/dotnet" >> dotnetcore.sh
 mv dotnetcore.sh /etc/profile.d

en run the command below to add the path to the dotnet executable to the current session
=$PATH:/home/ubuntu/dotnet

nally, you can:
 nano /etc/sudoers
d append to the secure_path option:
me/pi/dotnet
is will allow you to run dotnet in su mode

After that, you can reboot the raspberry. To check if dotnet is installed just run “dotnet” and a message should show. If you run into issues with error messages such as framework not found '2.0.0', it must be because the latest version might not be a stable version and the runtime is not rolled forward utomatically in this case. A simple solution is to create a 2.0.0 runtime symlink based on the current version. See the following link for detailed info: https://github.com/dotnet/cli/issues/7543

ocalhost~$ dotnet

e: dotnet [options]
e: dotnet [path-to-application]

ons:
|--help            Display help.
version         Display version.

-to-application:
e path to an application .dll file to execute.
Run the app on the raspberry
tu@ubuntu:~/publish$ sudo chmod u+x *
tu@ubuntu:~/publish$ ./Unosquare.RaspberryIO.Playground
The Camera Module

The `Pi.Cameramodule uses ``raspivid` andraspistill`` to access the camera so they must be installed in order for your program to work properly. `raspistillarguments are specified in an instance of the ``CameraStillSettings` class, while theraspivid`` arguments are specified in an instance of the `CameraVideoSettings` class.

Capturing Images

The `Pi.Camera.CaptureImage*methods simply return an array of bytes containing the captured image. There are synchronous and asynchronous falvors of these methods so you can use the familiar ``async` andawait`` pattern to capture your images. All `raspistillarguments (except for those that control user interaction such as ``-k`) are available via theCameraStillSettings``. To start, create a new instance of the `CameraStillSettingsclass and pass it on to your choice of the ``Pi.Camera.CaptureImage*``` methods. There are shortcut methods available that simply take a JPEG image at the given Width and Height. By default, the shortcut methods set the JPEG quality at 90%.

Example using a shortcut method:

ic void TestCaptureImage()

var pictureBytes = Pi.Camera.CaptureImageJpeg(640, 480);
var targetPath = "/home/pi/picture.jpg";
if (File.Exists(targetPath))
    File.Delete(targetPath);

File.WriteAllBytes(targetPath, pictureBytes);
Console.WriteLine($"Took picture -- Byte count: {pictureBytes.Length}");

Example using a CaptureImage method:

ODO: example code here
Capturing Video

Capturing video streams is somewhat different but it is still very easy to do. The concept behind it is to Open a video stream providing your own callback. When opening the stream `Raspberry IO` will spawn a separate thread and will not block the execution of your code, but it will continually call your callback method containing the bytes that are being read from the camera until the Close method is called or until the timeout is reached.

Example of capturing a stream of H.264 video

ic void TestCaptureVideo()

// Setup our working variables
var videoByteCount = 0;
var videoEventCount = 0;
var startTime = DateTime.UtcNow;

// Configure video settings
var videoSettings = new CameraVideoSettings()
{
    CaptureTimeoutMilliseconds = 0,
    CaptureDisplayPreview = false,
    ImageFlipVertically = true,
    CaptureExposure = CameraExposureMode.Night,
    CaptureWidth = 1920,
    CaptureHeight = 1080
};

try
{
    // Start the video recording
    Pi.Camera.OpenVideoStream(videoSettings,
        onDataCallback: (data) => { videoByteCount += data.Length; videoEventCount++; },
        onExitCallback: null);

    // Wait for user interaction
    startTime = DateTime.UtcNow;
    Console.WriteLine("Press any key to stop reading the video stream . . .");
    Console.ReadKey(true);
}
catch (Exception ex)
{
    Console.WriteLine($"{ex.GetType()}: {ex.Message}");
}
finally
{
    // Always close the video stream to ensure raspivid quits
    Pi.Camera.CloseVideoStream();

    // Output the stats
    var megaBytesReceived = (videoByteCount / (1024f * 1024f)).ToString("0.000");
    var recordedSeconds = DateTime.UtcNow.Subtract(startTime).TotalSeconds.ToString("0.000");
    Console.WriteLine($"Capture Stopped. Received {megaBytesReceived} Mbytes in {videoEventCount} callbacks in {recordedSeconds} seconds");
}            

Obtaining Board and System Information
se note ```Pi.Info``` depends on ```Wiring Pi```, and the ```/proc/cpuinfo``` and ```/proc/meminfo``` files.

sing the GPIO Pins
reference for the B plus (B+) - Header P1

M | wPi | Name    | Mode | V   | L      | R      | V   | Mode | Name    | wPi | BCM |
- | --- | ------- | ---- | --- | ------ | ------ | --- | ---- | ------- | --- | --- |
  |     |    3.3v |      |     | **01** | **02** |     |      | 5v      |     |     |
2 |   8 |   SDA.1 | ALT0 | 1   | **03** | **04** |     |      | 5V      |     |     |
3 |   9 |   SCL.1 | ALT0 | 1   | **05** | **06** |     |      | 0v      |     |     |
4 |   7 | GPIO. 7 |   IN | 1   | **07** | **08** | 1   | ALT0 | TxD     | 15  | 14  |
  |     |      0v |      |     | **09** | **10** | 1   | ALT0 | RxD     | 16  | 15  |
7 |   0 | GPIO. 0 |   IN | 0   | **11** | **12** | 0   | IN   | GPIO. 1 | 1   | 18  |
7 |   2 | GPIO. 2 |   IN | 0   | **13** | **14** |     |      | 0v      |     |     |
2 |   3 | GPIO. 3 |   IN | 0   | **15** | **16** | 0   | IN   | GPIO. 4 | 4   | 23  |
  |     |    3.3v |      |     | **17** | **18** | 0   | IN   | GPIO. 5 | 5   | 24  |
0 |  12 |    MOSI |   IN | 0   | **19** | **20** |     |      | 0v      |     |     |
9 |  13 |    MISO |   IN | 0   | **21** | **22** | 0   | IN   | GPIO. 6 | 6   | 25  |
1 |  14 |    SCLK |   IN | 0   | **23** | **24** | 1   | IN   | CE0     | 10  | 8   |
  |     |      0v |      |     | **25** | **26** | 1   | IN   | CE1     | 11  | 7   |
0 |  30 |   SDA.0 |   IN | 1   | **27** | **28** | 1   | IN   | SCL.0   | 31  | 1   |
5 |  21 | GPIO.21 |   IN | 1   | **29** | **30** |     |      | 0v      |     |     |
6 |  22 | GPIO.22 |   IN | 1   | **31** | **32** | 0   | IN   | GPIO.26 | 26  | 12  |
3 |  23 | GPIO.23 |   IN | 0   | **33** | **34** |     |      | 0v      |     |     |
9 |  24 | GPIO.24 |   IN | 0   | **35** | **36** | 0   | IN   | GPIO.27 | 27  | 16  |
6 |  25 | GPIO.25 |   IN | 0   | **37** | **38** | 0   | IN   | GPIO.28 | 28  | 20  |
  |     |      0v |      |     | **39** | **40** | 0   | IN   | GPIO.29 | 29  | 21  |

wait for a second, Where are Wiring Pi (wPi) pins 17 through 20? The above diagram shows the pins of GPIO Header P1. There is an additional GPIO header on the Pi called P5. [More info available here](http://www.raspberrypi-spy.co.uk/2012/09/raspberry-pi-p5-header/)

rder to access the pins, use ```Pi.Gpio```. The pins can have multiple behaviors and fortunately ```Pi.Gpio``` can be iterated, addressed by index, addressed by Wiring Pi pin number and provides the pins as publicly accessible properties.

 is an example of addressing the pins in all the various ways:

public static void TestLedBlinking() {

// Get a reference to the pin you need to use.
// All 3 methods below are exactly equivalent
var blinkingPin = Pi.Gpio[0];
blinkingPin = Pi.Gpio[WiringPiPin.Pin00];
blinkingPin = Pi.Gpio.Pin00;

// Configure the pin as an output
blinkingPin.PinMode = GpioPinDriveMode.Output;

// perform writes to the pin by toggling the isOn variable
var isOn = false;
for (var i = 0; i < 20; i++)
{
    isOn = !isOn;
    blinkingPin.Write(isOn);
    System.Threading.Thread.Sleep(500);
}

}

Pin Information
pins have handy properties and methods that you can use to drive them. For example, you can examine the ```Capabilities``` property to find out which features are available on the pin. You can also use the ```PinMode``` property to get or set the operating mode of the pin. Please note that the value of the ```PinMode``` property is by default set to _Input_ and it will return the last mode you set the property to.

Digital Read and Write
s very easy to read and write values to the pins. In general, it is a 2-step process.
t the pin mode
ad or write the bit value

ing the value of a pin example:

Pi.Gpio.Pin02.PinMode = GpioPinDriveMode.Input; // The below lines are reoughly equivalent var isOn = Pi.Gpio.Pin02.Read(); // Reads as a boolean var pinValue = Pi.Gpio.Pin02.ReadValue(); // Reads as a GpioPinValue

ing to a pin example

Pi.Gpio.Pin02.PinMode = GpioPinDriveMode.Output; // The below lines are reoughly equivalent Pi.Gpio.Pin02.Write(true); // Writes a boolean Pi.Gpio.Pin02.Write(GpioPinValue.High); // Writes a pin value

Analog (Level) Read and Write


Hardware PWM


Software PWM


Tone Generation
can emit tones by using SoftToneFrequency. Example:

// Get a reference to the pin var passiveBuzzer = Pi.Gpio[WiringPiPin.Pin01]; // Set the frequency to Alto Do (523Hz) passiveBuzzer.SoftToneFrequency = 523 // Wait 1 second System.Threading.Thread.Sleep(1000); // And stop passiveBuzzer.SoftToneFrequency = 0;

Interrupts and Callbacks
ster an Interrupt Callback example:

using System; using Unosquare.RaspberryIO; using Unosquare.RaspberryIO.Gpio;

class Program { // Define the implementation of the delegate; static void ISRCallback() {

 Console.WriteLine("Pin Activated...");         

}

static void Main(string[] args) {

    Console.WriteLine("Gpio Interrupts");
    var pin = Pi.Gpio.Pin00;
    pin.PinMode = GpioPinDriveMode.Input;
    pin.RegisterInterruptCallback(EdgeDetection.FallingEdge, ISRCallback);
    Console.ReadKey();

} }

sing the SPI Bus
ally liked the following description from [Neil's Log Book](http://nrqm.ca/nrf24l01/serial-peripheral-interface/): _The SPI (Serial Peripheral Interface) protocol behaves like a ring buffer so that whenever the master sends a byte to the slave, the slave sends a byte back to the master. The slave can use this behavior to return a status byte, a response to a previous byte, or null data (the master may choose to read the returned byte or ignore it). The bus operates on a 4-wire interface._

In order to use an SPI channel you MUST always set the `Channel0Frequencyor ``Channel1Frequency` (depending on the channel you want to use) before calling theSendReceive`` method. If the property is not set beforehand the SPI channel will fail initialization. See an example below:

Example of using the SPI Bus

pi.Channel0Frequency = SpiChannel.MinFrequency;
request = System.Text.Encoding.ASCII.GetBytes("HELLO!");
response = Pi.Spi.Channel0.SendReceive(request);
I2C to connect ICs

The Inter IC Bus (I2C) is a cousin of the SPI bus but it is somewhat more complex and it does not work as a ring buffer like the SPI bus. It also connects all of its slave devices in series and depends on 2 lines only. There is a nice tutorial on setting up and using the I2C bus at Robot Electronics. From their site: The physical bus is just two wires, called SCL and SDA. SCL is the clock line. It is used to synchronize all data transfers over the I2C bus. SDA is the data line. The SCL & SDA lines are connected to all devices on the I2C bus. There needs to be a third wire which is just the ground or 0 volts. There may also be a 5volt wire is power is being distributed to the devices. Both SCL and SDA lines are “open drain” drivers. What this means is that the chip can drive its output low, but it cannot drive it high. For the line to be able to go high you must provide pull-up resistors to the 5v supply. There should be a resistor from the SCL line to the 5v line and another from the SDA line to the 5v line. You only need one set of pull-up resistors for the whole I2C bus, not for each device.

rder to detect I2C devices, you could use the ```i2cdetect``` system command. Just remember that on a Rev 1 Raspberry Pi it's device 0, and on a Rev. 2 it's device 1. e.g.

i2cdetect -y 0 # Rev 1 i2cdetect -y 1 # Rev 2

ple of using the I2C Bus

// Register a device on the bus var myDevice = Pi.I2C.AddDevice(0x20);

// Simple Write and Read (there are algo register read and write methods) myDevice.Write(0x44); var response = myDevice.Read();

// List registered devices on the I2C Bus foreach (var device in Pi.I2C.Devices) {

Console.WriteLine($"Registered I2C Device: {device.DeviceId}");

}

iming and Threading


erial Ports (UART)
e is the serial port API? Well, it is something we will most likely add in the future. For now, you can simply use the built-in ```SerialPort``` class the .NET framework provides.

imilar Projects
 href="https://github.com/raspberry-sharp/raspberry-sharp-io">Raspberry# IO</a>
 href="https://github.com/danriches/WiringPi.Net">WiringPi.Net</a>
 href="https://github.com/andycb/PiSharp">PiSharp</a>

This work is supported by the National Institutes of Health's National Center for Advancing Translational Sciences, Grant Number U24TR002306. This work is solely the responsibility of the creators and does not necessarily represent the official views of the National Institutes of Health.