Fluent Interop 1.6 - Project Showcase - Netduino Forums
   
Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Fluent Interop 1.6


  • Please log in to reply
12 replies to this topic

#1 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 06 February 2011 - 11:06 PM

Hello,

This latest version of the fluent framework incorporates some major new features:
  • Support for firmware timers (that is, HAL_COMPLETIONS)
  • Much friendlier support for functions that call one another
  • Improved argument syntax (no more funny Unicode characters in the argument list)
First a video:
http://www.youtube.com/watch?v=6UI8ex6IeSo

In this video, a C# thread is counting to 30 (once per second), meanwhile a compiled routine is flashing the LED on and off (also once per second). I should stress that the LED blinking routine is running entirely on the firmware side with no .NET interaction whatsoever: a timeout on a HAL_COMPLETION triggers an interrupt service routine, which changes the state of the LED and then reschedules the timer to fire again half a second later. This will continue forever until the C# side tells it to stop.

This version shows much improved support for functions that call one another. For interrupt service routines, it is common to have the following pattern:
  • A "control" method to set up and tear down the state of the ISR, and schedule it to run
  • The interrupt service routine itself
In previous versions of the framework, properly setting up two separate interacting functions was a lot of work involving some confusing and fragile interactions. However, I recently had the brainwave that my framework should allow you to compile several functions at the same time, and these functions should be able to readily call one another as well as share the same static variables. In this way the situation is reminiscent of a C source file which might contain static variables as well as the definitions of several functions.

Accordingly, the source code for the above blinking demo is almost a pleasure to read:
using System.Threading;
using FluentInterop.CodeGeneration;
using Kosak.SimpleInterop;
using Microsoft.SPOT;
using SecretLabs.NETMF.Hardware.Netduino;

namespace TimerDemo {
  public class Program {
    public static void Main() {
      var code=BuildCode();
      new Thread(()=>BlinkLedFor20Seconds(code)).Start();

      //count to 30 in main thread
      for(var i=0; i<30; ++i) {
        Debug.Print("i="+i);
        Thread.Sleep(1000);
      }
    }

    private static void BlinkLedFor20Seconds(CompiledCode code) {
      //Because the code will be running as an interrupt, we need to keep the array pinned
      unsafe {
        fixed(short* fix=code.OpCodes) {
          code.Invoke(500000, (int)Pins.ONBOARD_LED); //on for 1/2 second, off for 1/2 second
          Thread.Sleep(20*1000); //sleep for 20 seconds
          code.Invoke(0); //abort timer so we can safely exit this fixed block
        }
      }
    }

    private static CompiledCode BuildCode() {
      return CodeGenerator.Compile(g => {
        //----------------------------------------------------------------------
        //static variables shared by both the setup routine and the interrupt service routine
        //----------------------------------------------------------------------

        //delay between interrupts in microseconds
        var delayBetweenInterrupts=g.Declare.Static.Int("delayBetweenInterrupts");
        
        //current led status (on or off)
        var ledStatus=g.Declare.Static.Int("ledStatus");

        //stashed copy of the interop method dispatch table (the interrupt service routine needs this)
        var firmware=g.Declare.Static.MethodDispatchTable("firmware");

        //the output port that we will turn on and off
        var port=g.Declare.Static.FastOutputPort("port");

        //the so-called "HAL Completion" that we use for our timer
        var hal=g.Declare.Static.HalCompletion("hal");

        //forward declaration of the interrupt status routine (body defined below)
        var interruptServiceRoutine=g.Declare.Function("interruptServiceRoutine");

        //----------------------------------------------------------------------
        //main(delayInMicroseconds, pinNumber)
        //
        //if delayInMicroseconds>0, then initialize the output port and the timer and enqueue the timer
        //  otherwise, dequeue the timer
        //----------------------------------------------------------------------
        g.Declare.Function("main", f => {
          //gather function arguments
          var args=f.StandardArgs;
          var delayInMicroseconds=args.intParam0;
          var pinNumber=args.intParam1;
          var firmwareParam=args.firmwareParam16;

          //delayInMicroseconds>0 means initialize, otherwise dequeue.
          f.If(delayInMicroseconds>0)
            .Then(() => {
              delayBetweenInterrupts.Value=delayInMicroseconds;
              ledStatus.Value=0;
              firmware.Value=firmwareParam;

              port.Initialize(firmware, pinNumber, false);
              hal.InitializeForISR(firmware, interruptServiceRoutine);

              //enqueue for the first time
              hal.EnqueueDelta(firmware, delayInMicroseconds);
            })
            .Else(() => {
              hal.Abort(firmware);
            })
            .Endif();
        });

        //----------------------------------------------------------------------
        //interruptServiceRoutine()
        //----------------------------------------------------------------------
        interruptServiceRoutine.Define(f => {
          ledStatus.Value=1-ledStatus;
          port.Write(ledStatus);

          //re-enqueue
          hal.EnqueueDelta(firmware, delayBetweenInterrupts);
        });
      });
    }
  }
}

As always, I attach new firmware (firmware\*) as well as the above demo program (code\TimerDemo\TimerDemo.sln)

P.S. Go Steelers!

Attached Files



#2 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 07 February 2011 - 02:03 AM

As always Corey, very impressive.

#3 Innovactive

Innovactive

    Member

  • Members
  • PipPip
  • 29 posts

Posted 07 February 2011 - 06:40 AM

That's amazing. Why not to try to use Fluent Interop to natively acquire and process IO change notifications coming from a fast quadrature encoder (e.g. 2000 pulses/s) or talk to internal mcu's input capture module?

#4 Illishar

Illishar

    Advanced Member

  • Members
  • PipPipPip
  • 146 posts

Posted 07 February 2011 - 08:16 AM

It's getting almost readable now. Very nice.

#5 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 07 February 2011 - 01:26 PM

Why not to try to use Fluent Interop to natively acquire and process IO change notifications coming from a fast quadrature encoder (e.g. 2000 pulses/s) or talk to internal mcu's input capture module?

Sounds interesting! I have no idea what either of those things are (other than what I just read in Wikipedia 5 minutes ago) but I'd be willing to help out if someone wanted to build something.

#6 Fabien Royer

Fabien Royer

    Advanced Member

  • Members
  • PipPipPip
  • 406 posts
  • LocationRedmond, WA

Posted 07 February 2011 - 04:41 PM

Great work Corey! The code is getting very readable. Cheers, -Fabien.

#7 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 16 March 2011 - 01:43 PM

Corey, some question to you that may help me and maybe other people.
I don't know Fluent so much, I never tried it, but I think should be really interesting.

What I do like of Fluent is:
  • it is another way to softly "program" your own application, without having to upload the whole firmware. (At least until something new will be given by the NetMF staff).
  • the ability to work with native code parts, even the language is *not* lo-level. I'd also say even "safe", but on that I'm not sure.
  • it is functional-like and that's exciting me so much!

What I do not like is:
  • you must have a firmware different than the SecretLabs's official one. At least until Chris will add what the Fluent needs.
  • the Fluent part is a big-block indeed: that's scaring me a lot.

The questions:
  • The Fluent 1.6 is based on what version of Chris's firmware?
  • What about the several versions that Chris is publishing?
  • How many ROM/RAM will take the Fluent itself?
  • Forget a moment that Fluent is your creature: do you think is much more an extreme way to avoid C++ or may you see it also for relatively large programs. As an example, suppose you have to write the equivalent of a 100-200 classic C# program, do you think Fluent is still OK?

Thanks a lot.
Mario
Biggest fault of Netduino? It runs by electricity.

#8 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 16 March 2011 - 03:21 PM

it is another way to softly "program" your own application, without having to upload the whole firmware. (At least until something new will be given by the NetMF staff).

Yes, that was a key driver of the design. I do not want to wait 5+ minutes while my firmware reflashes.

the ability to work with native code parts, even the language is *not* lo-level. I'd also say even "safe", but on that I'm not sure.

Agree. I think this forum is a little too obsessed with pure "safety" (after all, this is a circuit you have on your desk with wires and components and solder everywhere, and you're one crossed wire away from shorting out the device, but nevertheless you refuse to use a pointer in your language because it's not "safe"). My own internal guideline for Fluent, and for the Netduino in general, is that it ought to be "safe enough" so that programming/debugging is pleasant rather than a confusing nightmare, but not necessarily purely safe from a theoretical perspective.

it is functional-like and that's exciting me so much!

Yep. Although the functional parts were for my own selfish purposes-as they made the fluent compiler much easier to write.

And with regard to the rest of the questions, I'll address them imperfectly and in arbitrary order:

  • The firmware change that supports Fluent is trivial. It probably adds a couple hundred bytes to the size of the firmware.
  • The version I support is whatever I downloaded from the Netduino home page last time I built the firmware. If there is a new version somewhere I'd be happy to port Fluent to it (especially if there are gcc instructions rather than RVDS instructions, as I don't have RVDS and I'm not sure it's worth paying $1000+ for it for this hobby project)
  • The job of the firmware side is basically to jump to (i.e. move the CPU's program counter to) the start of an array. That's it. Whatever happens to be inside that array is someone else's responsibility (in this case it is the Fluent library's job in C# to provide executable instructions)
  • On the C# side there is a very large (by Netduino standards) program that compiles this freaky little Fluent language into Thumb opcodes, with the intention that this array would eventually be handed off for execution to the firmware entry point described above. This program is large, not especially efficient, and kind of slow. I wrote it to prove to the world that it could be done, but for practical purposes it's pretty awkward for daily use :blink:
  • The only practical thing to do is to run the Fluent compiler in the Netduino emulator, have it spit out the array, and then paste that array into your Netduino program. Then your Netduino program will actually be quite small (although now the compile-run-test cycle is now longer and awkward again)
  • Chris Walker says that he is going to put some kind of entry point in the firmware that will accomplish something related to my own entry point. Namely there will be some way to jump to ARM/Thumb opcodes. The contents of those opcodes will be determined by someone else. When he releases firmware with that change, then I could, in principle, change the Fluent library to match it (but see below)
  • I would be happy to add my Fluent entry point to any release of the firmware that comes out, provided that (1) the source code is available, and (2) someone helps me with the instructions to compile it with some version of gcc.
  • However: lately I've been secretly working on a new version of this concept which takes a very different approach. Basically I am trying to write a simple NGEN-like tool that will compile a limited subset of C# into assembly. It will definitely not compile any arbitrary C# code, but it will compile a subset of C# that is at least as powerful as the Fluent language. So you write your speed-critical subroutines in the IDE, in C#, but you'd be careful to use very simple types (probably just ints and bytes and pointers thereto), then some post-build step would recompile these subroutines as native assembly.
  • I've been toying with this idea for a while and haven't gotten very far yet. But because I think it's more viable and practical than Fluent, I kind of want to stop messing around with Fluent and start focusing on this approach.
Does that make sense?

Edited by Corey Kosak, 16 March 2011 - 03:27 PM.


#9 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 16 March 2011 - 04:53 PM

Yes, that was a key driver of the design. I do not want to wait 5+ minutes while my firmware reflashes.

Not only: if I send a bunch of lines of C# (equivalent), maybe on a very poor comm line, has no sense to upload 1000x more.
I'd also add that I would prefer having a stable and running device, without losing control of it, where I may insert my own "snippet" on-the-fly.

I think this forum is a little too obsessed with pure "safety" (after all, this is a circuit you have on your desk with wires and components and solder everywhere, and you're one crossed wire away from shorting out the device, but nevertheless you refuse to use a pointer in your language because it's not "safe").

I have a past of circuit design, but it was an hell simple to make an hardware working at best, than to publish a firmware/software without bugs. No comparison. Also hard to explain to my bosses. <_<
However, I must confess to be obsessed to safe and polite coding too. For the reason just above!

However: lately I've been secretly working on a new version of this concept which takes a very different approach. Basically I am trying to write a simple NGEN-like tool that will compile a limited subset of C# into assembly. It will definitely not compile any arbitrary C# code, but it will compile a subset of C# that is at least as powerful as the Fluent language. So you write your speed-critical subroutines in the IDE, in C#, but you'd be careful to use very simple types (probably just ints and bytes and pointers thereto), then some post-build step would recompile these subroutines as native assembly.

Ha!...My interest on Fluent was for the same idea (or at least similar).
I have two different targets:
  • just like you, create a script that would be compiled runtime into Fluent;
  • use xaml (of Workflow) to instruct N how to do some activities.
Both these scenario should take a string as input, because is a easy way to send data via web/HTTP (e.g. web-page). The actual target is to offer some tool to "program" small activities *without* upgrading firmware.
The actual problem is that I have very few time and tend to use the weekends to build something.
Anyway I will keep you informed about my moves.

Cheers
Mario
Biggest fault of Netduino? It runs by electricity.

#10 Cuno

Cuno

    Advanced Member

  • Members
  • PipPipPip
  • 144 posts
  • LocationZürich / Switzerland

Posted 17 March 2011 - 08:19 PM

Does that make sense?


A lot!

#11 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 17 March 2011 - 11:41 PM

However: lately I've been secretly working on a new version of this concept which takes a very different approach. Basically I am trying to write a simple NGEN-like tool that will compile a limited subset of C# into assembly. It will definitely not compile any arbitrary C# code, but it will compile a subset of C# that is at least as powerful as the Fluent language. So you write your speed-critical subroutines in the IDE, in C#, but you'd be careful to use very simple types (probably just ints and bytes and pointers thereto), then some post-build step would recompile these subroutines as native assembly.

Corey, that rocks. We could definitely support that with runtime interop as well.

Chris

#12 gol706

gol706

    New Member

  • Members
  • Pip
  • 1 posts

Posted 20 March 2011 - 09:43 PM

Corey, Do you know what it would take to gett a version of the firmware for the Netduino Mini?

#13 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 20 March 2011 - 11:09 PM

Do you know what it would take to gett a version of the firmware for the Netduino Mini?

It would probably be pretty easy. However, right now I'm working on the first steps of my SimpleNGEN project--if this is successful it will make the Fluent stuff obsolete. I'd rather stay focused on that rather than support Fluent right now, if that's all right.




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.