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

Program Storage and Execution


  • Please log in to reply
15 replies to this topic

#1 Jeff LaFay

Jeff LaFay

    New Member

  • Members
  • Pip
  • 6 posts

Posted 07 December 2010 - 02:43 PM

Does the netduino (or possibly the netduino plus) allow storage and execution of binaries from an SD card? This is something desirable for microcontroller hobbyists and most controllers don't allow (from what I've seen, I'm not a pro microcontroller developer) that because it appears to add a decent amount of complexity to the controller firmware. While I'm on the subject, can multiple programs execute at once (like a program pool of some type) or can a program spawn an instance of another? I apologize if my questions have been answered in another post. The tutorial is very basic and the .Net compact framework documents are .Net specific; not netduino specific and that's why I ask these questions. Thanks.

#2 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 07 December 2010 - 03:47 PM

The tutorial is very basic and the .Net compact framework documents are .Net specific; not netduino specific and that's why I ask these questions. Thanks.


Please note that you should be referencing documentation on the .NET Micro Framework API and not the .NET Compact Framework API as they are two different things.

#3 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 07 December 2010 - 03:51 PM

Does the netduino (or possibly the netduino plus) allow storage and execution of binaries from an SD card? This is something desirable for microcontroller hobbyists and most controllers don't allow (from what I've seen, I'm not a pro microcontroller developer) that because it appears to add a decent amount of complexity to the controller firmware.


Yes, it is possible to load assemblies (e.g. dll's) from external storage at runtime. You should probably search StackOverflow for solutions to make this work. The way to do this is probably the same for both the .NET Micro Framework and the full .NET Framework.

StackOverflow search results for loading assemblies at runtime in .NET

#4 Fred

Fred

    Advanced Member

  • Members
  • PipPipPip
  • 302 posts
  • LocationUK

Posted 07 December 2010 - 04:00 PM

I've been meaning to get around to looking at this as Chris Walker has said it's possible. With something like a simple FTP server to allow DLLs to be copied to the Netduino Plus SD card it should than be possible to remotely deploy an application. Would this DLL need to be copied over to the device's RAM to run though? That might restrict how useful it would be.

#5 Jeff LaFay

Jeff LaFay

    New Member

  • Members
  • Pip
  • 6 posts

Posted 07 December 2010 - 04:03 PM

Please note that you should be referencing documentation on the .NET Micro Framework API and not the .NET Compact Framework API as they are two different things.


My mistake, thanks for pointing that out.

#6 phantomtypist

phantomtypist

    Advanced Member

  • Members
  • PipPipPip
  • 142 posts
  • LocationNew York, NY

Posted 07 December 2010 - 04:04 PM

While I'm on the subject, can multiple programs execute at once (like a program pool of some type) or can a program spawn an instance of another?


I'm pretty certain you can't run multiple executables on the .NET Micro Framework at the same time. I could be wrong and maybe someone else knows otherwise.

Aside from that, if you want to have a different set of code run while your main code runs you should look into System.Threading. For example, you could have your main code running and then at some point you can have some other code to execute on a different thread while the main code runs its own thread.

Again, you should probably look to StackOverflow for solutions or read the MSDN documentation. If you are completely new to the .NET framework in general, you should probably pick up in introductory book first.

#7 Jeff LaFay

Jeff LaFay

    New Member

  • Members
  • Pip
  • 6 posts

Posted 07 December 2010 - 04:08 PM

Yes, it is possible to load assemblies (e.g. dll's) from external storage at runtime. You should probably search StackOverflow for solutions to make this work. The way to do this is probably the same for both the .NET Micro Framework and the full .NET Framework.

StackOverflow search results for loading assemblies at runtime in .NET


I think it could be beneficial to have a program running in memory that could read a manifest on SD storage that contained metadata on executables on SD. The thing is, could those executables execute from the external storage or would they need to be copied into memory?

Maybe threading could work but it would be nice to have the controller software handle process management for me when I don't have to.

#8 Jeff LaFay

Jeff LaFay

    New Member

  • Members
  • Pip
  • 6 posts

Posted 07 December 2010 - 04:11 PM

I'm pretty certain you can't run multiple executables on the .NET Micro Framework at the same time. I could be wrong and maybe someone else knows otherwise.

Aside from that, if you want to have a different set of code run while your main code runs you should look into System.Threading. For example, you could have your main code running and then at some point you can have some other code to execute on a different thread while the main code runs its own thread.

Again, you should probably look to StackOverflow for solutions or read the MSDN documentation. If you are completely new to the .NET framework in general, you should probably pick up in introductory book first.


I'll check out StackOverflow and see what's going on for Netduino questions there. I'm new to Netduino development as a hobbyist and .Net software engineer by day. That's why I chose the platform for microcontroller development. Thanks for the info needed to whet my appetite and getting me in the right direction.

#9 JonnyBoats

JonnyBoats

    Advanced Member

  • Members
  • PipPipPip
  • 155 posts
  • LocationPhillips, ME

Posted 07 December 2010 - 04:45 PM

For examples of many of these things (loading executibles from SD, multiple programs running at the same time etc) on the .Net micro framework, take a look at Pyxix 2 ( http://www.skewworks...roducts/Pyxis 2 ).

From the website "Pyxis 2 is an open-source operating environment based on NETMF technology."

#10 entens

entens

    Member

  • Members
  • PipPip
  • 10 posts

Posted 07 December 2010 - 05:24 PM

Wow, Pyxis is a goldmine!

The contents of 'AppLoader.cs' is probably what you'll want to use. It essentially grabs a byte array and uses 'System.Reflection' to load it as an executable assembly. This should work, but I see problems with a lack of memory while using the Netduino.


Contents of AppLoader.cs so you don't have to download the Pyxis source:
/*
Copyright 2010 Thomas W. Holtquist

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

using System;
using System.Collections;
using System.IO;
using System.Reflection;
using System.Runtime;

using Microsoft.SPOT;

namespace Skewworks.Pyxis.Kernel
{
    internal static class AppLoader
    {

        /// <summary>
        /// The interface for a standlone application
        /// </summary>
        interface IApplication
        {
            void RunFromBytes(ref ApplicationKey AppKey, ref PyxisAPI APIRef, ref string path, ref string[] parameters);
            AppIcon GetAppIcon(byte[] bytes);
        }

        /// <summary>
        /// A class that can be loaded across applicaiton domains which
        /// implements the IApplicaiton interface
        /// </summary>
        public class Application : MarshalByRefObject, IApplication
        {

            /// <summary>
            /// we need a defautl consturctor to create an instance of this object
            /// across an application domain
            /// </summary>
            public Application()
            {
            }

            public AppIcon GetAppIcon(byte[] bytes)
            {
                // Attempt to execute DLL
                try
                {
                    Assembly asm;
                    MethodInfo[] m;

                    asm = Assembly.Load(bytes);
                    if (asm == null)
                    {
                        return new AppIcon();
                    }

                    Type[] t = asm.GetTypes();
                    for (var j = 0; j < t.Length; j++)
                    {
                        m = t[j].GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
                        for (int i = 0; i < m.Length; i++)
                        {
                            if (m[i].Name == "PyxisIcon")
                            {
                                return (AppIcon)m[i].Invoke(asm, null);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    // Do nothing
                }

                return new AppIcon();
            }

            public void RunFromBytes(ref ApplicationKey AppKey, ref PyxisAPI APIRef, ref string path, ref string[] parameters)
            {
                string[] supporting = Directory.GetFiles(Path.GetDirectoryName(path));

                for (int i = 0; i < supporting.Length; i++)
                {
                    if (supporting[i] != path)
                    {
                        try
                        {
                            Assembly.Load(File.ReadAllBytes(supporting[i]));
                        }
                        catch (Exception)
                        {
                            // move along
                        }
                    }
                }

                RunAppFromBytes(AppKey, APIRef, File.ReadAllBytes(path), parameters);
            }

            private void RunAppFromBytes(ApplicationKey AppKey, PyxisAPI APIRef, byte[] bytes, string[] parameters)
            {

                // Attempt to execute DLL
                try
                {
                    Assembly asm;
                    MethodInfo[] m;

                    asm = Assembly.Load(bytes);
                    if (asm == null)
                    {
                        return;
                    }

                    Type[] t = asm.GetTypes();
                    for (var j = 0; j < t.Length; j++)
                    {
                        m = t[j].GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
                        for (int i = 0; i < m.Length; i++)
                        {
                            if (m[i].Name == "PyxisApp")
                            {
                                AppStartup myStartup = (AppStartup)m[i].Invoke(asm, new object[] { AppKey, APIRef, parameters });
                                APIRef.ActivateApplication(myStartup, AppKey);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    // Do nothing
                    APIRef.Prompt("Failed to launch program.\n" + e.Message, "System Alert", PromptType.OKOnly);
                }

            }

        }

        #region Variables

        private static IApplication iApp = null;
        
        #endregion

        /// <summary>
        /// The executable entry point.
        /// </summary>
        public static void LaunchApplication(PyxisAPI APIRef, string path, string[] parameters)
        {
            int AppID = GetAppID(APIRef);

            // Create the Application
            PyxisApplication PA = new PyxisApplication();
            PA.Forms = new ArrayList();
            PA.Domain = AppDomain.CreateDomain("PyxisApp" + AppID);
            PA.Key = new ApplicationKey(AppID, PA.Domain);
            APIRef._runningApps.Add(PA);

            // create an instance of the IApplication type
            // please note that the following call will also load the assembly that contains that type
            // which we pass as first parameter 
            try
            {
                iApp = (IApplication)PA.Domain.CreateInstanceAndUnwrap(typeof(IApplication).Assembly.FullName, typeof(Application).FullName);

                // Allow system time to catch up
                System.Threading.Thread.Sleep(100);

                // Launch the Program
                iApp.RunFromBytes(ref PA.Key, ref APIRef, ref path, ref parameters);

            }
            catch (Exception e)
            {
                APIRef.Prompt("Failed to launch application!\n" + e.Message + "\n" + e.InnerException.ToString(), "System Alert", PromptType.OKOnly);
                APIRef._runningApps.Remove(PA);
                return;
            }


        }

        public static AppIcon GetApplicationIcon(byte[] bytes)
        {
            AppIcon AI;

            // Create the Domain
            AppDomain ad = AppDomain.CreateDomain("PyxisAppDesktopIcon");

            // create an instance of the IApplication type
            // please note that the following call will also load the assembly that contains that type
            // which we pass as first parameter 
            if (iApp == null)
            {
                try
                {
                    iApp = (IApplication)ad.CreateInstanceAndUnwrap(typeof(IApplication).Assembly.FullName, typeof(Application).FullName);
                }
                catch (Exception e)
                {
                    AppDomain.Unload(ad);
                    return new AppIcon();
                }
            }

            // Get the Icon
            AI = iApp.GetAppIcon(bytes);

            // Destroy Domain
            iApp = null;
            AppDomain.Unload(ad);

            return AI;
        }

        private static int GetAppID(PyxisAPI APIRef)
        {
            bool bConflict = false;
            int AppID = 0;
            int i;
            PyxisApplication PA;

            while (true)
            {
                bConflict = false;
                for (i = 0; i < APIRef._runningApps.Count; i++)
                {
                    PA = (PyxisApplication)APIRef._runningApps[i];
                    if (PA.Domain.FriendlyName == "PyxisApp" + AppID)
                    {
                        bConflict = true;
                        break;
                    }
                }
                if (!bConflict) return AppID;
                AppID++;
            }
        }

    }
}


Unrelated side note: Would it be possible to get a 'spoiler' tag added so you can embed long pieces of code in collapsible block?

#11 AlfredBr

AlfredBr

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationConnecticut, USA

Posted 15 December 2010 - 05:35 PM

You will definitely use some RAM using this technique, but the upside is that you will get that RAM back when you unload the AppDomain. So you could use this approach to "demand load" some code that you need only temporarily, execute the code, and then unload the assembly and reclaim the RAM.

#12 AlfredBr

AlfredBr

    Advanced Member

  • Members
  • PipPipPip
  • 138 posts
  • LocationConnecticut, USA

Posted 16 December 2010 - 02:54 AM

Is CreateInstanceAndUnwrap() implemented in the Netduino? Even the simplest example throws System.NotImplementedException.

#13 Fabien Royer

Fabien Royer

    Advanced Member

  • Members
  • PipPipPip
  • 406 posts
  • LocationRedmond, WA

Posted 24 December 2010 - 10:37 PM

Can someone from Secret Labs please provide a definitive answer on the subject of dynamic assembly loading / execution on the netduino?

#14 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 25 December 2010 - 05:09 AM

Hi Fabien, AppDomains work, but I'm not 100% sure about dynamic appdomain loading. I'll dig into this next week during the holidays and will post back on the forums with my findings. Please note that we'll be pretty short-staffed until January 4th...but I will monitor the boards. Chris

#15 Fabien Royer

Fabien Royer

    Advanced Member

  • Members
  • PipPipPip
  • 406 posts
  • LocationRedmond, WA

Posted 30 December 2010 - 12:00 AM

Just closing the loop: I figured out how to load assemblies dynamically and wrote a post about it on my blog: http://fabienroyer.w...ith-a-netduino/

Cheers,
-Fabien.

#16 Jeff LaFay

Jeff LaFay

    New Member

  • Members
  • Pip
  • 6 posts

Posted 30 December 2010 - 03:08 PM

Just closing the loop: I figured out how to load assemblies dynamically and wrote post about it on my blog: http://fabienroyer.w...ith-a-netduino/


Thanks so much!




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.