Loading an Assembly with an interface using AppDomain?

Hello guys,
I was wondering if anyone can point me to an example of how to CREATE an Assembly interface and load it into another Project at Runtime…

so far i can create a Separate assembly and load it’s pe image using Assembly.Load();
i can call functions in the assembly and get data returned.

but now i want to define an interface for my Assemblies and use AppDomain to load and unload them at runtime… but i have been unsuccessful.

BTW i have visited the Pyxis 2 Project and source code but it is too tangled together that it doesn’t clearly show how it loads the assembly from File into an AppDomain.

i would really appreciate it if anyone could share a sample of two separate projects where one is the Main Project and the is the assembly that the main would load using AppDomain…

here is what i have so far:


Standard MF Class library: MFClassLibrary1

Class1.cs

using System;
using Microsoft.SPOT;

namespace MFClassLibrary1
{
    [Serializable]
   public class Program : System.MarshalByRefObject, IPlugin
    {
       public static void Main(string test)
        {
            try
            {
                Debug.Print("Hello, World! (Main method)= " + test);
            }
            catch (Exception)
            {

                //throw;
            }

        }

        public string RemoteObject(ref string[] test)//
        {
            try
            {
                Debug.Print("Hello, World! (Assembly method)= " + test[0]);
            }
            catch (Exception)
            {

                //throw;
            }
            // throw new NotImplementedException();

            return "Cooooool= " + test[0];
        }
    }
}

i build the above code and browse to the bin/debug/le folder and copy MFClassLibrary1.pe file to the SDCard… BTW this is the assembly file that you should load and not the DLL… i noticed a lot of people were having trouble loading assemblies because the were using the DLL.

and my Gadgeteer project looks like this:


        void ProgramStarted()
        {
            sdCard.SDCardMounted += new SDCard.SDCardMountedEventHandler(sdCard_SDCardMounted);
  // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
            Debug.Print("Program Started");
}

      void sdCard_SDCardMounted(SDCard sender, GT.StorageDevice SDCard)
        {
            Debug.Print("SD Card Detected");           
            byte[] test = File.ReadAllBytes(@ "\SD\MFClassLibrary1.pe");
            Assembly a = Assembly.Load(test);

                // Attempt to execute DLL
                try
                {
                    MethodInfo[] m;
                    Type[] t = a.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 == "RemoteObject")
                                Debug.Print("************returned from remote= " + (string)m[i].Invoke(asm, new object[] { new string[] { "hey i called RemoteObject and i am a String Array" } }));
                            else
                                Debug.Print("************returned from Main= " + (string)m[i].Invoke(asm, new object[] { "hey i'm calling the main Method and i am a String" }));
                           
                        }
                    }
                }
                catch (Exception)
                {
                    // Do nothing
                }
}

my Questions are:

  1. how would i updated MFClassLibrary1 to use an interface and be able to access that interface in from my Gadgeteer project using Type Safe classes and AppDomain to share Data between the project?
  2. is it possible to register a Callback in the Child Assembly so it can trigger a Method from the Main application? kind of like Events?

thank you.
Jay.

Here’s a walk through for Gadgetos’ (Pyxis 3) app loading, which uses interfaces.

First we have an interface for the launcher and 3 exposed methods

        private interface IApplicationLauncher
        {

            #region Methods

            IApplication RunApp(string Filename);
            AppIcon GetAppIcon(string Filename);
            string RunShell(ref IKernel Kernel, ref string Filename);

            #endregion

        }

Next the launcher itself

        [Serializable]
        private class MyApplication : IApplicationLauncher
        {

            public AppIcon GetAppIcon(string Filename)
            {
                AppIcon AI = new AppIcon();

                // Load Helper Assemblies
                string[] supporting = Directory.GetFiles(Path.GetDirectoryName(Filename));
                for (int i = 0; i < supporting.Length; i++)
                {
                    if (Path.GetExtension(supporting[i]).ToLower() == ".pe" && supporting[i] != Filename)
                    {
                        try
                        {
                            Assembly.Load(File.ReadAllBytes(supporting[i]));
                        }
                        catch (Exception) { }
                    }
                }

                // Load Application
                Assembly asm;

                try
                {
                    asm = Assembly.Load(File.ReadAllBytes(Filename));
                    if (asm == null)
                        return AI;

                    Type[] t = asm.GetTypes();
                    for (int i = 0; i < t.Length; i++)
                    {
                        if (t[i].IsSerializable && t[i].IsClass && t[i].BaseType.FullName == "System.Object")
                        {
                            try
                            {
                                IApplication IA = (IApplication)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(asm.FullName, t[i].FullName);
                                AI.title = IA.Title;
                                AI.icon = IA.Icon;
                                return AI;
                            }
                            catch (Exception) { }
                        }
                    }
                }
                catch (Exception) { }

                return AI;
            }

            public IApplication RunApp(string Filename)
            {
                // Load Helper Assemblies
                string[] supporting = Directory.GetFiles(Path.GetDirectoryName(Filename));
                for (int i = 0; i < supporting.Length; i++)
                {
                    if (Path.GetExtension(supporting[i]).ToLower() == ".pe" && supporting[i] != Filename)
                    {
                        try
                        {
                            Assembly.Load(File.ReadAllBytes(supporting[i]));
                        }
                        catch (Exception) { }
                    }
                }

                // Load Application
                Assembly asm;

                try
                {
                    asm = Assembly.Load(File.ReadAllBytes(Filename));
                    if (asm == null)
                        return null;

                    Type[] t = asm.GetTypes();
                    for (int i = 0; i < t.Length; i++)
                    {
                        if (t[i].IsSerializable && t[i].IsClass && t[i].BaseType.FullName == "System.Object")
                        {
                            try
                            {
                                return (IApplication)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(asm.FullName, t[i].FullName);
                            }
                            catch (Exception) { }
                        }
                    }
                }
                catch (Exception) { }

                return null;
            }

            public string RunShell(ref IKernel Kernel, ref string Filename)
            {
                // Attempt to execute DLL
                Assembly asm;
                MethodInfo[] m;
                string sBuild = string.Empty;
                bool launched = false;

                asm = Assembly.Load(File.ReadAllBytes(Filename));
                if (asm == null)
                    return sBuild;

                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 == "Shell")
                        {
                            m[i].Invoke(asm, new object[] { Kernel });
                            launched = true;
                        }
                        else if (m[i].Name == "BuildID")
                            sBuild = (string)m[i].Invoke(asm, null);
                    }
                }

                return (launched) ? sBuild : string.Empty;
            }

        }

As you can see in RunApp we’re using an interface called IApplication which we convert the loaded assembly to.

That interface looks like this:

    public interface IApplication
    {

        #region Properties

        string ApplicationDirectory
        {
            get;
            set;
        }

        IApplicationKey ApplicationKey
        {
            get;
            set;
        }

        string Company
        {
            get;
        }

        string Copyright
        {
            get;
        }

        byte[] Icon
        {
            get;
        }

        IKernel KernelReference
        {
            get;
            set;
        }

        string[] StartParameters
        {
            get;
            set;
        }

        string Title
        {
            get;
        }

        string Version
        {
            get;
        }

        #endregion

        #region Public Methods

        void Main();
        void QuitRequest();

        #endregion

    }

Interfaces can expose events. So you can have events that you subscribe to or bubble up. Hope that helps.

@ skewworks care to add a wiki page about this please? This is a very frequent question and you are the expert in this area. I ma willing to help.

Sure thing. There is a good bit to know.

Thank you so much Skewworks for shading the light on this and for taking the time to write the code…

now let me see if i got this right:

the code above will all go into the main Application let’s call it the LOADER or Launcher in your case right? so all of the above code will go in one project?

now How would the Assembly we are loading look (let’s call it Plugin for simplicity sake)… could you please add the code for that as well…

i also noticed in your code you have this :


 public string RunShell(ref IKernel Kernel, ref string Filename)
            {
                // Attempt to execute DLL

are we Attempting to load the actual DLL File here or is it the pe image still… i’m confused …

Basically what i’m trying to do is create an Assembly that contains a driver class, that can control a Module on a socket for example (the driver will also be able to control multiple Modules on different sockets )… once i load the driver i need to be able to hold it’s instance and call out its methods all from the same instance… and the reason why i need to keep that instance, is because Gadgeteer doesn’t allow us to release the socket and pins created by a class even if that class dies… so if i loose that instance and try to recreate it again by calling it’s constructor i get pin conflict exception because those pins are still assigned to that first class that i no longer have access to …

The way i think Gadgeteer should have implemented this is instead of throwing an Exception about pin conflict it should return the instance of the class that is controlling those pins. or give us a way to release the socket and pins if the class that created them was disposed of…

i even tried to make my Driver Class a singleton Class, but it threw a Dispatcher exception… saying that this must be load into the Main Dispatcher.

i tried to look over the Gadgeteer code and see if i can get the instance of the class that is holding the socket and pins and return it instead of the exception but didn’t get anywhere, i think the change must be done in the NetMF Core, i might be wrong here…either that or is there a way to do release the socket and pins from NETMF directly? i would prefer to get the class instance that create the socket in the first place… if possible.

Thank you.
Cheers,
Jay.

Jay, once you figure it out maybe you can also help with the wiki page? This is the best way you can say thank to this awesome community.

Of course i would Gus,
You may have noticed in asking my questions i answered some of the issues that i read people having on other posts… and i posted a working sample example just inc case someone wants to load a standard (no interface) assembly (.pe image) and call it’s methods.

Jeeee it’s Sunday already… i guess it’s time to go to sleep :smiley:

Cheers.

The problem is that responses herd get lost over time between thousands of other threads where wiki pages stay there forever :slight_smile:

Let me know guys if I can help.

Hi Guys,
Well after a long night of rest, i got up this morning and decided to give the NETMF SDK a look. and there it was… the Method i was looking for is all there…i;m talking about releasing the PINS after they are reserved… so i decided to do a little test and fair enough it worked GREAT…

a walk through on how it works now and how it will work after the pin release…

Currently the Gadgeteer code Creates and initializes the modules once and assumes that those are never going to change… which works great if you are adding the modules and drivers at Design time, but the challenge comes when you decided to not include those drivers at Design time but rather at runtime through loading the driver image/assembly (pe) File.

when you load the assembly and call a method in the Driver, basically the first time you do that the Driver initializes the code and reserves a Socket and pins required by that driver… it calls your Method and unloads… this works on the first run… now if you decided to load that same assembly and call the same Method or another one, the same cycle will happen the driver will try to initialize the Module and try to reserve the socket and pins again…which trows the Exception about pin conflict (hence they were already reserved by the earlier instance of the loaded class)… which renders the Driver unusable because you can no longer create a class to control it… that was the reason for my hunt for interface implementation… by witch I’m thinking i can create/load the assembly once , and reuse it through out my application (Still have to test this theory and see if it’ll work)… anyway so before jumping into the interface design (Thanks to Skewworks ) for his complete code… i decided to try and give socket code another look and find out how i can bypass the pin conflict exception and i stepped trough the code all the way down to the native calls so i now i know how it all works…

basically every time a module is initialed the Gadgeteer socket reserves the pin used by the Socket and keeps track of thyem using an internal ArrayList “_reservedPins” which it uses to check if the pin was already used and trows the exception when it finds the pin in the collection… now the challenge is to remove the used pins from the list and release it from the Processor…
removing the pin from the list was simple a call to .Remove did the trick which leads to finding a way to remove the pin from the CPU… and searching the docs surely showed the way… the Method is called…

Microsoft.SPOT.Hardware.Port.ReservePin(Cpu.Pin, Bool); 

basically the Port class is the one responsible for reserving the pins and releasing them…

so a call like this would release the pin:


Cpu.Pin cpuPin = (Cpu.Pin) 9; // the pin to release in this case
Port.ReservePin(cpuPin, false); //setting it to false releases the pin :) if set to true reserves the pin.

So now if i Modify the code in the Gadgeteer Core >> socket.cs and update the following:


        /// <summary>
        /// Tells GadgeteerCore that a pin is being used on this socket.  A <see cref="PinConflictException"/> will be thrown if the pin is already reserved.
        /// This is called by Gadgteeer.Interface classes automatically.  Gadgeteer.Modules which do not use a Gadgeteer.Interface helper class in using a pin should call this directly.
        /// Note that Gadgeteer allows mainboard pins to be reused across multiple sockets, so the reservation check also checks if the pin is used on a different socket where the pin is shared.
        /// </summary>
        /// <param name="pin">The socket pin being used</param>
        /// <param name="module">The module using the socket pin (can be null, but if it is not null a more useful error message will be generated).</param>
        /// <returns></returns>
        public Cpu.Pin ReservePin(Socket.Pin pin, Module module)
        {
            PinReservation myReservedPin = null;
            Cpu.Pin cpuPin = CpuPins[(int)pin];
            if (cpuPin == UnspecifiedPin)
            {
                throw new PinMissingException(this, pin);
            }

            if (cpuPin == UnnumberedPin)
            {
                // bypass checks, return no pin
                return Cpu.Pin.GPIO_NONE;
            }

            // Check to see if pin is already reserved
            foreach (PinReservation reservation in _reservedPins)
            {
                if (cpuPin == reservation.CpuPin)
                {
                  [b]  Debug.Print("about to remove the pin");
                    Port.ReservePin(cpuPin, false);
                    myReservedPin = reservation;
                    Debug.Print("pin removed");
                    // throw new PinConflictException(this, pin, module, reservation);[/b]
                }
            }

            // see if this is a display socket and reboot if we need to disable the LCD controller
            if (!(module is Module.DisplayModule) && (SupportsType('R') || SupportsType('G') || SupportsType('B')))
            {
                Module.DisplayModule.LCDControllerPinReuse();
            }
 [b]           if (myReservedPin != null)
            {
                Debug.Print("Remving the myReservedPin");
                _reservedPins.Remove(myReservedPin);
                Debug.Print("myReservedPin removed");
            }[/b]

            _reservedPins.Add(new PinReservation(this, pin, cpuPin, module));
            return cpuPin;
        }

as you can see above when a reserved pin was found instead of trowing the exception, i released the reserved pin from the cpu and removed it from the list and added it again to the list and let the code continue which eventually reserves the pin again… and bang it worked like a charm…

So what is next, now that it works, i will continue to try and find a way this can be done from driver instead of the Modifying the Socket.cs… if i can’t find a way, maybe the Gadgeteer team can update the code to allow us to flag a bool to true if we want to remove and re-reserve the pin again instead of getting an Exception. Or what would be better is to add a dispose method of class that would release the pins when it is dead…

Now i will try to work with Skewworks code and see if i can make this happen with an interface…

Cheers.
Jay

Hi,
@ Skewworks: i can’t get the interface stuff to work for some reason it loads the Assembly fine but when i call a method using an instance i get a null exception… maybe i’m doing this wrong…

Could you please create a very simplified solution that has one Main Application Project and one Plugin Assembly that would show how to load the assembly get an instance and call two or three methods from the assembly, get some data from the loaded plugin and even have an event that would trigger a method in the main application and pass some data … and finally unload the assembly… and dispose of the instance…

thanks…

Jay.

OK after several debugging session i realized what i was doing wrong, and what was not mentioned anywhere on the internet… not sure if these are obvious things but it certainly wasn’t to me…

anyway what i was doing wrong is the way i was sharing the interface between my Main Application and the Plugin/Assembly… basically i was creating the actual interface inside each project, and obviously that made it fall into separate namespace (each projects own namespace) which would cause the Casting to fail when i load the Assembly…so to fix this all i had to do was create a new Project (Class Library ) name myInterface put the interface code in it, Build it and reference it’s dll in each of my projects using Add reference and browsing to the myInterface.dll… now i can load the assembly cast the interface correctly and i call the Methods successfully. ;D

wohooooooooooo…
So yes a WIKI is definitely needed here… because these little thing would drive you nuts…

now next step is finding out how to add delegates and events int the interface and hook to them…

Fun stuff indeed when it works that is…

Cheers.
Jay.

@ JayJay

Great thing you figured it out. I just came here to post a solution for you. :slight_smile:

Here’s the main application code that will create an object from an external assembly, that implements a given interface. The interface is declared in a separate project that both the main application and the satellite assembly reference.

void LoadAndExecuteExternal()
{
    if ( !sdCard.IsCardInserted )
    {
        Debug.Print( "Card not inserted." );
        return;
    }
    if ( !sdCard.IsCardMounted )
    {
        sdCard.MountSDCard();
        if ( !sdCard.IsCardMounted )
        {
            Debug.Print( "Card could not be mounted." );
        }
        return;
    }

    // this is a bit of an assumption here, but it works for the test
    if ( !VolumeInfo.GetVolumes()[ 0 ].IsFormatted )
    {
        Debug.Print( "Card not formated" );
        return;
    }

    // open a file stream to the test assembly. if this were not a test,
    // we could search/load all *.pe files, but the essence of the
    // given code would remain the same
    string rootDirectory = sdCard.GetStorageDevice().RootDirectory;
    FileStream fileStream = new FileStream( rootDirectory + @ "\TestLibrary.pe", FileMode.Open );

    // load the data from the stream
    byte[] data = new byte[ fileStream.Length ];
    fileStream.Read( data, 0, data.Length );

    fileStream.Close();

    // now generate an actual assembly from the loaded data
    System.Reflection.Assembly testAssembly = System.Reflection.Assembly.Load( data );

    // find an object in the loaded assembly that implements
    // our required interface
    CommonInterfaceLibrary.IDataStorage dataStorage = null;
    Type[] availableTypes = testAssembly.GetTypes();
    foreach ( Type type in availableTypes )
    {
        Type[] interfaces = type.GetInterfaces();
        foreach ( Type i in interfaces )
        {
            // not sure if there is a better way of comparing
            // Type to actual CommonInterfaceLibrary.IDataStorage
            if ( i.FullName == typeof( CommonInterfaceLibrary.IDataStorage ).FullName )
            {
                // if we found an object that implements the interface
                // then create an instance of it!
                dataStorage = (CommonInterfaceLibrary.IDataStorage)
                    AppDomain.CurrentDomain.CreateInstanceAndUnwrap(
                        testAssembly.FullName, type.FullName );
                break;
            }
        }

        // if we created an instance
        if ( dataStorage != null )
        {
            // use it!
            Debug.Print( dataStorage.Data );
            break;
        }
    }
}

For the full writeup, please see my new blog post: Mindscape hobtacular: Run-time assembly loading from SD card

Hi MoonDragon,

Thank you very much for your contribution and for the clear writing on the subject, I’m sure it will be very helpful for others…

as far as unloading the assembly all you would have to do is unload the newly created AppDomain… that is the only way to unload the assemblies…

in your code update this:


From :
   // if we found an object that implements the interface
                // then create an instance of it!
                dataStorage = (CommonInterfaceLibrary.IDataStorage)
                    AppDomain.CurrentDomain.CreateInstanceAndUnwrap(
                        testAssembly.FullName, type.FullName );

To:


 if (newlyDomain != null) AppDomain.Unload(newlyDomain);
            newlyDomain = AppDomain.CreateDomain("myNewDomain"); //create  a new domain to load our assembly in.
            dataStorage = (CommonInterfaceLibrary.IDataStorage)
                  newlyDomain.CreateInstanceAndUnwrap(
                      testAssembly.FullName, type.FullName);


//and don't forget to declare : AppDomain newlyDomain = null; somewhere on Top before the loop...
the above code will unload the domain that will in turn unload all assemblies...

now the other task that i still have to figure out is having events in the Satellite assembly that would hook into from the main application and intercept the calls from the satellite in the main… can you help?

thank you.

First, the new appdomain code you posted does not work for me. My application always hangs when trying to do anything meaningful with the new appdomain. I haven’t been able to figure out how to use it at all.

As for the events… that’s easy. Add an event to the interface:

public interface IDataStorage
{
    string Data { get; set; }
    event PropertyChangedEventHandler PropertyChanged;
}

Implement the change in the run-time assembly object:


public class DataStorage : IConfusingInterface, IDataStorage
{
    string data = "bar";

    public event Microsoft.SPOT.PropertyChangedEventHandler PropertyChanged;

    string IDataStorage.Data
    {
        get { return data; }
        set
        {
            string old = data;
            data = value;
            PropertyChanged.Invoke( this, new PropertyChangedEventArgs( "Data", old, data ) );
        }
    }

    int IConfusingInterface.Data { get { return 5; }   }
}

And in the application code, use the new event as you would any other:

        // if we created an instance
        if ( dataStorage != null )
        {
            // use it!
            dataStorage.PropertyChanged += new PropertyChangedEventHandler( dataStorage_PropertyChanged );
            dataStorage.Data = "foo";
            break;
        }
    }
}

void dataStorage_PropertyChanged( object sender, PropertyChangedEventArgs e )
{
    Debug.Print( e.Property + " changed from " + e.OldValue + " to " + e.NewValue );
}

If you loaded the assembly into the main thread, then you don’t even need to worry about the dispatcher in your event handlers. Unless you’re explicitly running things on a different thread, but that goes beyond the scope of this discussion.

@ Jay Jay, @ Skewworks, @ MoonDragon

Thank you very much for your contributions on this subject.

I am developing a home automation application for which I want to include the ability to add “plug-in” drivers at start-up,but I was dreading the hours of research, development, and debugging that I would have to put in in order to get this to work. With your detailed code examples, and excellent explanations, I am now confident that I can do this with little additional effort.

I can’t wait to try this out ;D ;D

Hi jasdev,
Thank you and thanks for all of the members of this community, hopefully by the time this thread is closed we would have completely covered the subject…with examples Solution ready to build on Code share…
That’s exactly what I’m doing… i have created a really nice framework, very extensible and flexible… based on nlayer design. where all layers are separated, Data, business, business entity, and Hardware layer… this would allow me to for example to compile the project and run it on ANY .NETMF board… all i would have to do is create a new project and set few references…

the project was tested on Panda, Spider, Hydra and so far it runs on all three very nicely.

The project is still in it’s infancy, but it’s going great so far… I’ll be interested to learn more about your project…

Cheers,
Jay.

My project is a home automation controller. The goal is to make something similar to the commercial product HomeSeer, but that will run on either a NETMF or a PC platform. I’ve layered the application into multiple sub-projects in VS, with C# interfaces defining interfaces between the various entities.

So far I have defined these logical entities:

Client - provides interface to the user, including web, REST, TCP, etc
Model - provides data storage, and Rule processing logic.
Controller - provides plug-in interface to “device” networks, such as:
- Insteon, ZWave, X10
- Security systems
- Weather and News providers
Device - may represent a physical device such as a light switch or an abstract device such as a “house status”, a timer, etc

The Model has methods for “registering” clients, controllers, and other providers such as the logger, settings storage provider, device collection, time service, etc. Many of these entities are platform specific, but they all implement generic C# interfaces, so the Model does not know or care what platform it is running on. Only the Program.cs file knows which implementation is being registered.

Currently my Clients and Controllers are hardcoded into the Program.cs file, but I would like to add the ability to read the config file at startup time and dynamically load these plug-ins into the app. This would provide the ability for others to develop their own clients or controllers and use them in the application.

My current implementation is being tested on the Cobra. I have an Insteon/PLM driver working. It uses the 2413U USB PLM from Smarthome. When the driver starts up it tests all serial ports on the USB Host for the presence of the PLM device. Once found, it queries the device for it config info. The driver is able to receive and decode event messages from other Insteon devices such as the LampLinc. I can detect the “All-link” message and the followup direct “link cleanup” message from this device when it is switch on and off. This code needs more work to make it robust. I’m trying to figure out the best way to do this. I haven’t decided yet how the various modules will communicate with each other. Each entity is running in their own Thread, and the whole system needs to be asynchronous, so I will probably use bi-directional message queues in a producer-consumer pattern. Any ideas or suggestions would be very welcome.

I have a ton of more programming to go, but I’m really having fun doing it :slight_smile:

I have visions of turning this into a commercial product some day, but that may never happen! In any case, I will release all my initial code to this community when it is at a stage that works.

Please send more details of your project. I know there are several other regulars on this forum that have home automation projects they are working on. I wish this forum had a board dedicated to home automation. It is sometimes hard to find something related to this topic because it is buried deep in posts about other topics.

Is this possible with the default .NET CF functionality (would it work on a Cerberus?) or does it rely on GHI custom libraries?

@ iwritecode - It should be possible. I’m using GHI libraries for:

[ulist]USB Host serial device
Ethernet interface
SD card access
Realtime clock[/ulist]

Hi there,
@ iwritecode : this is standard NETMF function nothing to do with GHI Exclusive Libraries… :slight_smile:
@ jasdev: Thank you for the detailed explanation about your project… It sounds we are on the same exact Path…

Currently My Project is set a bit different, i’m using nLayer Design which is giving the Flexibility to add new Device very easily. and change the underlying access Class without interfering with the code on the Devices…

I’m currently using the Spider, Hydra and panda as my target devices, yes my application does run on the Panda so far… using the panda to set the minimum required hardware…

So far what my Project can do:
It has DataBase Support with Linq, yes you heard it right i can create a simple DB and save it to a file, load it later and run simple queries, like select, insert and delete… it works on Panda as long as your DB is small due to the limited memory on Panda.
the system with will be configurable by Web interface meaning if you want to add a new Module let’s say a music module that would come out on 2013, the end user would only use the admin Web interface to pick the new module from a Web DB and install it, turn off the device plug in the new hardware and restart the system… so no onsite access to the hardware is needed… still in development… but so far so good. i’m trying to come up with a very generic interface that would allow any driver to be used and installed.

the system supports Scheduling, where one can schedule and event for something to happen at a given time for example…turn on the light at 9:00pm on 01/01/2013… you can add as many event as your memory allow…this works on it’s own for now but will be added to support the DB…

i’m very focused on the Software side for now… once i have the software complete i will start looking into integrating different types of hardware interfaces like X10 and so on…

so if you like we can join forces and come up with a great system. contact me directly at jcherrabi at the google mail service .com

Cheers,
Jay.