.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, Powershell

Using PowerShell to install the latest .NET Core 2 preview

I’ve been living on the bleeding edge and programming with the .NET Core 2 preview, which lives at https://github.com/dotnet/cli.

Reasonably frequently I find that I get error messages from the compiler saying there’s been some kind of file binary mismatch between versions, and I resolve this by getting rid of previous versions of .NET Core 2, and clearing out my .NET and Nuget caches.

Since a new build comes out every day, I wrote a simple PowerShell script to automate this process. I’ve highlighted (in red) some paths in the script which you might have to change in your setup if you want to use the script.

This is a pretty savage way to clear dotnet out – it deletes a lot of stuff. I use it on my development machine which I’m happy to trash. If you use this script, treat it very carefully!

Write-Host "About to clear .NET cache from my profile..."
$dotnetProfileFolder = "C:\Users\Jeremy\.dotnet"
Remove-Item $dotnetProfileFolder\* -recurse

# https://jeremylindsayni.wordpress.com/2016/05/24/fixing-rogue-behaviour-in-nuget-by-clearing-the-caches/
Write-Host "About to clear Nuget Cache..."
nuget locals all -clear

# https://blog.jourdant.me/post/3-ways-to-download-files-with-powershell
Write-Host "About to delete existing .NET Core binaries..."
$dotNetSdkFolder = "C:\Program Files\dotnet"
Remove-Item $dotNetSdkFolder\* -recurse

Write-Host "About to download latest .NET Core 2 binaries..."
$url = "https://dotnetcli.blob.core.windows.net/dotnet/Sdk/master/dotnet-dev-win-x64.latest.zip"
$output = "$dotNetSdkFolder\dotnet-dev-win-x64.latest.zip"

Import-Module BitsTransfer
Start-BitsTransfer -Source $url -Destination $output

# https://www.howtogeek.com/tips/how-to-extract-zip-files-using-powershell/
Write-Host "About to unzip latest .NET Core 2 binaries..."
$shell = new-object -com shell.application
$zip = $shell.NameSpace($output)
foreach($item in $zip.items())
{
 $shell.Namespace($dotNetSdkFolder).copyhere($item)
}

Write-Host "Done - dotnet version installed is:"
dotnet --version
.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.