Users with experience in arduino are familiar with its references, like pinMode() and digitalWrite(). How can we make the use of NETMF easier fro them? We somewhat talked about this before and Ian’s idea of a document guide maybe the best approach.
I have been “learning” at arduino and trying to see how we can do this in C#. Here is what I came up with.
Here is a blink LED example that ship with arduino
// Pin 13 has an LED connected on most Arduino boards.
// give it a name:
int led = 13;
// the setup routine runs once when you press reset:
void setup() {
// initialize the digital pin as an output.
pinMode(led, OUTPUT);
}
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
And this is the C# version
//int led = 13;
Cpu.Pin led = (Cpu.Pin)13;//add pin enumerator in the class
// the setup routine runs once when you press reset:
void setup()
{
// initialize the digital pin as an output.
Duino.Digital.pinMode(led, Duino.Digital.Mode.OUTPUT);
}
// the loop routine runs over and over again forever:
void loop()
{
Duino.Digital.digitalWrite(led, Duino.Digital.Level.HIGH); // turn the LED on (HIGH is the voltage level)
Duino.Time.delay(1000); // wait for a second
Duino.Digital.digitalWrite(led, Duino.Digital.Level.LOW); // turn the LED off by making the voltage LOW
Duino.Time.delay(1000); // wait for a second
}
Which uses this class, which is incomplete! Just brain storming
namespace GHI.OSHW.ArduinoReferenceMap
{
public class Duino
{
public static class Time
{
public static void delay(int ms)
{
Thread.Sleep(ms);
}
}
public static class Digital
{
public enum Mode
{
INPUT,
OUTPUT,
}
public enum Level
{
HIGH=1,
LOW=0,
}
public static void pinMode(Cpu.Pin pin, Mode mode)
{
}
public static void digitalWrite(Cpu.Pin pin, Level level)
{
}
public static bool digitalRead(Cpu.Pin pin)
{
return true;
}
}
}
}
Looks like it can be done to be a mirror of existing libs but this will be a bad way to program in a modern language. Do we really want to use a method to handle IOs instead if creating an IO object and then calling its methods?! But this is about making the first transition easy and about making converting arduino examples to NETMF easier.
I personally don’t like the lower case method names. That’s just me, but it’s not common to .NET/C# even that I know that a lot of People comming from the Unix world are verry used to it.
I also would make
Duino.Digital.digitalWrite()
to
Duino.Digital.wirte()
Is shorter and as I think more readable.
Without global methods it’s impossible to get the same ‘code feeling’ anyway.
And I’m not sure how big the acceptanc would be if everyting is 3 or 4 time longer:
if you define INPUT, OUTPUT, LOW and HIGH as const or readonly fileds, then the code in the overriden Loop method would nearly look like Gus original sample. If you Change the Cpu.Pin params to int, then it’s practically identical.
Why not just an interpreter that converts arduino code to quality C# code? The arduino language isn’t that large. It shouldn’t be too hard. They could write the code they know and learn how it should be written at the same time. While I think your direction is a good step, it’s missing a teaching attribute to it.
I still like this class to be a separate file added to any project. Here it is with the changes. The challenge now is how to use digital pins with these methods! We can’t make a pin high without creating an object and losing that object will cause GC to collect and then the pin is back to input. I guess keep an array of all IOs and control them would be the only way.
using System;
using Microsoft.SPOT;
using System.Threading;
using Microsoft.SPOT.Hardware;
using GHI.OSHW.ArduinoReferenceMap;
namespace GHI.OSHW.ArduinoReferenceMap
{
public class Duino
{
public const int INPUT=0;
public const int OUTPUT =1;
public const int HIGH =1;
public const int LOW =0;
public static void delay(int ms)
{
Thread.Sleep(ms);
}
public static void pinMode(Cpu.Pin pin, int mode)
{
}
public static void digitalWrite(Cpu.Pin pin, int level)
{
}
public static bool digitalRead(Cpu.Pin pin)
{
return true;
}
}
}
namespace MFConsoleApplication1
{
public class Program
{
//int led = 13;
static Cpu.Pin led = (Cpu.Pin)13;//add pin enumerator in the class
// the setup routine runs once when you press reset:
static void setup()
{
// initialize the digital pin as an output.
Duino.pinMode(led, Duino.OUTPUT);
}
// the loop routine runs over and over again forever:
static void loop()
{
Duino.digitalWrite(led, Duino.HIGH); // turn the LED on (HIGH is the voltage level)
Duino.delay(1000); // wait for a second
Duino.digitalWrite(led, Duino.LOW); // turn the LED off by making the voltage LOW
Duino.delay(1000); // wait for a second
}
public static void Main()
{
setup();
while (true)
loop();
}
}
}
What if class Program inherits class Duino ? This may make the use app almost similar to your first example without the Duino.xxx calls ?
I modified the methods to use int instead of Cpu.Pin, the int value can be used by the base class method to instantiate the correct Cpu.Pin
public class Program : Duino
{
static int led = 13;
static void setup()
{
pinMode(led, OUTPUT);
}
static void loop()
{
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
public static void Main()
{
setup();
while (true)
{
loop();
}
}
}
The Arduino language is C (or maybe C++?). The library exposes a set of simple APIs, implementing those might not be so hard (but some of them, it might be!), but translating source code is not a trivial operation.
Agreed. It definitely looks the most like Arduino. I’m not crazy about the idea that every class would have to inherit from it, though.
I think enums would be a welcome addition and considering the user would almost have to be in VS then why not take advantage of some Intellisense. What if Gus’ class introduced some enums. Even an arduino programmer would not be able to ignore the productivity enhancements awarded by Intellisense in this case.
public enum PinMode
{
INPUT,
OUTPUT
}
public enum PinLevel
{
LOW,
HIGH
}
public class Duino
{
public static void delay(int ms)
{
Thread.Sleep(ms);
}
public static void pinMode(Cpu.Pin pin, PinMode mode)
{
}
public static void digitalWrite(Cpu.Pin pin, PinLevel level)
{
}
public static bool digitalRead(Cpu.Pin pin)
{
return true;
}
}
Probably the best plan is to do both const fields and enums. That way existing code runs without modification, and intellisense is there for new development if it’s desired:
I suggest also making it simple for Arduino users to migrate their code to firmware cpp. A lot of Arduino code involves high speed bit banging. If they migrate their hardware drivers there and put their program logic in managed code they end up with a much better bunch of bits.
The few Arduino snibits I tried simply won’t execute fast enough in managed land. …At least not on the tiny chips (like the STMF4).
@ untitled - I find the idea an “arduino”-like *.cpp compiler/interface for netmf/gadgeteer really brillant, bringing the best of both worlds. Anyway, it may require serious development and long term project. Perhaps the fact that arduino-compatible boards (like teensy 3.0) are already using Cortex-M4 should help on the cerb-family front, for example.