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

Runtime Native Code Interop


  • Please log in to reply
46 replies to this topic

#1 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 12 February 2011 - 09:29 AM

Summary
We're planning to add runtime native code interop to the Netduino firmware. Many of the new features that the community has been asking for will be based off of this new feature (meaning that they only consume codespace if used in your Netduino app).

As a core feature of the Netduino firmware, runtime interop would make it possible to simply add a project or assembly reference to your solution to add features like OneWire, BitBanger, Register, etc. And it will make it easy for community members with C/C++ experience to add really cool, blazingly fast features to the Netduino firmware _without requiring anyone to recompile the Netduino firmware_. And it will make it easier to build things like Quadcopters that need fast real-time routines.

Details
We're going to be cautious in how we add runtime interop. It will come in phases. We're probably going to implement it, learn some things, and tweak the implementation. We'll learn from your feedback. There will be some limitations (described below) in the initial release, but we hope to take these away in future releases...and we hope to work with the .NET MF core tech team to get something integrated into future releases of the .NET MF core which is backwards compatible.

[Community member Corey Kosak and I got together tonight and shared ideas about runtime native code interop for Netduino. Corey--lots of great ideas; thanks for sharing and taking the time to chat!]

At this point, here's the plan. This is tentative, and we'd love your feedback to make this even better.
1. We'll create a managed code project template for runtime native code interop (i.e. a C# wrapper)
2. We'll also create an app which takes the C# wrapper as input and outputs a C++ native code template where you can write your native C/C++ code.
3. The native code will be compiled using GCC (free) or RVDS (efficient) and attached to the managed code project as an embedded resource.
4. The managed code project (with its native code attachment) will be compiled into an assembly which you can add to another project (or you can just add the interop project to an existing solution).
5. Users can then call this managed code wrapper using standard C# calls (including a limited number of parameter types -- byte, int, simple arrays, etc.).
6. Internally we'll basically be loading the parameters into memory and moving the MCU's instruction pointer to the first instruction in the native code. When done, we'll unload the parameters and optional return value from memory and move the instruction pointer back to where we left off in managed code.

There are a few limitations (and possibly others), at least in this first implementation:
1. Native code would essentially live in its own world, unaware of the rich C++ classes provided by .NET MF. For a first cut, there would be no "smart linker" or jump table support.
2. There will be limited support for callback delegates (events).
3. Native code basically "takes over" when run. So badly written native code can technically freeze the .NET CLR and there's no safety checking (either logic or electrical).

Also, we're planning on integrating a few ways for the user to run the native code:
1. C# wrapper: by default, the user will be able to call the native code function from standard C# code.
2. Interrupt-driven: code will be run when selected events (microsecond-resolution timer, pin state change, etc.) occur.
3. FIQ integration: high-priority native code will be run at a higher priority than .NET MF.

Thoughts? Feedback? We're a few weeks away from embarking on this new feature, and we'll welcome any/all open source contributions from the community. Hopefully we're on the right track here. If you disagree, please politely share your ideas.

Exciting times ahead,

Chris
Secret Labs LLC

Edited by Chris Walker, 11 December 2011 - 04:48 PM.
clarified strategy


#2 Nevyn

Nevyn

    Advanced Member

  • Members
  • PipPipPip
  • 1072 posts
  • LocationNorth Yorkshire, UK

Posted 12 February 2011 - 09:50 AM

3. The native code will be compiled using GCC (free) or RVDS (efficient) and attached to the managed code project as an embedded resource.

Sounds like exciting times ahead :D

Any chance you could update the downloads section to give us some pointers to the tools and documentation we'll need in order to take advantage of this feature.

Regards,
Mark

To be or not to be = 0xFF

 

Blogging about Netduino, .NET, STM8S and STM32 and generally waffling on about life

Follow @nevynuk on Twitter


#3 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 12 February 2011 - 09:59 AM

Sounds like exciting times ahead :D

Any chance you could update the downloads section to give us some pointers to the tools and documentation we'll need in order to take advantage of this feature.

Regards,
Mark


Sure, I'll see what we can do. Or maybe we can get the Wiki integrated and build out documentation (and "tips and tricks") with the community.

Chris

#4 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 12 February 2011 - 10:03 AM

BTW, for those familiar with Arduino code... Runtime interop will be much like what happens in the Arduino community today. Many users write Arduino code using the Wiring libraries (an abstraction on top of C) but for more powerful features they call into native C code. In our case, most users will write Netduino code using C# (an interpeted runtime on top of C) but for more powerful features they'll be able to call into native C/C++ code. Obviously C# code is interpreted so there's a much bigger performance hit than Wiring's library/postprocessor system...but hopefully this serves as a good analogy. [Runtime interop is a very technical phrase...but it's a simple premise and should be really easy to use for end users.] Chris

#5 andybareweb

andybareweb

    Member

  • Members
  • PipPip
  • 12 posts

Posted 12 February 2011 - 11:27 AM

Just wanted to add my voice to the excited hubub - this sounds a really good feature and if it's anywhere near as bright as Corey's stuff it'll be awesome. Looking forward to seeing it in action.

#6 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 12 February 2011 - 11:30 AM

Just wanted to add my voice to the excited hubub - this sounds a really good feature and if it's anywhere near as bright as Corey's stuff it'll be awesome.

Looking forward to seeing it in action.


[BTW Thanks for the tweet, Andy.]

One of our goals is to enable Corey's Fluent Interop to run "on top of" runtime interop--so that everyone can play with Fluent without having to use custom firmware. The really cool part...you can create native code on the fly using Corey's Fluent meta-language.

Speaking of on-the-fly, we're going to see if we can support SD-card based assemblies with native code as well. This would require loading the native code into RAM instead of executing it from flash. One can already load assemblies from an SD card using Netduino...so we'd use the same infrastructure.

Chris

#7 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 12 February 2011 - 12:16 PM

I have been following Corey's excellent work from the beginning, I am really excited about it and this native code interop mechanism.

1. Native code would essentially live in its own world, unaware of the rich C++ classes provided by .NET MF. For a first cut, there would be no "smart linker" or jump table support.

What exactly does this mean? If this means native code will not be able to call existing .NET MF functions, then there is a significant problem: resource management. IMHO the code must call .NET MF functions to access system resources, such as I/O ports, timers, communication interfaces etc., to make sure there are no conflicts - while I understand it is very tempting to have for example direct (assembly) access to a GPIO pin, the code definitely must throw "pin not available" exception when it has been used already.

Additionally, what kind of debugging & diagnostics will be available? How do I debug and troubleshoot the native code? On boards where debugging interface such as JTAG is not available, I would need to be able to call at least CLR_Debug::Printf() or HAL xxx_printf() functions, along with pin toggling.

If I understand it correctly, the proposed mechanism is basically an implementation of DllImport attribute that takes a managed assembly ('dllName') and calls an entry point from its resources (?)

#8 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 12 February 2011 - 12:31 PM

Hi CW2,

Thanks for the enthusiasm!

What exactly does this mean? If this means native code will not be able to call existing .NET MF functions, then there is a significant problem: resource management. IMHO the code must call .NET MF functions to access system resources, such as I/O ports, timers, communication interfaces etc., to make sure there are no conflicts - while I understand it is very tempting to have for example direct (assembly) access to a GPIO pin, the code definitely must throw "pin not available" exception when it has been used already.

On resource management, yes this is an issue. You'll be able to reserve resources in the managed code wrapper before it calls your native code. Eventually, we'd like to implement a smart function pointer (linker) feature which lets native code call some/all .NET MF native code functions...I'm pretty sure as a community we can come up with a clever way to do that.

Additionally, what kind of debugging & diagnostics will be available? How do I debug and troubleshoot the native code? On boards where debugging interface such as JTAG is not available, I would need to be able to call at least CLR_Debug::Printf() or HAL xxx_printf() functions, along with pin toggling.

You can still call Debug.Print from the managed side...and perhaps we can create limited function pointer functionality with access to CLR_Debug::Printf on a global basis. You can also use JTAG with an AT91SAM7X-EK board and an AT91SAM7X512 chip if you have the nice ARM tools for that. Pin toggling will be straightforward.

If I understand it correctly, the proposed mechanism is basically an implementation of DllImport attribute that takes a managed assembly ('dllName') and calls an entry point from its resources (?)

Something like that. Let's say you created a OneWire driver :) Your assembly, CW2.OneWire.dll, could have a CW2.OneWire class. That assembly would also have an embedded resource of compiled native code. And the CW2.OneWire wrapper class would call a Netduino "native code reflection" function which would pass your parameter list into the compiled native code, execute the native code, and return an optional return value.

For IRQ/FIQ/continuation-driven native code, a managed code routine could be used for setup/cleanup...but native code would run independently "in the background" until the class was disposed.

Chris

#9 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 12 February 2011 - 12:59 PM

You'll be able to reserve resources in the managed code wrapper before it calls your native code.

Now it is so obvious.

And the CW2.OneWire wrapper class would call a Netduino "native code reflection" function which would pass your parameter list into the compiled native code, execute the native code, and return an optional return value.

Chris, this is exactly what I thought - now excuse me for a while, I have to check something related to calling conventions Posted Image

#10 Mario Vernari

Mario Vernari

    Advanced Member

  • Members
  • PipPipPip
  • 1768 posts
  • LocationVenezia, Italia

Posted 12 February 2011 - 02:28 PM

Happy to read that the argument I've posted shares soooo many people interest! :) So, thanks firstly to Chris, but also thanks to everyone is/will be involved in that feature. Well, I offer my availability to help you in any way (I could do)! I've a strong experience with C#, hardware and assembler, but I literally hate C/C++. So, as far I can help you in whatever way, I'll do. More in general, I and my colleagues are evaluating how reliable could be develop industrial devices based on Netduino-like platform. We need a very very good reliability. A mandatory feature is ability to rescue the MCU control in case of failure remotely (e.g. TCP/IP or serial). Think that most of these devices could serve uninhabited areas, where a simple stupid firmware bug could be *very* expensive! We may help in this way, for example. Thanks again. Mario
Biggest fault of Netduino? It runs by electricity.

#11 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 12 February 2011 - 04:35 PM

Chris, it is really great to see how excited you are about this topic, and it will be a delight to have a feature like this implemented with both the design effort and imprimatur of Secret Labs behind it.

I think the best way to organize a discussion like this is to first settle on what design characteristics a native code interop feature ought to have. Once those characteristics are well-understood, it becomes a lot easier to talk about the pros and cons of any proposed implementation. In the absence of a defined list of characteristics, people tend to talk in circles.

And by the way, I think we have a huge advantage here in that Fluent Interop exists: its existence allows us to establish a lower bound on what is possible on the Netduino (i.e. what we can prove works rather than what we think ought to work). In other words if I did it in Fluent, you should be able to do it too :wub:

So allow me to enumerate some design characteristics:
  • Do you have an easy-to-understand language
  • Do you have IDE support, such as IntelliSense, for that language
  • Can you execute both ARM and Thumb opcodes
  • Can you generate both ARM and Thumb opcodes
  • Can you execute opcodes generated from any tool
  • Can those opcodes be generated offline at build time
  • Can those opcodes be generated online, dynamically at run time
  • Can the interop code touch hardware registers (such as the PIO).
  • In such cases, is the base address baked-in at compile time or determined dynamically at run time
  • Can the interop code call certain external ABI functions to provide basic operations that the CPU does not support natively (e.g. integer division and modulus, any floating point operation)
  • Can the interop code call arbitrary firmware functions (such as HAL_COMPLETION::EnqueueDelta)
  • Can one generate a function with an arbitrary signature in such a way that it is could be called back by the firmware (i.e. not just callable from C#). One such signature is defined by HAL_CALLBACK_FPN
  • Can the interop code call other user-supplied interop functions (so that one could mix-and-match modules from various community contributions and have one a user-defined function from module A call a user-defined function from module B )
  • Can the interop code create data structures of arbitrary size as needed by some firmware functions? (I do not mean full C++ support necessarily, but just enough to give other compiled C++ functions what they need). A good example is HAL_COMPLETION::InitializeForISR. Even though this is a C++ member function, it happens to work properly if it is passed a "this" pointer to a 32-byte region of uninitialized memory. This technique is of pretty general utility as it can be used to call any C++ constructor or destructor as well as member functions)
  • Can the interop code be pinned so that it is suitable for callbacks/interrupts?
  • Can the interop side allocate a fixed-size buffer (suitable e.g. for BitBanger)
  • Is there a way to pin that buffer memory so that it can be accessed at interrupt time (e.g. imagine a long-running interrupt-driven bit banger or some continuously-running PWMish thing operating on a circular buffer)
  • Is there a way for the interop side to allocate a buffer suitable for input (imagine some high-resolution sampling thing triggered by some external event and which quickly stores a few thousand samples in a buffer)
  • Can the interop side and C# side use shared memory for these buffers so there is no need for copying

I am certainly not saying that the answers to all of these need to be "yes". Rather I am trying to provide a conceptual framework for understanding and talking about the specific characteristics of any given approach. (Though of course the above list is highly prejudiced by what I went through when building Fluent)

The nice thing about a list like this is that it allows me to think concretely about various proposals. For example, once your framework can do most of the above, then Fluent becomes pointless and can be terminated. (Interestingly, one key difference is that your proposal answers "no" to question #7, as you intend to generate opcodes offline and then embed them in a .NET resource. This means that, contrary to what was said above, Fluent will likely not run on top of your framework, except as an offline code generator. But if you have gcc plus most of the above, you don't need Fluent. In this scenario the only thing Fluent can do that you can't are certain code optimizations based on information available solely at runtime. But as a practical matter, dynamic code generation in the manner that I'm doing it in the Fluent framework is really too computationally expensive for the Micro Framework anyway)

Then one can establish a set of milestones, which I conceptualize as sandbox programs. Again, this is a prejudiced list, based on what I've built and know I can build for Fluent:
  • Can you turn an LED on and off
  • Can you repeatedly turn an LED on and off with no intervention from the C# side and triggered by a firmware timer
  • Can you do BitBanger synchronously
  • Can you do BitBanger asynchronously
  • Can you do an asynchronous trigger/measure operation like the PING))) demo
  • Can you read in a long stream of samples into a fixed buffer
  • Can you do so asynchronously
  • Can you set up a cooperating pair of processes, one C# and one native; one of which pushes data into a circular buffer and the other of which consumes it
  • Can you fire a C# event
  • Can you have one user-written method call another (as a simple proof of concept my Quicksort demo, which calls a routine to exchange array elements)


#12 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 12 February 2011 - 06:02 PM

A good example is HAL_COMPLETION::InitializeForISR. Even though this is a C++ member function, it happens to work properly if it is passed a "this" pointer to a 32-byte region of uninitialized memory. This technique is of pretty general utility as it can be used to call any C++ constructor or destructor as well as member functions)

This is inherently wrong and in this particular case works only by accident - please don't do that. A nonstatic member function needs a valid 'this' pointer to 1) access member variables and 2) access virtual method table (to call virtual methods).

#13 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 12 February 2011 - 06:18 PM

I did not mean to offer general C++ interop advice to those who do not know precisely what they are doing. The techniques I am talking about below are those that would be implemented by Secret Labs' programmers, not exposed to end-user level on this community. But it's an overstatement to say it works by accident. I did not reveal all of my reasoning but my comment was being made in the context of from one expert to another. In this specific case, HAL_COMPLETION has no constructor, no destructor, all of its fields are plain-old-data, and it has no virtual methods. The MF programmer decided to do all of the initialization in the InitializeForXXX methods. If it makes you more comfortable perhaps point 14 should be written as: Can the interop code create data structures of well-known but arbitrary size so that it can (a) allocate uninitialized memory for them, (b ) call the object's constructor, a la "placement new", (c ) call member functions, and then (d) call the object's destructor. And then in those cases when the system knows that the constructor or destructor do literally no code at all, they can eliminate step (b ) and/or step (d) if they feel like it

#14 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 12 February 2011 - 07:55 PM

But it's an overstatement to say it works by accident. I did not reveal all of my reasoning but my comment was being made in the context of from one expert to another. In this specific case, HAL_COMPLETION has no constructor, no destructor, all of its fields are plain-old-data, and it has no virtual methods. The MF programmer decided to do all of the initialization in the InitializeForXXX methods.

I know what you mean - but those assumptions are really very, very, very specific (and still not complete - you also assume that they apply to all base classes and that there is only so many member variables that they take up to 32 bytes, and that the 'Initialize' function is being called at particular order (i.e. first)). My main concern is that this is not 'pretty general utility' that 'can be used to call __any__ C++ constructor or destructor as well as member functions'; and with the exception of class size none of the above assumptions can be enforced in compile time. On the other hand I understand the circumstances, so if you know precisely what you are doing... Posted Image

#15 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 12 February 2011 - 09:11 PM

Quick answers to a few of the questions:
  • Runtime interop will only execute native code instructions (ARM/Thumb), not generate them. I see the dynamic code generation features of Fluent coming in handy for that :) Most runtime interop code will have been compiled by GCC/RVDS.
  • You'll be able to create variables or buffers in memory in C#...and then read/write to them in native code. We'll have to work out memory pinning arrangements (i.e. garbage collection).
  • Our goal is to copy what .NET MF does for standard native code interop as much as possible.
  • One way or another, we'll get v4.1.1 up on CodePlex/GitHub. For v4.1.2, all the beta code will be online as well.
  • We'll be building this carefully in phases, but with a master plan in mind. During the Alpha phase, things will change a lot...but as we get into beta they should stabilize.
  • Some wishlist interop features are going to have to wait for v4.1.3+, but we should still talk about them now so we design in preparation for them.
  • I'll see what we can do to rush the Wiki so we have a good place to coordinate on implementing runtime interop as a community.

We'll be kicking off development of this feature in a few weeks (final specs following by prototypes, alpha, etc.). So today's conversation will laregly shape that process. Thanks to everyone participating in this conversation!

Chris

#16 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 12 February 2011 - 09:12 PM

I think this particular point is taking the thread off on a tangent, so if you think there is more to talk about on this point, why don't we put it on a separate topic on the bboard. However ultimately I doubt we disagree on the facts. My post was an attempt to establish a bunch of starting points for a conversation. I had never intended to provide universal and thorough instructions applicable to all situations. When I was talking about HAL_COMPLETION, I was talking about a very specific class in a specific version of the Micro Framework whose structure I understand completely. Its size is 32 bytes and that's why I mentioned the number 32. I was not talking about the universe of all possible C++ classes. The "technique of general utility" I referred to is the fact, perhaps not obvious to everyone, that one can in many cases correctly construct and use a C++ object out of an opaque blob of memory without ever needing to know its internal structure. This is useful in scenarios like Fluent Interop where I do not have a C++ compiler to fall back on. The only advice I can say that is of universal applicability is this: "If you're in a context that allows you to use a C++ compiler, then do so. If not, then you'll need to do exactly what the C++ compiler would have done in the same circumstances." It seems a bit obvious but you seem to really want to pin me down on precise statements. If there's more followup to be had, let's do it on a separate topic.

#17 Corey Kosak

Corey Kosak

    Advanced Member

  • Members
  • PipPipPip
  • 276 posts
  • LocationHoboken, NJ

Posted 12 February 2011 - 09:39 PM

You'll be able to create variables or buffers in memory in C#...and then read/write to them in native code. We'll have to work out memory pinning arrangements (i.e. garbage collection).

Regarding memory pinning arrangements, the "fixed" statement worked fine for me and has the advantage that you are doing standard C# with no behind-the-scenes shenanigans. One could also make the code a little safer if one is willing to use lambdas.

e.g. (hypothetical code)

unsafe {
  fixed(var *b=myBuffer) {
    InteropUtil.KickOffSomeInterruptRoutine(myCode, myBuffer);
    Thread.Sleep(30*1000); //run for 30 seconds
    InteropUtil.KillInterruptRoutine(myCode);
  }
}
versus

InteropUtil.FixBufferAndKickOffSomeInterruptRoutine(myCode, myBuffer, () => {
  Thread.Sleep(30*1000); //run for 30 seconds
  //library cleans up at exit
});


#18 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 12 February 2011 - 09:49 PM

I think this particular point is taking the thread off on a tangent, so if you think there is more to talk about on this point, .... However ultimately I doubt we disagree on the facts.

You are right and I don't think it is necessary to dig deeper into this. There are more interesting things to talk about Posted Image

...but you seem to really want to pin me down on precise statements.

I did not mean to sound like that, sorry.

#19 Dan Vanderboom

Dan Vanderboom

    Member

  • Members
  • PipPip
  • 10 posts

Posted 13 February 2011 - 05:03 PM

I don't have nearly the low level expertise compared to some of the commenters here, but I have a few thoughts and some questions regardless. :) Is there a single thread of execution? If more than one were available, it would seem ideal to dedicate one thread to unmanaged/native execution and one to managed code, allowing the native code to run tight, fast loops while pulling messages off a queue coming from the other thread (as opposed to direct method calls that cross context boundaries). With dual core smart phones arriving, is a dual core Netduino being considered? If multiple threads aren't available, would some form of preemptive multitasking to simulate this make sense? And if so, could the developer configure the priority or time sharing divisions based on the needs of the project? For example, in a quadcopter, 80% of the time might be needed for time-sensitive stabilization logic (running native code) and the remaining 20% could handle command processing, waypoint nav, telemetry and data logging (running managed code). What kind of performance gains could be achieved by compiling managed code and deploying the native image (instead of interpreting)? I understand it consumes more storage space for compiled assemblies, but in some cases this might not matter: some programs might be small anyway, and an SD card or other storage device could be used to store larger programs. By making this a configuration option per project, developers would be able to consider the trade-offs and make the right decision based on the needs of individual projects. The bulk of a large program could be interpreted while time critical routines could live in a project configured for native pre-compilation. This arrangement may get 80% of the way there in terms of delivering high performance capabilities without having to solve the many problems and challenges currently being discussed regarding native/managed interop, resource access and coordination, etc. I'm not saying the native code stuff shouldn't be pursued. It should! I'm just saying there may be lower-hanging fruit worth considering.

#20 Dan Vanderboom

Dan Vanderboom

    Member

  • Members
  • PipPip
  • 10 posts

Posted 13 February 2011 - 05:34 PM

What do you folks think about Suspend & Resume functions for garbage collection? In a desktop, web, or phone app this would be pretty crazy, I know, but on a dedicated embedded device, I wonder if this is the right way to go in advanced scenarios. It would be good then to have another function to manually deallocate memory (maybe by passing in a root object in an object graph to reclaim). How many of these decisions are made by the Micro Framework team at Microsoft, and which are open for modification by Secret Labs and the broader development community? Some of the benefits of the managed world come at a high price (as the need for this thread attests). Having GC as an option is great, but in the world of tiny devices and resource constraints, we should probably evaluate the necessity of imposing it on all projects at all times. What could we peel away to get as close to the bare metal without losing the ability to use our favorite languages, tools, and libraries? If we suspend GC and mismanage our objects, we won't crash our work computers or brick our cell phones, so how big of a deal would it be to relax some of these constraints? Besides garbage collection, what kind of overhead is imposed by the Micro Framework? <Opinion> Netduino is a fantastic, exciting platform precisely because it brings .NET to the physical world. We'd be better off adapting NETMF to meet the demands of this low level world than in devising clever but complicated mechanisms to circumvent it, creating high performance NETMF capabilities rather than fragmenting Netduino with a new, non-.NET code base. Once we head down the road that goes around NETMF, there will be less incentive for the NETMF team to make the sort of changes I'm referring to here. </Opinion>




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.