Apresentei no post anterior minhas aventuras com o porte do .NET nanoFramework para Linux e NuttX. Nesse artigo irei documentar como você pode executar aplicações .NET nanoFramework usando esse porte em Raspberry Pi Zero.

.NET nanoFramework Solution (Linux Mono)

Você pode usar qualquer solução criada pela extensão do .NET nanoFramework para Visual Studio. Infelizmente não há ainda um template para o dotnet CLI (para ficar independente do VS 2019 por exemplo). Para esse caso eu criei um exemplo que você pode clonar o repositório.

⚠️ Para os passos a seguir iremos usar comandos que fazem parte do Mono. Tenha certeza de ter instalado o pacote mais recente mono-complete em sua distro Linux.

Siga os passos com um terminal aberto:

1- Clone o repositório dos exemplos:

git clone https://github.com/dotnuttx/nanoFrameworkPOSIX-samples.git

2- Entre na pasta Blink:

cd nanoFrameworkPOSIX-samples/Blink

Para esse exemplo vamos compilar o seguinte Program.cs:

using System;
using System.Diagnostics;
using System.Threading;
using System.Device.Gpio;
using nanoFramework.Runtime.Native;

Debug.WriteLine($"Running nanoFramework on {SystemInfo.OEMString}");

try
{
    GpioController gpioController = new GpioController();
    int ledPinNumber;
    PinValue ledValue = PinValue.Low;
    GpioPin led;

    switch (SystemInfo.TargetName) {
        case "pi-zero":
            // pin 16 in the header is the gpio23
            ledPinNumber = 23;
        break;
        case "pi-pico":
            // onboard LED
            ledPinNumber = 25;
        break;
        default:
            throw new Exception($"Your target [{SystemInfo.TargetName}] does not support GPIOs");
    }

    // initialize pin
    led = gpioController.OpenPin(ledPinNumber, PinMode.Output);

    // blink forever
    while (true)
    {
        Debug.WriteLine($"Blinking {ledValue}");

        ledValue = !(bool)ledValue;
        led.Write(ledValue);

        Thread.Sleep(500);
    }
}
catch (Exception ex)
{
    Debug.WriteLine(ex.Message);
    Debug.WriteLine(ex.StackTrace);
}

3- Faça download dos pacotes NuGet listados no packages.config, execute:

nuget restore

⚠️ A versão 2.6.4.6 do interpretador para Linux precisa exatamente da versão 1.10.5-preview.18 do pacote nanoFramework.CoreLibrary

4- Compile a solução, execute:

msbuild

Após a build você deverá ter os seguintes arquivos com extensão .pe na pasta bin/Debug/ do projeto:

ls -l bin/Debug/*.pe

-rw-r--r-- 1 castello castello   960 Jun 23 00:34 bin/Debug/Blink.pe
-rwxr--r-- 1 castello castello  5684 Jun 19 08:09 bin/Debug/System.Device.Gpio.pe
-rwxr--r-- 1 castello castello 31668 Jun 19 07:25 bin/Debug/mscorlib.pe
-rwxr--r-- 1 castello castello  3412 Jun 19 07:44 bin/Debug/nanoFramework.Runtime.Events.pe
-rwxr--r-- 1 castello castello  1496 Jun 19 07:46 bin/Debug/nanoFramework.Runtime.Native.peRuntime.Native.pe

Esses são os Portable executables/assemblies que o interpretador do .NET nanoFramework sabe ler e executar. Se você tem eles listados na pasta bin/Debug/, parabéns 🎉 você compilou a aplicação com sucesso.

Conectando LED no Raspberry Pi Zero

Como vamos executar um blink precisamos de um LED conectado no GPIO da nossa Raspberry Pi Zero. Para esse exemplo estou usando o GPIO23 pino 16 no header padrão das Raspberry Pi B:

⚠️ Você pode usar qualquer outro GPIO disponível no header da sua Pi Zero. Lembre-se de mudar a referência do ledPinNumber no Program.cs para o case "pi-zero":

nanoFramework Runtime (Raspberry Pi OS arm32v6)

Você pode baixar binários pré-compilados do interpretador para Raspberry Pi Zero aqui: https://github.com/dotnuttx/nf-Community-Targets/releases

⚠️ Os seguintes passos devem ser executados em uma sessão de terminal da Raspberry Pi Zero. Conecte-se via serial ou SSH.

Para instalar baixe o binário, adicione permissões de execução e mova para /usr/bin/:

wget https://github.com/dotnuttx/nf-Community-Targets/releases/download/v2.6.4.6/dotnet-nf.armel-Linux.2646
chmod +x dotnet-nf.armel-Linux.2646
sudo mv dotnet-nf.armel-Linux.2646 /usr/bin/dotnet-nf

Agora podemos enfim usar o runtime para rodar nossa aplicação compilada nos primeiros passos. O binário recebe como argumento o caminho de uma pasta aonde irá carregar todos os arquivos .pe listados. No seu computador de desenvolvimento vá até a pasta Blink/bin/Debug/ do repositório do exemplo e copie todos os arquivos .pe para a Raspberry Pi Zero. Se você tiver configurado o SSH da sua Raspberry Pi Zero você pode executar:

scp -r bin/Debug/*.pe pi@192.168.1.98:/home/pi

⚠️ Lembrando que 192.168.1.98 é só um exemplo de uso, troque pelo ip local da sua Raspberry Pi Zero

⚠️ Caso não tenha configurado o SSH ou não esteja com uma conexão Wi-Fi disponível, ou mesmo você tenha a versão sem suporte à Wi-Fi da Pi Zero, uma opção é copiar os arquivos .pe para a partição boot do SDCard do Raspberry Pi OS.

Com os arquivos .pe na placa você pode agora executar sua aplicação:

⚠️ Caso você tenha copiado os arquivos via SSH para o /home/pi

dotnet-nf /home/pi/

⚠️ Caso você tenha copiado os arquivos para a partição boot do SDCard. Aqui eu criei uma nova pasta nf, então o comando ficou:

dotnet-nf /boot/nf/

Se você tiver algo parecido com o seguinte output e seu LED estiver piscando:

Parabéns 🎉! Você executou seu primeiro blink usando .NET nanoFramework em uma Raspberry Pi Zero.

Conclusão

Ter o nanoFramework rodando em Linux arm32v6 é uma opção interessante. Por exemplo, o "full" dotnet só suporta arm32v7 e arm64v8. Uma outra opção pode ser o Mono, que também tem releases para arm32v6. O pacote mono-runtime no Raspberry Pi OS instala ~20.7MB

⚠️ Lembrando que isso é algo que estou trabalhando nos finais de semana e durante meu tempo livre. É algo EXTREMAMENTE EXPERIMENTAL e não estou sendo financiado por nenhum grupo ou instituição para tal.

Gostou da possibilidade? Se isso for de alguma forma útil, ou fizer sentido para você, deixe me saber. Me mande um alô no Twitter @math_castello ou no Linkedin 👍