Custom Firmata function called by Windows 10 IoT Core

In my previous blog, we investigated the usage of the standard Firmata protocol to communicate between UWP apps and an Arduino. I ended with directing to Channel 9 for more information about custom functions in Firmata.

But I think that’s not enough ūüôā First of all, that demo in the presentation failed. And next to that, it simply lacked any description on how to do it yourself.

I have put some time in figuring out this functionality. Again, the example below is based on the code of Part 4.

So we want to call some logic on the Arduino, using Firmata, and it has to be available for real-time usage. So we want to pass some parameters and we want to receive some response.

This is part 5 of a series of blogs about device communication between Arduino, RaspberryPi etc:

  • Part 1: Using I2C to connect two Arduino Nano‚Äôs
  • Part 2: Using I2C between Rpi Master and Arduino Slave
  • Part 3: Use Bluetooth between Win 10 UWP and Arduino
  • Part 4: Add virtual Arduino ports to your UWP app
  • Part 5: Custom Firmata function called by Windows 10 IoT Core
  • Part 6: Better long running custom Firmata functions
  • Part 7: Custom servo usage in Firmata
  • Part 8: Using NRF24L01+ modules¬†between Arduino’s
  • Part 9: Cheap Arduino mesh using RF24 radio¬†modules

I took a look at the source code from the presentation of Mitch Denny, especially the Arduino Firmata function. I just made a comparison to the standard Firmata code he used as template (which was Firmata 2.4.3  from April 11, 2015).

Essentially, we only have to add a new function so we define one which echoes the input in the response:

#define ECHO_QUERY  0x44

First, add this to the rest of the defines at the top of the Standard Firmata code.

Next, we add the actual function as part of the sysexCallback:

...
void sysexCallback(byte command, byte argc, byte *argv)
{
  byte mode;
  byte stopTX;
  byte slaveAddress;
  byte data;
  int slaveRegister;
  unsigned int delayTime;

  String echoText;

  switch (command) {
    case ECHO_QUERY:

      echoText = "Echo Firmata-";
      for (int i = 0; i<argc; i++)
      {
        echoText = echoText + argv[i] + "-";
      }

      Firmata.sendString(echoText.c_str());

    break;
...

The new function is just a case statement inside the switch inside that sysexCallback. Our Echo query takes the arguments passed (multiple bytes behind an array pointer) and iterate through them using the count.

And we return a response using the sendString() function.

Note: the echoText string variable is declared OUTSIDE the case statement.

The now not-so-standard Firmata must be deployed to the Arduino.

Our UWP app from a previous blog must be altered. The biggest change is the introduction of the UwpFirmata class. This class gives us access to the sysex functionality.  So change the code of the Start button:

private void btnStart_Click(object sender, RoutedEventArgs e)
{
  _bluetooth = new BluetoothSerial("HC-05");
  _bluetooth.ConnectionLost += _bluetooth_ConnectionLost;
  _bluetooth.ConnectionFailed += _bluetooth_ConnectionFailed;
  _bluetooth.ConnectionEstablished += OnConnectionEstablished;
 
  _firmata = new UwpFirmata();
  _firmata.StringMessageReceived += 
                        Firmata_StringMessageReceived;
  _arduino = new RemoteDevice(_firmata);
  _firmata.begin(_bluetooth);
 
  _bluetooth.begin(0, SerialConfig.SERIAL_8N1);
 
  _arduino.DeviceReady += _arduino_DeviceReady;
}

The Firmata is put between the Bluetooth logic and the Arduino proxy. Now add an extra button to make the Echo call:

<Button Name="btnEcho"
        Click="btnEcho_Click"
        FontSize="20"
        Content="Echo"
        IsEnabled="False" />

<TextBlock Name="tbRead" FontSize="40" />

Finally we pass some data when connected in the Echo button click. And we receive a message back in an event handler:

private void btnEcho_Click(object sender, RoutedEventArgs e)
{
    byte ECHO_QUERY = 0x44;
    _firmata.sendSysex(ECHO_QUERY, 
                       new byte[] { 66, 67 }.AsBuffer());
    _firmata.flush();
}

private async void Firmata_StringMessageReceived(
              UwpFirmata caller, StringCallbackEventArgs argv)
{
    var content = argv.getString();
    await Dispatcher.RunAsync(
            CoreDispatcherPriority.Normal, () =>
            {
              tbRead.Text = content;
            });
}

And that’s all. We call the Echo query using the same ID (0x44) and we pass the values 66 and 67:

FirmataEcho

The Arduino translates the two bytes into a string which is returned.

There are some observations:

  1. There is no reference in the string returned to the called function. I recommend to add the function ID in the response. This way responses from multiple function can not be mixed up.
  2. The bytes pass have a maximum op 127. We I sent 128, I received 0 back.
  3. Do not forget to call the flush method after calling SendSysex. You get a strange  behaviour as when the call is actually made or when the response is returned.

And with this example it must be fairly simple to write your own custom Firmata functions. Please let me know it this is working for you.

 

Advertenties

14 thoughts on “Custom Firmata function called by Windows 10 IoT Core

  1. This solution doesn’t seem to work for me. I’m using USB instead of bluetooth. My custom command in the Arduino sketch is correctly received, but C# doesn’t raise the StringMessageReceived event:
    firmata.StringMessageReceived += stringMessage;

    the method stringMessage is never invoked.

    On the arduino side I have kept it very simple:
    Firmata.sendString(“hello”);

    Which is under my custom command in the switch(command).

    Any idea where I am going wrong?

    1. Hello jayblackwell, sorry it’s not working properly. I had some issues in the past with the vaiables within the case statement. Please check if String echoText; is declared at the top of the sysexCallback function. And it’s always a good thing to check if the whole sketch is still working in the app provided by MSFT (Windows Remote Arduino Experience)

  2. Hi Sander – thanks for all the info and nice tutorials….youve been a great help for me. I was hoping you could tell me whether im on the right track, and even possible? Im trying to create a custom function for my max31865 temperature sensor (https://hallard.me/max31865/), based on the examples given above, but havent had any luck yet. The ino file seems pretty simple (https://github.com/hallard/arduino-max31865/blob/master/Examples/Read_Temperature/Read_Temperature.ino) Im also not sure if SPI will work? Please, any help would be much appreciated.

    1. Hello Roelof, it’s nice to hear my blog is helpful. Unfortunately my experience with sensor is limited to the ones I have. I could be the soldering, could de something else…

Reacties zijn gesloten.