Building Visual Studio Code for the Raspberry Pi 3

If you’d rather prefer to use Visual Studio Code for C# development instead of MonoDevelop, you can build Microsoft’s own Visual Studio Code from the source repository. I’ve used Visual Studio Code on Ubuntu and it’s actually a pretty neat tool for developing on Linux. It supports over 30 languages including C#, C++, Python, Java and more, so even if you’re not writing C# code, it’s still a useful tool.

Prerequisites for the build on Linux include Python 2.7, make and libx11-dev which should already be installed on your Pi if you started of with a Raspbian Jessie image. Also, if git has not been installed yet, run sudo apt-get install git. Nodejs and npm also need to be installed, as they will be used by the build script to retrieve some required packages. A recent version of nodejs has to be downloaded since the package version in the repository is not adequate.

wget -c http://node-arm.herokuapp.com/node_latest_armhf.deb
sudo dpkg -i node_latest_armhf.deb

Install required dependencies for running Visual Studio Code.

sudo apt-get install libnotify4 libnss3

Let’s clone the repository and start the build process.

git clone https://github.com/microsoft/vscode
cd vscode
./scripts/npm.sh install --arch=armhf

If you get an error like so:

npm ERR! Linux 4.4.14-v7+
npm ERR! Linux 4.4.14-v7+
npm ERR! argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "--arch=armhf"
npm ERR! node v4.2.1
npm ERR! npm  v2.14.7
npm ERR! code EBADPLATFORM

npm ERR! notsup Unsupported
npm ERR! notsup Not compatible with your operating system or architecture: fsevents@0.3.8
npm ERR! notsup Valid OS:    darwin
npm ERR! notsup Valid Arch:  any
npm ERR! notsup Actual OS:   linux
npm ERR! notsup Actual Arch: arm

edit npm-shrinkwrap.json and delete the following lines.

"fsevents": {
  "version": "0.3.8",
  "from": "fsevents@>=0.3.1 <0.4.0",
  "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-0.3.8.tgz"
},

Once the build is completed, you can run:

./scripts/code.sh

The script will download a few more required files and perform a few initialisation steps before the IDE launches. The editor performance was very poor when I ran it using X11 forwarding however. Perhaps, it works better if running within a native X11 display.

Visual Studio Code running on the Raspberry Pi 3 using X11 forwarding

Visual Studio Code running on the Raspberry Pi 3 using X11 forwarding

How to control GPIO pins on the Raspberry Pi 3 using C#

GPIO pins on the Raspberry Pi can be controlled using the sysfs interface, which is a virtual filesystem that the Linux kernel provides. In this guide, we will write a basic C# class to control available pins on the Pi through sysfs.

Understanding the sysfs interface
sysfs provides access to the GPIO pins at the path /sys/class/gpio. You can cd into this path and ls to list files in the directory. There are two special files here which are export and unexport. You write to the export file to activate a particular pin, while writing to unexport deactivates the pin. The following example activates GPIO pin 18.

echo 18 > /sys/class/gpio/export

You can verify that the pin is activated by listing the files in the /sys/class/gpio directory. You should see a gpio18 folder in the directory listing. After the pin has been activated, you should specify whether the pin should be an input or output pin before you can read or write values. You do this for input like so:

echo in > /sys/class/gpio/gpio18/direction

Or for output:

echo out > /sys/class/gpio/gpio18/direction

If the pin is specified as an output pin, you can write a value of either 0 (low) or 1 (high) for the pin. If a LED is connected to the pin for this example, a value of 0 will turn the LED off, while a value of 1 will turn the LED on. To specify the pin value, you can do this:

echo 1 > /sys/class/gpio/gpio18/value
echo 0 > /sys/class/gpio/gpio18/value

Once you are done with the pin, you can deactivate it using:

echo 18 > /sys/class/gpio/unexport

Writing the C# class
Now that we have an idea of how sysfs works, we can create a class to implement the necessary steps. The sysfs approach basically requires writing values to the file, so we can use simple file I/O operations to achieve the desired result. The full listing for the GPIO class can be found at https://gitlab.com/akinwale/NaniteIo/blob/master/Nanite/IO/GPIO.cs.

The first thing we’ll do is add the using statements for the namespaces. System.IO is required for FileStream, StreamReader and StreamWriter which are used for file I/O. System.Threading is required for the Thread class, while Nanite.Exceptions contains the custom exceptions defined for our project. We’ll also define enumerations for the GPIO direction and value, and a few constants for strings like the GPIO path and other special files. The class will be defined as static, because we do not need to create an instance of the class.

using System.IO;
using System.Threading;
using Nanite.Exceptions;

namespace Nanite.IO
{
    public static class GPIO
    {
        public enum Direction
        {
            Input = 0,
            Output = 1
        };

        public enum Value
        {
            Low = 0,
            High = 1
        };

        private const string GPIOPath = "/sys/class/gpio";

        private const string GPIODirection = "direction";

        private const string GPIOExport = "export";

        private const string GPIOUnexport = "unexport";

        private const string GPIOValue = "value";

Pretty straightforward so far. The first method we’re going to define is the PinMode method, which will take the pin number and direction as parameters. This method will activate the pin and then set the direction to either in or out depending on the specified parameter value.

public static void PinMode(int pin, Direction direction)
{
    ClosePin(pin);

    string pinPath = Path.Combine(GPIOPath, string.Format("gpio{0}", pin));
    if (!Directory.Exists(pinPath))
    {
        try
        {
            using (StreamWriter writer = new StreamWriter(new FileStream(
                Path.Combine(GPIOPath, GPIOExport), FileMode.Open, FileAccess.Write, FileShare.ReadWrite)))
            {
                writer.Write(pin);
            }
        }
        catch (IOException ex)
        {
            throw new GPIOException("Unable to export the pin.", ex);
        }
    }

    do
    {
        // Wait until the pin has been initialised properly before setting the direction
        Thread.Sleep(500);
    } while (!Directory.Exists(pinPath));

    try
    {
        using (StreamWriter writer = new StreamWriter(new FileStream(
            Path.Combine(pinPath, GPIODirection), FileMode.Truncate, FileAccess.Write, FileShare.ReadWrite)))
        {
            writer.Write(direction == Direction.Input ? "in" : "out");
        }
    }
    catch (IOException ex)
    {
        throw new GPIOException("Unable to set the pin direction.", ex);
    }
}

We build the pinPath string making use of Path.Combine(GPIOPath, string.Format("gpio{0}", pin));. If the value specified for the pin parameter is 18, pinPath will contain the string, "/sys/class/gpio/gpio18". The ClosePin method call is optional, but the idea behind this is that the pin should be deactivated first before activating. We also check if the gpio pin directory exists using if (!Directory.Exists(pinPath)) before activating to make sure we are not activating a pin that has already been activated.

After the request for pin activation, there may be a small delay which is why we have a while loop which waits until the corresponding gpio pin directory has been created before we set the pin direction. Thread.Sleep(500) makes the program wait 500 milliseconds before proceeding to the next statement. Note that this while loop is completely optional, but it acts as a safeguard against setting the pin direction before the gpio pin directory has been created by the system. One thing to take note of is if the gpio pin directory never gets created (for instance, if the pin is invalid), the loop may end up running forever. To fix this, we can set a maximum number of times the loop should run before ending the loop.

int loopCount = 1;
do
{
    if (loopCount > 5)
    {
        // Exit the loop after it has been run 5 times (waited for 2.5s)
        break;
    }

    // Wait until the pin has been initialised properly before setting the direction
    Thread.Sleep(500);
    loopCount++;
} while (!Directory.Exists(pinPath));

The next method is the ClosePin method which takes the pin number as a parameter. This method checks if the pin directory exists before it writes the pin number to the /sys/class/gpio/unexport file.

public static void ClosePin(int pin)
{
    string pinPath = Path.Combine(GPIOPath, string.Format("gpio{0}", pin));
    if (Directory.Exists(pinPath))
    {
        try
        {
            using (StreamWriter writer = new StreamWriter(new FileStream(
                Path.Combine(GPIOPath, GPIOUnexport), FileMode.Open, FileAccess.Write, FileShare.ReadWrite)))
            {
                writer.Write(pin);
            }
        }
        catch (IOException ex)
        {
            throw new GPIOException("Unable to close the pin.", ex);
        }
    }
}

We create the Write method to write a value to a pin. It takes two parameters, the pin number and the value which is of the Value enumerator type with possible values Value.Low or Value.High. In this method, we make use Path.Combine to create the full path to the value file in the gpio pin directory. For pin 18, this will be "/sys/class/gpio/gpio18/value". If value for the value parameter is Value.Low, we write 0 to the file, otherwise if it’s Value.High, we write 1 to the file.

public static void Write(int pin, Value value)
{
    try
    {
        string pinPath = Path.Combine(GPIOPath, string.Format("gpio{0}", pin));
        using (StreamWriter writer = new StreamWriter(new FileStream(
            Path.Combine(pinPath, GPIOValue), FileMode.Truncate, FileAccess.Write, FileShare.ReadWrite)))
        {
            writer.Write(value == Value.Low ? 0 : 1);
        }
    }
    catch (IOException ex)
    {
        throw new GPIOException("Unable to write the pin value.", ex);
    }
}

Finally, we have our Read method to read a value from a pin. It will return either Value.Low or Value.High depending on what the pin has been set to. The question mark at the end of the method return type indicates that we can return null for the method if the value retrieved is invalid.

public static Value? Read(int pin)
{
    int pinValue = -1;

    try
    {
        string pinPath = Path.Combine(GPIOPath, string.Format("gpio{0}", pin));
        using (StreamReader reader = new StreamReader(new FileStream(
            Path.Combine(pinPath, GPIOValue), FileMode.Open, FileAccess.Read, FileShare.ReadWrite)))
        {
            int.TryParse(reader.ReadToEnd(), out pinValue);
        }
    }
    catch (IOException ex)
    {
        throw new GPIOException("Unable to read the pin value.", ex);
    }

    if (pinValue != 0 && pinValue != 1)
    {
        return null;
    }

    return (Value) pinValue;
}

To determine if the retrieved value is valid, we add a couple of checks in the method. The first is the int.TryParse method, which returns false if the retrieved value is not a valid integer. Then verify that the value is either 0 or 1 using if (pinValue != 0 && pinValue != 1). If it’s neither 0 nor 1, null is returned. Otherwise, the corresponding enumeration value is returned by casting the integer to GPIO.Value.

Finally, we can put this all together in a sample program. If a LED is connected to pin 18, the LED will light up when the value is set to High and turn off when the value is set to Low.

using System;
using System.Threading;
using Nanite.IO;
using Nanite.Exceptions;

namespace NaniteIoSample
{
    class Program
    {
        public static void Main(string[] args)
        {
            // Activate the pin and set the direction as Output
            GPIO.PinMode(18, GPIO.Direction.Output);

            // Blink a LED connected to pin 18 up to 50 times
            for (int i = 0; i < 50; i++)
            {
                GPIO.Write(18, GPIO.Value.High);
                Thread.Sleep(200);

                GPIO.Write(18, GPIO.Value.Low);
                Thread.Sleep(200);
            }

            // Close the pin after we're done
            GPIO.ClosePin(18);
        }
    }
}

Source Code
The full code listing for the GPIO class can be obtained from https://gitlab.com/akinwale/NaniteIo/blob/master/Nanite/IO/GPIO.cs.

Building MonoDevelop for the Raspberry Pi 3

4 Dec 2017 Update
I ran into some issues building the latest github versions of Mono and MonoDevelop on the PINE64, and I guess the same may apply here. If you encounter any difficulty building either Mono or MonoDevelop, you can try using the specific versions listed below. You can checkout the specific tags immediately after cloning the corresponding repositories before you start building.
Mono 4.8.1.0 – git checkout tags/mono-4.8.1.0
MonoDevelop 6.1.0.5441 – git checkout tags/monodevelop-6.1.0.5441

Since I will be using C# for most of my development (with a combination of C for some native system functionality), I decided to go with Mono. This guide is based on the assumption that you’re running the May 2016 Raspbian Jessie Lite image. The easiest way to get MonoDevelop up and running would be to run sudo apt-get install monodevelop which would also handle all the necessary dependencies including the Mono runtime. However, the versions in the repository are pretty old, and I want to be able to make use of .NET 4 features.

Another option for .NET development on Linux is .NET Core. Version 1.0 was officially announced by Microsoft a few days ago, but there aren’t ARM binaries available and I haven’t been able to successfully build it for the Pi, yet.

Git
The Mono project code is hosted on Github, so the first thing to be done is to install git.

sudo apt-get install git

Build Mono
Obtain the source code from the Github repository using the command

git clone https://github.com/mono/mono

Then install the Mono build process prerequisites.

sudo apt-get install autoconf autotool libtool libtool-bin

You can follow the build instructions in the README.md for the repository at https://github.com/mono/mono/blob/master/README.md. To summarise, change to the source root directory (cd mono) and run the following commands.

./autogen.sh --prefix=/usr
make get-monolite-latest
make
sudo make install

If you wish to run the mono and mcs test suites, you can do a make check before make install. The build will take quite a while, so you have to be patient. I didn't time my build, but my best guess would be about 3 to 4 hours.

Build FSharp
MonoDevelop apparently requires the F# compiler to be installed. First thing to do is to import trusted root certificates required by the NuGet package manager into the machine store. The NuGet package manager retrieves certain required packages as part of the build process, so this is required.

sudo mozroots --import --sync
sudo certmgr -ssl -m https://nuget.org

Next, we clone the FSharp git repository and build.

git clone https://github.com/fsharp/fsharp
cd fsharp
./autogen.sh --prefix=/usr
make
sudo make install

Build additional MonoDevelop dependencies
MonoDevelop also requires gtk-sharp and gnome-sharp to be installed on the system. The first step is to install the rest of the apt dependencies for all three packages.

sudo apt-get install cmake libgtk2.0-dev libglade2-dev libgnomecanvas2-dev libgnome2-dev libgnomeui-dev libssh2-1-dev devscripts

devscripts will be used to create a package of PCL Assemblies which is required for the MonoDevelop build process.

Once the dependencies have been installed, gtk-sharp should be built first and then gnome-sharp.

To build gtk-sharp

git clone -b gtk-sharp-2-12-branch --single-branch https://github.com/mono/gtk-sharp
cd gtk-sharp
./bootstrap-2.12 --prefix=/usr
make
sudo make install

And gnome-sharp

git clone https://github.com/mono/gnome-sharp
cd gnome-sharp
./bootstrap-2.24 --prefix=/usr
make
sudo make install

Build MonoDevelop
If you made it through all of that, you can finally proceed to build MonoDevelop. But there are a few caveats which we'll cover in a bit.

git clone https://github.com/mono/monodevelop
cd monodevelop
git submodule update --init --recursive
./configure --prefix=/usr --profile=stable --disable-nls

The first error I encountered after I running make was an issue with NuGet not finding a number of packages. To fix this while your current directory is the monodevelop directory, run the following commands and then run make again (if you've run it previously).

cd main/.nuget
mono NuGet.exe update -self
cd ../../

The next error stated that certain PCL Assemblies were missing. To sort this out

git clone http://github.com/directhex/xamarin-referenceassemblies-pcl
cd xamarin-referenceassemblies-pcl/debian
nano control

Remove mono-xbuild from the list of dependencies in the control file, save and close. Then continue with the following commands.

cd ..
debuild -i -us -uc -b
cd ..
sudo dpkg -i referenceassemblies-pcl_2014.04.14-1_all.deb

The final error had to do with the fsharpbinding regarding missing references in a particular assembly. Since I don't need the F# bindings, and it's not a required feature, I removed it from the build process using the following steps (assuming the monodevelop source directory is the working directory).

cd main
nano Makefile.am

Remove the external/fsharpbinding/MonoDevelop.FSharpBinding/FSharpBinding.addin.xml \ line, save the file and close.

rm -r external/fsharpbinding
cd ../

Finally, you can build and install.

make
sudo make install

This build will also take a bit of time, so sit back, relax and rest easy. Once the installation is complete, you can simply run it by typing monodevelop at the command line (assuming you have X11 forwarding enabled in your SSH session).