.net, .net core, Raspberry Pi 3

Using .NET Core 2 to read from an I2C device connected to a Raspberry Pi 3 with Ubuntu 16.04

I’ve bought a lot of hardware devices – often I2C devices – to attach to my Raspberry Pi devices over the years – things like thermometers, gyroscopes, light intensity sensors and so on. And usually there’s a library supplied by the manufacturer of a device breakout board which shows me how to use the device in the .NET framework.

But what if there isn’t a library for my device? Or what if the library isn’t in .NET – or if it is in .NET, what if it isn’t compatible with .NET Core 2? I wanted to know if I could find a way to still read from my I2C devices while coding from scratch using .NET Core 2, and not depend on someone else writing the library for me.

PInvoke

I’ve written a couple of posts recently (one for Windows 10 IoT Core and one for Ubuntu 16.04) about how to create simple platform invocation service (also known as PInvoke) applications in .NET Core 2 – these posts describe calling native methods to capitalise some text, and deploy the application to a Raspberry Pi 3.

So since I found that it was so easy to use PInvoke with .NET Core and Ubuntu on the Raspberry Pi, I thought I’d try something more ambitious – accessing hardware device registers over an I2C bus using native libraries.

What is I2C?

I2C is a protocol often used to connect peripheral hardware devices (such as a thermometer) to a processor device such as a Raspberry Pi or an Arduino. Typically I find there are four wires needed to connect the Raspberry Pi to an I2C device – one for power (usually 3.3V or 5V), one for ground, one for a serial data line (sometimes labelled as SDA), and one for a serial clock line (sometimes labelled SCL).

As a software developer, I don’t need to worry too much about these wires – I just need to connect the correct 5V/3.3V and 0V wires, and connect the SDA wire to Pin 3 on my Raspberry Pi, and connect the SCL wire to Pin 5 on my Pi.

How can I set up my Ubuntu Raspberry Pi 3 to use I2C?

My Ubuntu installation on my Raspberry Pi 3 didn’t have I2C enabled out of the box – I needed to make a few simple changes.

  • I opened the file “/etc/modules” as sudo and added a couple of lines to the end:
i2c-dev
i2c-bcm2708
  • I opened the “/boot/config.txt” file as sudo and added a couple of lines to the end:
dtparam=i2c_arm=on
dtparam=i2c1=on
  • I then ran the command below:
sudo apt-get install -y i2c-tools

At this point I was able to run the command below:

i2cdetect -y 1

This command scans the I2C bus for attached devices. The “-y” switch means it doesn’t prompt me to type ‘Yes’ to confirm, and the “1” means I’m scanning the I2C-1 bus.

screenshot.1494270470

This showed me that my I2C bus is configured correctly, and highlighted that an external device is connected to my I2C-1 bus, and is accessable at address 0x48.

The device is actually a TMP102 temperature sensor – which I’ve written about before when I used a UWP application to read from this device.

How can I read from a device connected to my Raspberry Pi 3?

I happen to know for this device that the temperature is written into the first two bytes of the TMP102 device (from the datasheet), so I want my code to read these bytes.

Once I’ve connected my I2C device correctly to my Raspberry Pi 3, there are three steps to the code:

  • Open the I2C bus,
  • Specify the address of the device we want to control and read from, and
  • Read from the device.

Whereas this isn’t possible in standard .NET Core 2, there are three functions available in the GNU C library which will do this for us.

I’ve pasted the invocation signatures below to access these functions.

[DllImport("libc.so.6", EntryPoint = "open")]
public static extern int Open(string fileName, int mode);
 
[DllImport("libc.so.6", EntryPoint = "ioctl", SetLastError = true)]
private extern static int Ioctl(int fd, int request, int data);
 
[DllImport("libc.so.6", EntryPoint = "read", SetLastError = true)]
internal static extern int Read(int handle, byte[] data, int length);

So we can open the I2C-1 bus with the .NET code below:

int OPEN_READ_WRITE = 2; // constant, even for different devices
var i2cBushandle = Open("/dev/i2c-1", OPEN_READ_WRITE);

We can control the I2C slave device with address 0x48 on the I2C-1 device with the .NET code below:

int I2C_SLAVE = 0x0703; // constant, even for different devices
int registerAddress = 0x48; // different address for each I2C device
var deviceReturnCode = Ioctl(i2cBushandle, I2C_SLAVE, registerAddress);

And finally we can read two bytes into a byte array from the device with the code below:

var deviceDataInMemory = new byte[2];
Read(i2cBushandle, deviceDataInMemory, deviceDataInMemory.Length);

Putting it all together

First install .NET Core 2 using the executable from here, and then install the template for .NET Core 2 IOT projects using the command below:

dotnet new -i RaspberryPi.Template::*

Next create a project (for the TMP102 device) using the command

dotnet new coreiot -n Tmp102

Open the project, and replace the code in the Program.cs file with the code below:

using System;
using System.Runtime.InteropServices;
 
namespace RaspberryPiCore
{
    class Program
    {
        private static int OPEN_READ_WRITE = 2;
        private static int I2C_SLAVE = 0x0703;
 
        [DllImport("libc.so.6", EntryPoint = "open")]
        public static extern int Open(string fileName, int mode);
 
        [DllImport("libc.so.6", EntryPoint = "ioctl", SetLastError = true)]
        private extern static int Ioctl(int fd, int request, int data);
 
        [DllImport("libc.so.6", EntryPoint = "read", SetLastError = true)]
        internal static extern int Read(int handle, byte[] data, int length);
		
        static void Main(string[] args)
        {
            // read from I2C device bus 1
	    var i2cBushandle = Open("/dev/i2c-1", OPEN_READ_WRITE);
 
            // open the slave device at address 0x48 for communication
	    int registerAddress = 0x48;
	    var deviceReturnCode = Ioctl(i2cBushandle, I2C_SLAVE, registerAddress);
 
            // read the first two bytes from the device into an array
	    var deviceDataInMemory = new byte[2];
	    Read(i2cBushandle, deviceDataInMemory, deviceDataInMemory.Length);
 
            Console.WriteLine($"Most significant byte = {deviceDataInMemory[0]}");
            Console.WriteLine($"Least significant byte = {deviceDataInMemory[1]}");
        }
    }
}

Now build and publish using the commands below:

dotnet build
dotnet publish -r ubuntu.16.04-arm

And copy the published code (inside the “.\bin\Debug\netcoreapp2.0\ubuntu.16.04-arm\publish\” directory) to your Raspberry Pi 3 running Ubuntu.

Now if you run the Tmp102 executable (you might need to chmod it to have execute privileges), it’ll write the contents of the first two bytes to the console, which proves we’ve successfully connected to the device over the I2C bus and read from it.

screenshot.1494274133

Wrapping up

There’s obviously a lot more to I2C than this post, but it proves that we can use PInvoke and .NET Core 2 to read from devices using the I2C protocol. With this knowledge, I’m not dependent on hardware vendors supplying working .NET code for my I2C devices (although that obviously makes things easier!)

.net, .net core, Raspberry Pi 3

Using PInvoke with .NET Core 2 and Ubuntu 16.04 on the Raspberry Pi 3

I’ve written previously about how to use PInvoke with .NET Core 2 on a Raspberry Pi 3 running Windows 10 IoT Core – I tested it with a very simple example where I converted some text to upper case using the CharUpper method in the user32.dll library. I was able to invoke the CharUpper method using the code below:

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern char CharUpper(char character);

You can see the full code at Github here.

I decided to see if I could repeat this simple example on Ubuntu using the built in libraries – and found that it is actually really easy to use PInvoke with .NET Core on Ubuntu also. I’ll run through the steps to repeat this on your own Raspberry Pi 3 running Ubuntu 16.04.

  • Install .NET Core 2 – you can get the installer from here.
  • Create a console app for the Raspberry Pi 3 – you can install a template using the code below:
dotnet new -i RaspberryPi.Template::*
  • And then you can create a new project using the command below:
dotnet new coreiot -n RaspberryPi_PInvoke
  • In the generated project, replace the code in Program.cs with the code below. I’ve highlighted the key part of the code in red – this uses the GNU C library, libc. I import the method “toupper”, but alias it as CharUpper which is the name of the function I used in the previous post.
using System;
using System.Runtime.InteropServices;
 
namespace RaspberryPi_PInvoke
{
    class Program
    {
        [DllImport("libc.so.6", EntryPoint = "toupper")]
        private static extern int CharUpper(int c);
 
        static void Main(string[] args)
        {
            var textToChange = "Hello Internet of Things!";
            var inputCharacterArray = textToChange.ToCharArray();
 
            // array of chars to hold the capitalised text
            var outputCharacterArray = new char[inputCharacterArray.Length];
 
            for(int i = 0; i < inputCharacterArray.Length; i++) 
            {
                var charToByte = (byte)inputCharacterArray[i];
                outputCharacterArray[i] = (char)CharUpper(charToByte);
            }
 
            Console.WriteLine($"Original text is {textToChange}");
            Console.WriteLine($"Changed text is {new string(outputCharacterArray)}");
        }
    }
}
  • Now build this using the command:
dotnet build
  • And publish for Ubuntu using the command:
dotnet publish -r ubuntu.16.04-arm
  • Finally, deploy this to your Raspberry Pi 3 running Ubuntu.

I use pscp to copy files from my Windows machine to the Pi 3 running Ubuntu, but you could also use rsync from Bash in Windows 10. Remember to make the file you need to run (RaspberryPi_PInvoke) executable on the Pi 3 using chmod.

When you run this application through a terminal, you’ll see that it converts the text “Hello Internet of Things!” to upper case.

screenshot.1494193840

Wrapping up

This post is very similar to a post I wrote previously about using PInvoke with Windows 10 IoT Core on the Raspberry Pi 3 – except this time, I use a function from the GNU C library, libc. This is an incredibly rich source of code, and I’ll write next time about how I can use this to access the I2C bus.

.net, .net core, Raspberry Pi 3

Controlling GPIO pins using a .NET Core 2 WebAPI on a Raspberry Pi, using Windows 10 or Ubuntu

Previously I’ve written about creating a .NET Core 2 Web API and hosting it on a Raspberry Pi 3, and this time I’ll expand on this work to interact with GPIO pin logic levels.

This is the latest in a series of posts helping developers write .NET Core 2 code to interact with IoT hardware, in a way which is agnostic towards the device operating system. I’ve written a few bits and pieces about how to change GPIO pin status with a console application previously – but with a WebAPI, we can now control GPIO status with HTTP Post requests. So with this capability, you can imagine how we could control a physical device from something like a browser application, or even a HoloLens or Xbox app.

TL:DR – as usual, the source code is up on GitHub here.

Create the Web API project for the Raspberry Pi

This bit is easy – once you have .NET Core 2 on your machine, just install the template from Nuget using the command below:

dotnet new -i RaspberryPi.WebApi::*

And then pick a folder on your development environment to create a new project called GpioSwitcherWebApio with the command:

dotnet new piwebapi -n GpioSwitcherWebApi

At this point you’ll have all the code you need to run a .NET Core 2 Web API project on your Raspberry Pi.

If you want to read more about this, check out a longer post here.

Create a controller to change pin status

Let’s open our project, and add a dependency on the Bifröst project – this helps us in a couple of ways. We can write the same code to target both Ubuntu and Windows 10 IoT Core devices, and there’s also a Bifröst UWP app that helps us access GPIO hardware on Windows 10 IoT devices. Open up a Package Manager prompt in Visual Studio 2017 and enter:

Install-Package Bifrost.Devices.Gpio.Core -Version 0.0.1
Install-Package Bifrost.Devices.Gpio.Abstractions -Version 0.0.1
Install-Package Bifrost.Devices.Gpio -Version 0.0.2

If you’re not using Visual Studio 2017, you can just modify the GpioSwitcherWebApi.csproj file and add the package references shown below:

  <ItemGroup>
    <PackageReference Include="Bifrost.Devices.Gpio" Version="0.0.2" />
    <PackageReference Include="Bifrost.Devices.Gpio.Abstractions" Version="0.0.1" />
    <PackageReference Include="Bifrost.Devices.Gpio.Core" Version="0.0.1" />
    <PackageReference Include="Microsoft.AspNetCore" Version="2.0.0-preview1-*" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.0.0-preview1-*" />
    <PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="2.0.0-preview1-*" />
  ItemGroup>

Next, we can edit the default ValuesController which comes with the project – I’ve renamed mine to be PinsController.cs, which is a title better suited to the action we’re going to carry out.

I want my controller to have three actions for Ubuntu or Windows IoT devices:

  • Get() – an HttpGet action which returns a list of Gpio pins which are presently exported, and their current status (high/low).
  • Get(int pinId) – an HttpGet action which returns the status of the Gpio pin with the number pinId.
  • SwitchPin(int pinId, int status) – an HttpPost action which allows me to select a GpioPin with number pinId, and set it to a value of status (which is either 1 or 0, corresponding to high or low).

The Bifröst libraries make setting up our controller to modify GPIO pin statuses very easy.

The code below is just an example – obviously in a properly structured application, modifying GPIO pin levels would be managed through an interface to a service layer.

First, we need to instantiate a static instance of the GpioContoller object – so we can add a private member variable and a class constructor, as shown below.

private IGpioController gpioController;
 
public PinsController()
{
    Console.WriteLine("In controller - instantiating GpioController instance");
    gpioController = GpioController.Instance;
}

Next, we need to write the HttpGet action that returns a list of Gpio pins which are presently exported, and their current status. The code below shows the controller action which achieves this, and returns a 200 OK Http code.

[HttpGet]
public IActionResult Get()
{
    Console.WriteLine("About to list pin statuses.");
    return Ok(gpioController.Pins);
}

We also want to be able to find the present status of a Gpio pin by passing the pin number to the HttpGet method, and we can do this with the code below.

[HttpGet("{pinId}")]
public IActionResult Get(int pinId)
{
    GpioPinValue pinStatus;
 
    Console.WriteLine("About to get pin status.");
    var pin = gpioController.OpenPin(pinId);
 
    pinStatus = pin.Read();
 
    Console.WriteLine("Returning pin status.");
    return Ok(pinStatus.ToString());
}

Finally, the interesting bit – rather than just reading pin logic levels, I’d like to be able to modify them – I think the most logical Http verb to use here is the HttpPost verb, so I can post values for the pin number I want to change, and the level I want to change it to, using the code below:

[HttpPost]
public void SwitchPin(int pinId, int status)
{
    Console.WriteLine("About to change pin status.");
    var pin = gpioController.OpenPin(pinId);
 
    pin.SetDriveMode(GpioPinDriveMode.Output);
 
    if (status == 1)
    {
        Console.WriteLine("Going on");
        pin.Write(GpioPinValue.High);
    }
    else
    {
        Console.WriteLine("Going off");
        pin.Write(GpioPinValue.Low);
    }
}

To see the complete controller file already coded, check it out here.

If you’ve followed the steps above correctly, you should be able to build the WebAPI application in your normal way (e.g. in Visual Studio 2017 use Ctrl+Shift+B, or from a terminal in VSCode, execute the dotnet build command.

If you’ve pulled the project from GitHub here, there’s a file named build.ps1 which you can run from a PowerShell prompt to do the build for you. There are other more useful ones generated for publishing and deploying to Ubuntu 16.04 or Windows 10 IoT Core.

Deploying to your Raspberry Pi device

I’ve previously written step by step instructions on how to deploy code to a Raspberry Pi 3 running Ubuntu 16.04 or Windows 10 IoT Core, so I won’t repeat all of that here – the easiest way to do this is just to run the into PowerShell scripts I’ve uploaded to Github, and I briefly cover these below along with the parameters these scripts need to run.

To run these scripts successfully, make sure you’ve switched on your Raspberry Pi 3, logged into the device, and have connected it to your network.

Deploying to Ubuntu 16.04

  • Make sure you’ve got PuTTY installed on your development machine.
  • Get the IP address of your Raspberry Pi 3 (mine is 192.168.1.110)
  • Get the username you logged in with (default is ubuntu).
  • Get the path you want to deploy your WebAPI to (mine is /home/ubuntu/GpioWebAPI)

Using the script hosted here, run the command in PowerShell:

.\deploy-ubuntu.ps1 -ip 192.168.1.110 -username ubuntu -destination /home/ubuntu/GpioWebAPI

The WebAPI binaries will be build and published for an Ubuntu OS, and then copied to your Raspberry Pi.

Deploying to Windows 10 IoT Core

This is a little bit more complex – you have to deploy your WebAPI, and also deploy the Bifröst UWP app (you need the Bifröst UWP app on Windows to allow your .NET Core 2 app to read and change logic levels of your GPIO pins).

First, deploy the Web API application

  • Get the IP address of your Raspberry Pi 3 (mine is 192.168.1.125)
  • The name of the Web API application, which for me is GpioSwitcherWebApi.

Using the script below (you can get a copy from here), run the command to create the destination directory and add a firewall rule:

.\setup-windows.ps1 -ip 192.168.1.125 -applicationName GpioSwitcherWebApi

Now run the script below (you can get a copy from here), which copies the binaries to your Raspberry Pi 3.

.\deploy-windows.ps1 -ip 192.168.1.125 -applicationName GpioSwitcherWebApi

Thanks to wind-rider for their pull request with excellent powershell scripts.

Next, deploy the Bifröst Windows Device Bridge

How to deploy this UWP app is described in detail here, but it’s just a standard UWP app deployment. You can download the code from here, load it into Visual Studio Community 2017, and deploy it to your Raspberry Pi 3 hosting Windows 10 IoT Core.

screenshot.1493500867

Start the Kestrel web server to start the Web API

This is straightforward – for a Raspberry Pi hosting Ubuntu 16.04, I ssh in using PuTTY and run:

sudo /home/ubuntu/GpioWebApi/GpioSwitcherWebApi

And for a Raspberry Pi hosting Windows 10 IoT Core, I ssh in using PowerShell, navigate to where deployed the app, and run:

.\GpioSwitcherWebApi.exe

The web server will start up after a few seconds and it’s ready to test.

Testing our Web API by changing GPIO pin logic levels

We can test this really easily by issuing HttpGet or HttpPost requests to our webserver. Let’s test this for Pin 26 on our Raspberry Pi – I’ve connected an LED between Pin 26 and ground.

For my Windows 10 Raspberry Pi, I can just browse to the address:

http://192.168.1.125:5000/api/pins

This will return a JSON list of pins and logic levels (it’s probably an empty list if you’ve not run this before).

To switch a pin on, let’s use a Firefox plug in like HttpRequester.

  • For the URL, enter the URL above (http://192.168.1.125:5000/api/pins).
  • Select the “Parameters” tab (as shown below) and add name-value pairs of:
    • pinId = 26
    • status = 1
  • Now click on the “POST” button

The site responds with a HTTP status of 200 OK, and the logic level of GPIO pin 26.

screenshot.1493561495

The logic level is 1, which means the white LED attached to pin 26 will turn on.

Windows 10 Web API - LED On

If we want to find the status of Pin 26 now, we can read it with an HTTP get request of:

http://192.168.1.125:5000/api/pins/26

As shown below, there’s a GET request which returns a status of 200 OK and a text value of High – which is what we expect as we’ve just turned the pin on.

screenshot.1493561789

Finally let’s just issue an HTTP Get request with no pin Id specified to get all statuses – again we receive a 200 OK code and a JSON object listing the open GPIO pin and its status.

screenshot.1493562077

For testing Ubuntu the process is identical except for I had to substitute the IP address of my Ubuntu Raspberry Pi (which is 192.168.1.110). Repeating the process above turns on the orange LED attached to the Ubuntu Raspberry Pi (see below)

Raspberry Pi running Ubuntu LED On

Wrapping up

That’s all for this time – we’ve seen how to access GPIO pins from a .NET Core 2 Web API, and deploy that application to a Raspberry Pi 3 running either Windows 10 IoT Core or Ubuntu 16.04. This technique allows us to use the Raspberry Pi’s capabilities from a wider variety of interfaces than just a console – so we could use a browser, or even a HoloLens or Xbox app.

.net, .net core, Powershell, Raspberry Pi 3

Using PInvoke with .NET Core 2 and Windows 10 IoT Core on the Raspberry Pi 3

Since I’ve been kicking the tyres on .NET Core 2 to see what’s possible with the Raspberry Pi 3, I wondered if it was possible to use PInvoke on the Windows 10 IoT Core operating system – and it turns out that it is.

Let’s write a simple console application and deploy it to a Pi 3 to show PInvoke working.

As usual, you can find the finished code on my GitHub repository here.

First, install .NET Core 2

You can get the .NET Core 2 installer from here – remember that this version of .NET Core hasn’t made it to RTM status yet, so you’re playing with code at the bleeding edge. I’ve found it to be pretty stable, but I’m working on a machine which I’m happy to trash and rebuild.

screenshot.1492889096

Create a console app for the Raspberry Pi 3

Next, open a PowerShell prompt, and navigate to where you want to create the .NET Core 2 project.

dotnet new -i RaspberryPi.Template::*

This’ll add the template for a .NET Core 2 Console application which targets IoT devices – you can see this in your list of installed templates if you run:

dotnet new --list

You’ll see it in the list, as shown below.

screenshot.1493574830

So to create this kind of IoT console application, run:

dotnet new coreiot -n RaspberryPi.PInvoke

This creates a new folder and project called “RaspberryPi.PInvoke”, which presently will just write “Hello Internet of Things!” to the console.

Choose an unmanaged function to call – CharUpper

Let’s change this application to make that text – “Hello Internet of Things!” – become upper case. Inside user32.dll, there is a function called CharUpper which will do exactly that.

Obviously we could just use the “ToUpper()” string method inside managed .NET code to achieve this, but this application is a proof of concept to use PInvoke.

The C# signature for this is below:

[DllImport("user32.dll", CharSet=CharSet.Auto)]
static extern char CharUpper(char character);

So we can modify our very simple program to now become like the code below:

using System;
using System.Runtime.InteropServices;
 
namespace RaspberryPiCore
{
    class Program
    {
        [DllImport("user32.dll", CharSet=CharSet.Auto)]
        static extern char CharUpper(char character);
 
        static void Main(string[] args)
        {
            var textToChange = "Hello Internet of Things!";
            var inputCharacterArray = textToChange.ToCharArray();
 
            // array of chars to hold the capitalised text
            var outputCharacterArray = new char[inputCharacterArray.Length];
 
            for(int i = 0; i < inputCharacterArray.Length; i++) 
            {
                outputCharacterArray[i] = CharUpper(inputCharacterArray[i]);
            }
 
            Console.WriteLine($"Original text is {textToChange}");
            Console.WriteLine($"Changed text is {new string(outputCharacterArray)}");
        }
    }
}

Let’s build this using:

dotnet build

Let’s publish it for Windows 10 IoT Core devices with an ARM processor using

dotnet publish -r win8-arm

Let’s open a Powershell prompt to our Raspberry Pi 3, create a folder to host this application.

mkdir c:\ConsoleApps\PInvoke

You can ssh to your Raspberry Pi 3 using a Powershell prompt from the Windows IoT Dashboard as shown in the image below:

screenshot.1489958874

And now let’s open a command prompt on our development machine, and copy the application binaries to the directory we created on our Raspberry Pi 3 earlier.

robocopy.exe /MIR ".\bin\Debug\netcoreapp2.0\win8-arm\publish" "\\<your-ipaddress-here>\c$\ConsoleApps\PInvoke"

Finally after building, publishing and deploying, we can go back to the ssh PowerShell prompt and run:

C:\ConsoleApps\PInvoke\RaspberryPi.PInvoke.exe

And this shows the text has been changed to upper case, as shown below.

screenshot.1493578558

Wrapping up

There’s nothing special about this code, it’s all pretty standard PInvoke code – but it’s nice to confirm that it works with .NET Core 2 on the Raspberry Pi 3’s ARM processor under Windows 10 IoT Core.

.net, .net core, Raspberry Pi 3

Hosting a .NET Core 2 Web API instance on the Raspberry Pi 3

I’ve been spending a lot of time recently working to improve developer’s experiences with writing cross platform code for the Raspberry Pi 3 using .NET Core 2.

In a previous post, I wrote about creating a simple .NET Core 2 console app for the Pi – you can see the code on GitHub here, or if you just want to install the template, just install the Nuget package by running the code below from a command line:

dotnet new -i RaspberryPiTemplate::*

And to create a new console project with this template, run the code from a command line:

dotnet new coreiot -n MyProject

I saw this very nice post from Laurent Kempe where he writes about creating an MVC application for the Raspberry Pi – there’s a bit of overlap in this post about WebAPI, particularly around modifying the csproj file, but there’s also a few subtle differences which made me think that WebAPI deserves its own post.

I’ve also started a project called Bifröst – this is a project for developers who want to write .NET Core 2 applications that use IoT devices, and want to target Ubuntu and Windows with the same code.

What about creating a WebAPI project for a Raspberry Pi 3?

First – make sure you have .NET Core 2 – I noticed that the status has changed from Beta to Preview recently, and you can download an installer from here.

Remember .NET Core 2 is not in official release – you’re living on the edge using these latest builds of code from Microsoft!

 

screenshot.1492889096.png

 

The easy way – use the pre-baked templates from Nuget

If you just want to install a template from Nuget, run the code below at a command line;

dotnet new -i RaspberryPi.WebApi::*

Once you’ve installed this template, you can browse to where you’d like your project to be created and run the command below (obviously if you don’t want to call your project “MyProject”, choose a different name).

dotnet new piwebapi -n MyProject

This will create a .NET Core 2 WebAPI project called “MyProject”, which can be deployed to a Raspberry Pi running Windows 10 or Ubuntu. There are a bunch of deployment PowerShell scripts in the root, and you can read a bit more about them here.

If you want to look at a sample project which is created from this template, I’ve created a sample one on GitHub here.

If you’re deploying to Windows 10 IoT Core, remember to open a port in the firewall to allow connections – my sample template uses port 5000 and can be opened using the code below if you ssh into your Pi.

netsh advfirewall firewall add rule name="ASPNet Core 2 Server Port" dir=in action=allow protocol=TCP localport=5000

Or try the hard way – cook your own project

It’s not actually that hard – creating a WebAPI project for the Raspberry Pi 3 ARM processor is very similar to creating a standard WebAPI project for an x86/x64 machine, with a few small tweaks to the code.

After you’ve got .NET Core 2 installed, open a command line where you want your project to live and run the line of code below (again, obviously if you don’t want to call your project “MyProject”, choose a different name).

dotnet new webpi -n MyProject

When the project is created, open the root folder (which will be called MyProject) and edit the MyProject.csproj file. Look for the ProjectGroup node which should look like the code below:

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
  </PropertyGroup>

And add two additional notes – RuntimeFrameworkVersion and RuntimeIdentifiers:

  <PropertyGroup>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <RuntimeFrameworkVersion>2.0.0-preview1-002028-00</RuntimeFrameworkVersion>
    <RuntimeIdentifiers>win8-arm;ubuntu.14.04-arm;ubuntu.16.04-arm</RuntimeIdentifiers>
  </PropertyGroup>

Now look at the project’s Program.cs file, and add the line of code:

.UseUrls("http://*:5000")

to the main method, as shown below:

public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseUrls("http://*:5000")
            .ConfigureAppConfiguration((context, configBuilder) => {
                configBuilder
                    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                    .AddJsonFile($"appsettings.{context.HostingEnvironment.EnvironmentName}.json", optional: true)
                    .AddEnvironmentVariables();
            })
            .ConfigureLogging(loggerFactory => loggerFactory
                .AddConsole()
                .AddDebug())
            .UseStartup<Startup>()
            .Build();
 
        host.Run();
    }
}

I noticed one strange thing when generating the code using the WebAPI template – the main method calls a ConfigureConfiguration method, but this causes a compiler error against the most recent version of .NET Core 2 – I had to update this code to ConfigureAppConfiguration (in green in the code above). So watch out for that.

Building and deploying to a Raspberry Pi 3

First, build this project in the normal way – browse to the directory that you’ve created your project and run:

dotnet restore .

dotnet build .

Next, publish the application – the target depends on whether you want to run on a Raspberry Pi with Windows 10 or Ubuntu 16.04.

Publish targetting Ubuntu 16.04:

dotnet publish . -r ubuntu.16.04-arm

Publish targetting Windows 10:

dotnet publish . -r win8-arm
Next, we need to deploy these binaries:

Deploy to Ubuntu 16.04

To deploy to Ubuntu 16.04 from a Windows machine, we need a few things:
  • Install PuTTY (which also installs tools called pscp and plink, which we need). Add the PuTTY install directory to your Windows’ machine path.
  • The userid you used to log into your Pi – mine is ubuntu.
  • Create a directory on your Raspberry Pi to deploy the WebAPI code to – I’ve created on called “PiWebApi” which is at “/home/ubuntu/PiWebApi“.
  • The IP address of your Raspberry Pi – make sure your Raspberry Pi is logged in and connected to your local network – my Ubuntu Pi’s IP address is 192.168.1.110

Now run the command below to copy the binaries from your Windows development machine to the remote Raspberry Pi 3.

pscp.exe -r .\bin\Debug\netcoreapp2.0\ubuntu.16.04-arm\publish\* ubuntu@$192.168.1.110:/home/ubuntu/PiWebApi

Then run the command below from your development machine to make the binary executable on the Raspberry Pi.

plink.exe -v -ssh ubuntu@192.168.1.110 chmod u+x,o+x /home/ubuntu/PiWebApi/MyProject
Open an ssh connection using PuTTY to your Pi 3 and run the command:
./home/ubuntu/PiWebApi/MyProject
The console will show the text below as the web server starts up:
Hosting environment: Production
Content root path: /home/ubuntu/PiWebApi
Now listening on: http://[::]:8000
Application started. Press Ctrl+C to shut down.
And now you can browse to the address below to see the Raspberry Pi server returning values from the HTTP GET request:
screenshot.1492900054

Deploy to Windows 10 IoT Core

To deploy to a Raspberry Pi running Windows 10, we need to:
  • Create a directory on your Raspberry Pi to deploy the WebAPI code to – I’ve created on called “PiWebApi” which is at “C$/PiWebApi“.
  • Get the IP address of your Raspberry Pi – make sure you’ve logged into your Raspberry Pi and connected to your local network – my Windows 10 Pi’s IP address is 192.168.1.125

From a command prompt opened at the root of your WebAPI project, run the code below to copy the binaries from your development machine to your Pi:

xcopy.exe /y ".\bin\Debug\netcoreapp2.0\win8-arm\publish" "\\192.168.1.125\C$\PiWebApi"
Now open an ssh connection to your Raspberry Pi – I use PowerShell to do this through the “Windows IoT Dashboard” (as shown in the picture below):
screenshot.1489958874
From this ssh connection, you now need to open port 5000 in the Raspbery Pi 3’s firewall:
netsh advfirewall firewall add rule name="ASPNet Core 2 Server Port" dir=in action=allow protocol=TCP localport=5000
Browse to the deployment folder on your Raspberry Pi (in this case C:\PiWebApi) and run the command below:
./MyProject.exe
Again the text below is written to the console as the web server starts up:
Hosting environment: Production
Content root path: C:\PiWebApi
Now listening on: http://[::]:5000
Application started. Press Ctrl+C to shut down.

And again you can browse to the address below to see the Raspberry Pi server returning values from the HTTP GET request:

screenshot.1492899256.png
Footnote: There’s presently (26-Apr-17) an issue with some WebAPI calls in .NET Core 2, logged on GitHub with more information here. I’ve found that Kestrel throws an exception the first time I hit the the api/values/1 url, but it works the second time I hit the URL. Hopefully this’ll be diagnosed and fixed soon.

.net, .net core, Bifröst, Powershell, Raspberry Pi 3

Project Bifröst – improving deployment of Raspberry Pi apps written in .NET Core 2

Bifröst is a project for developers who want to write .NET Core 2 applications that use IoT devices, and want to target Ubuntu and Windows with the same code.

Last time I wrote an introductory post explaining how this UWP application works and why it’s useful if you want to access GPIO pins. I wrote quite a lot about how to deploy a sample .NET Core application (called GpioSwitcher) – and it occurred to me while writing the post that the deployment process for Raspberry Pi apps from Windows currently sucks. So I’ve written some PowerShell scripts to neatly manage application deployment, which are in the project’s GpioSwitcher directory.

The deployment scripts mentioned in this post aren’t part of the Bifröst UWP application – rather they’re part of a broader project effort to improve the quality of life for .NET developers working in the IoT space.

Improving deployment for the GpioSwitcher application

If you want to just build the application, open PowerShell at the GpioSwitcher project root and run:

.\build.ps1

Deploy to a running Raspberry Pi 3 with Windows 10

This script has two parameters:

  • ip: the ip address of the Raspberry Pi 3 (mine is 192.168.1.125)
  • destination: the network path to where you want the application to be copied (I created a folder named CoreTest in the root, so the network path is “C$\CoreTest”)
.\deploy-windows.ps1 -ip 192.168.1.125 -destination "c$\CoreTest"

So to now run the application and to set pin 26 to logic high: ssh into your Raspberry Pi 3 (either using PuTTY or Powershell), navigate to the directory that you copied the application to, and run:

./GpioSwitcher 26 1

Deploy to a running Raspberry Pi 3 with Ubuntu 16.04

This script has three parameters:

  • ip: the ip address of the Raspberry Pi 3 (mine is 192.168.1.110)
  • destination: the path to where you want the application to be copied (I created a folder named GpioSwitch in my user directory, so the path is “/home/ubuntu/GpioSwitch”)
  • username: the user id that you’ve logged in with (my userid is “ubuntu”)
.\deploy-ubuntu.ps1 -ip 192.168.1.110 -destination "/home/ubuntu/GpioSwitcher" -username ubuntu

(This process will prompt you to enter your Raspberry Pi password.)

So to now run the application and to set pin 26 to logic high: ssh into your Raspberry Pi 3 (either using PuTTY or Powershell), navigate to the directory that you copied the application to, and run:

sudo -E /home/ubuntu/GpioSwitcher/GpioSwitcher 26 1

This is a much better way to deploy applications to a Raspberry Pi hosting Windows or Ubuntu.

.net, .net core, Bifröst, Raspberry Pi 3

Write .NET Core 2 once, run anywhere: hardware access on Raspberry Pi 3 with Ubuntu and Windows 10 IoT Core

I’ve previously written about how to access the underlying Raspberry Pi 3 hardware with .NET Core on Ubuntu – but what about accessing GPIO on Windows 10 IoT Core with .NET Core? Presently the .NET Standard doesn’t have any API surface which would allow my .NET Core 2 application to switch GPIO pins on or off.

It’s easy to access pins if I write a UWP app, because the library to access GPIO is in the Windows.Devices.Gpio namespace. But this UWP app can’t be deployed to Ubuntu.

If I only wanted to run my code on Ubuntu (and didn’t care about running my code on Windows 10 IoT Core) then I could use libraries like PiSharp, or Raspberry# IO, or RaspberryGPIOManager. And whereas I can run this code on my Pi 3 which has Windows 10, it won’t actually do anything because it’s only the filesystem (not actually affecting GPIO statuses).

So we’ve two solutions for two different platforms, which isn’t really in keeping with the idea of writing cross-platform code for .NET Core. I don’t really want to have to write a .NET Framework app for my code to run on Windows 10 IoT Core, and then a separate .NET Core app for my code to run on Ubuntu 16.04. I want to write code once and be able to run it on different operating systems.

Can I write a single .NET Core application which can access hardware and run on both Ubuntu and Windows 10?

Project Bifröst

Project Bifröst allows me to write .NET Core code that accesses hardware and runs on both Ubuntu 16.04 and Windows 10 IoT Core. It is a Windows UWP application which runs on my Raspberry Pi 3 under Windows 10 IoT Core, and acts as a bridge between my .NET Core application and the Windows.Devices libraries which make hardware available to UWP applications.

The project is in a very early phase right now – it just switches GPIO pins on and off. I’ve a product roadmap planned – but more on that in a later post.

rasppi1

Basically it allows us to write code in .NET Core and access pins through an interface in both Ubuntu 16.04 and Windows 10 IoT Core devices.

Recap

In Ubuntu, we can control the status of GPIO pins by modifying the file system, e.g. If we want to switch GPIO 26 to a status of on:

  • We choose the pin to open by writing the number “26” to the file “/sys/class/gpio/export“,
  • We choose the pin’s drive mode by writing the text “out” to the file “/sys/class/gpio/gpio26/direction“, and
  • We switch on the pin by writing the number “1” to the file “/sys/class/gpio/gpio26/value“.

In Windows 10 IoT Core, we can control the status of GPIO pins using the Windows.Devices.Gpio API.

  • We instantiate a GpioController object,
  • We choose the pin to open by instantiating a GpioPin object,
  • We choose the pin’s drive mode using the SetDriveMode method on the GpioPin object, and
  • We switch on the pin by using the Write method on the GpioPin object.

Bifröst uses the UWP file system notifications feature to monitor for changes to the file system in Windows, and then translates those modifications into Windows.Device API calls.

How to download, build, deploy and use Bifröst

Ubuntu 16.04

After you’ve installed Ubuntu 16.04, you don’t need to install Bifröst – it’s a UWP app and only needed for Windows 10 IoT Core.

Windows 10 Iot Core

There’s no such thing as a Windows App Store for the Raspberry Pi, so the easiest way is to download the source, build and deploy. I’ve provided some pretty comprehensive instructions below.

I code using Visual Studio 2017 (which has a free community edition available here). I also have .NET Core 2 (presently in preview, available here) installed on my machine.

  • Get Bifröst. The code for Bifröst is available here (you can clone the whole code base, including libraries needed to write Bifröst applications, from here).
  • Connect a Raspberry Pi 3 with Windows 10 IoT Core installed. I’ve blogged previously about how to set this up, but the simplest way is to use the “Set up a new device” option from the Windows IoT Dashboard download, and install a Windows 10 IoT Core build to an approved SD card. Then insert this card into your Raspberry Pi 3 and power it up. It’s best to have an ethernet connection (so you can deploy apps more quickly than over wireless) and a monitor connected (so if something.goes wrong you’ll at least be able to visually debug it).

screenshot.1492453516

  • Open the Bifröst solution file in Visual Studio 2017.

screenshot.1492449445

  • You might need to set the Bifrost solution to be default – right click in the solution explorer and select “Set as startup project…”.

screenshot.1492449598.png

  • Change the project configuration’s Solution Platform to ARM.

screenshot.1492449624.png

  • Change the project configuration’s destination device to “Remote Machine”.

screenshot.1492449715

  • Usually your Raspberry Pi 3 will be automatically detected (as shown below).

screenshot.1492454159

  • But if it isn’t enter in the IP address of your Pi 3 into the textbox as shown below, and click on “Select”.

screenshot.1492449771.png

Now you can build the application (the keyboard shortcut is Ctrl+Shift+B) and deploy it to run (shortcut is just F5) on your Raspberry Pi 3. The splash screen with a bridge icon is shown below.

screenshot.1492454372

I prefer to have Bifröst up and running when I start my Pi – so I’ve modified the settings in the App Manager page of the Device Portal (at http://192.168.1.125:8080/#Apps%20manager, though you will almost certainly need to use a different IP address for your Pi 3), and set my Bifröst app to run at start up.

screenshot.1492454574

How to access GPIO pins with platform independent .NET Core 2

Let’s use a simple example of turning a GPIO pin on and off.

I’ve written three libraries targetting .NET Standard 1.6 – available here – which I include in my Raspberry Pi 3 projects. These contain the necessary libraries, interfaces and enumerations to switch GPIO pins on and off.

In the solution, I’ve also included a sample library – named GpioSwitcher – which works on both Ubuntu 16.04 and Windows 10 IoT Core. The code below shows part of GpioSwitcher’s main method in the Program.cs file –  it opens a pin, sets the drive mode, and writes the pin value as high or low. This code works on Raspberry Pi 3 devices running either Ubuntu 16.04 or Windows 10 IoT Core.

// create gpio controller
Debug.WriteLine("About to instantiate the switch controller");
var controller = GpioController.Instance;
 
// open pin
Debug.WriteLine("Opening pin " + pinNumber);
var pin = controller.OpenPin(pinNumber);
 
// set direction
Debug.WriteLine("Setting the direction to out");
pin.SetDriveMode(GpioPinDriveMode.Output);
 
// set value
if (logicLevel == 1)
{
    Debug.WriteLine("Setting the value to high");
    pin.Write(GpioPinValue.High);
}
else
{
    Debug.WriteLine("Setting the value to low");
    pin.Write(GpioPinValue.Low);
}

Deploying your application

UPDATE: I’ve written a post here describing a better and simpler way to deploy this application to Windows or Ubuntu using a PowerShell script.

I go into a lot of detail in the steps below – some of these steps will be really obvious to anyone who has deployed an application to a Raspberry Pi before, or has used an SSH client to remotely access a Raspberry Pi.

Deploying to Ubuntu

You’ll need to be able to ssh into your Raspberry Pi 3 running Ubuntu 16.04 – I’ve written a long post on how to set up Ubuntu 16.04 and install PuTTY and pscp here, which are useful tools for deploying applications to remote machines.

SSH into your Raspberry Pi and create a directory where you can drop the the GpioSwitcher application binaries.

mkdir /home/ubuntu/GpioSwitcher

Back on your dev machine, build the source code (I use Visual Studio 2017), and publish it by running the command below in a command prompt from the directory containing the project’s csproj file.

dotnet publish -r ubuntu.16.04-arm

Then browse to publication directory (which will be all the way in \GpioSwitch\bin\Debug\netcoreapp2.0\ubuntu.16.04-arm\publish), and open a command prompt from this directory. Run the command below:

pscp -r * ubuntu@192.168.1.111:/home/ubuntu/GpioSwitcher

Once the project files are transferred to my Raspberry Pi 3, I change the permissions of the files in this directory to allow them to be executed as root using the command:

sudo chmod u+x,o+x *

 

Now you can alter the status of the GPIO pin using the command below (which switches the status of pin 26 to high (i.e. logic 1).

sudo -E /home/ubuntu/GpioSwitch/GpioSwitcher 26 1

Deploying to Windows 1o IoT Core

Open an explorer window to your Windows 10 Raspberry Pi 3 device (you can do this by right clicking on your device in the Windows IoT Dashboard and selecting “Open network share”.

screenshot.1492461963

Once you’ve opened the explorer window you can create a directory to hold the Windows application (I created a directory called “CoreTest”) as shown below.

screenshot.1492462069

Build the source code using Visual Studio 2017, and publish it by running the command below in a command prompt from the directory containing the project’s csproj file.

dotnet publish -r win8-arm

Then browse to publication directory (which will be all the way in \GpioSwitch\bin\Debug\netcoreapp2.0\win8-arm\publish), and copy all the files from here into the directory you just created on the Raspberry Pi 3. You can drag and drop, or you can use xcopy like the example command below (obviously you’ll have to change the source and destination directories to match your environment).

xcopy /y 
 "C:\Users\Jeremy\Documents\Visual Studio 2017\Projects\Magellanic.Hardware\GpioSwitcher\bin\Debug\netcoreapp2.0\win8-arm\publish" 
 "\\192.168.1.111\c$\CoreTest"

Now you can ssh into your Raspberry Pi 3 and run this command – I find the easiest way is to open a PowerShell prompt from the Windows IoT Dashboard by right clicking on the device and select “Launch PowerShell” (as shown in the image below).

screenshot.1489958874

This will open a PowerShell prompt and a dialog challenging you for your administrative password.

screenshot.1489959150

It takes a few seconds to connect (maybe even up to 30 seconds) – until then it just shows an empty blue screen – but eventually the prompt will return, as shown below.

screenshot.1489959232

At this point, I can navigate to the directory where I copied my console application (C:\CoreTest\) and then I can run the executable with the command below (which switches the status of pin 26 to high (i.e. logic 1).:

./GpioSwitcher 26 1

I’ve tested this out on two Raspberry Pi 3 devices running side by side – I designed and printed out a simple jig to hold the two devices and two mounted LEDs which are connected to Pin 26 on each of the devices so I can deploy and test each operating system side by side (you obviously don’t need two devices, I just find it more convenient than swapping out the SD card when I want to switch from Ubuntu to Windows).

Printing Pi Holder

WP_20170417_17_23_20_Pro

Summing up

I’ve written some code that allows .NET Core applications to interact with GPIO pins. This code acts as a bridge between the application and the Windows.Device.Gpio API surface. This is early days for project Bifröst – it doesn’t do much right now except allow you to turn GPIO pins on and off, and the deployment process is a step-by-step manual process. But I only have to write my hardware access code once, and I can run it on different operating systems – I’ll work to expand the features with the aim of making it more functional.