2012-04-30

DPWS Client through WCF

In the last post I discussed creation of the host application on the device. In this post I'd like to finish off the example by delving into the client side, on the PC, using WCF. We'll start by creating a new Windows Forms Application. Really, any normal Windows application that supports full .NET Framework would do. But I like the idea of making a GUI based application that can be extended in the future to show the status of, and interact with, our Gadgeteer device.

In the new form, I make two buttons and two labels. The first button will be to manually initiate connection with the device, and the second will be to invoke our example method: getButtonValue. The labels with show the statuses of the two actions.

Next we need to auto-generate code for the client side, in a manner similar to that which we used for the device host. But, this time we need to use a different tool: SvcUtil.exe. Just like the host example, run the utility on the WSDL file. Unlike the MFSvcUtil, this one has a few extra parameters. Ignore most of them. The command to generate the code is:
D:\[...]\WcfDpwsClientExample>svcutil ..\GadgeteerDpwsHostExample\GadgeteerReportingService.wsdl /language:c#
If you followed along with my example code, the utility will generate a warning. It complains that my namespaces don't have a fully formed uri (i.e. http:// prefix). Whatever... We'll make the whole thing work just fine without uri namespaces.

Next we need to create a proper config file to enable the application to connect to the device host. We could do this manually, but there is a wonderful utility to do it for us automatically. I mentioned it in the former blog-post: SvcConfigEditor.exe. Open the auto generated output.config file in this utility. Remember, use the utility from the NETFX 4.0 Tools folder. The file we opened will just serve as a loose guideline. We will pretty much recreate a new file.

First, open the endpoint information in: Client/Endpoints. There should be a single auto-generated port in there. Most likely with a name like: gadgeteerStatusesBinding_GadgeteerStatuses. This is fine, but I will rename mine to gadgeteerStatusesPort. This is the name you give your Client object when initializing it, so it knows which section of the config file to read.

Secondly, go into Bindings section. There should be a single binding in there, with two extensions under it. We need to recreate these two extensions. So go ahead and delete them and then re-add them. The first was textMessageEncoding. Under its properties, ensure that MessageVersion is set to Soap12WSAddressing10. The second extension was httpTransport. Just add it and leave it at default settings.

Now save the file as app.config and add it to your project. The wonderful thing about the utility you just used is the ability to enable logging under Diagnostics section. This will allow you to save logs of all your Soap transactions and then view these logs visually with yet another tool--the name of which currently escapes me, but if you look into MSDN documentation for transaction logging, you will quickly find the name.

Next comes a tricky part. Add the auto-generated code file to your project. In order to stop VS from complaining about types, we'll need to add a reference to System.ServiceModel. There are several changes we need to do in order to communicate successfully with the device host. First and foremost, we need to end up with DataContractSerialization. The way that MFSvcUtil auto-generated its code. But if we tell SvcUtil to give us DataContractSerialization, it will have a mental meltdown and give us useless code. So, let it generate XmlSerialization and we'll have to fix it manually.

Find GadgeteerStatuses interface and replace:
[System.ServiceModel.XmlSerializerFormatAttribute()]
With:
[System.ServiceModel.DataContractFormatAttribute(Style=System.ServiceModel.OperationFormatStyle.Document)]
Then  find ButtonValueType class and add an attribute to it:
[System.Runtime.Serialization.DataContractAttribute( Namespace = "GadgeteerReportingService/gadgeteerStatuses" )]
Inside of the class, locate the Value property and add an attribute to it:
[System.Runtime.Serialization.DataMemberAttribute( Order = 0 )]
For the last two, you'll need to add a reference to System.Runtime.Serialization assembly. While you're at it, add one to System.ServiceModel.Discovery, as you'll need it in the next step.

We are ready to write the actual work code in our form now. I added two members:
Uri serviceAddress;
GadgeteerStatusesClient client;
Then, added a new method (blatantly copied from the .NETMF examples mentioned in my previous post):
bool FindService()
{
    try
    {
        DiscoveryClient discoveryClient =
            new DiscoveryClient( new UdpDiscoveryEndpoint( DiscoveryVersion.WSDiscoveryApril2005 ) );

        Collection services = discoveryClient.Find( new FindCriteria( typeof( GadgeteerStatuses ) ) ).Endpoints;

        discoveryClient.Close();

        if ( services.Count == 0 )
        {
            return false;
        }
        else
        {
            serviceAddress = services[ 0 ].ListenUris[ 0 ];
        }
    }
    catch
    {
        return false;
    }

    return true;
}
Then after adding a handler for the connection button, we give it a body:
private void buttonConnect_Click( object sender, EventArgs e )
{
    labelConnect.Text = "Searching...";

    while ( !FindService() )
    {
        Console.WriteLine( "GadgeteerStatuses service not found.  Trying again..." );
        System.Threading.Thread.Sleep( 1000 );
    }

    // perform WebServices discovery
    client = new GadgeteerStatusesClient( "gadgeteerStatusesPort", serviceAddress.AbsoluteUri );
    labelConnect.Text = "Connected";
}
And finally, after adding a handler for the value fetching button, we fill its body:
private void buttonValue_Click( object sender, EventArgs e )
{
    if ( client == null )
        return;

    try
    {
        ButtonValueType bv = client.getButtonValue( new EmptyValueType() );
        labelValue.Text = bv.Value.ToString();
    }
    catch ( Exception ex )
    {
        System.Diagnostics.Debug.Print( "Web Service call returned exception with message: " + ex.Message );
    }
}

From what I understand, the discovery will search active web services available on the network, for all that implement GadgeteerStatuses interface. Once it finds some, it will assign the first one to our form variable. We will then use the configuration file settings to connect to it and exchange data. If you followed the steps in these two posts, you should be able to connect, and then query the device for the status of the button. If the button is currently not depressed, it should return 0, and if it's depressed, it should return 1.

Have fun with it.

2012-04-26

DPWS Host for Gadgeteer

DPWS stands for Devices Profile for Web Services. When I read up on it, it got me really excited with possibilities of network Plug-n-Play type devices. So, when I decided to test it out, I was really surprised to find very little help with the whole idea. My biggest hurdle was my lack of familiarity with Web Services in general.

I set out to write a simple service host running on the device, exporting a status of a button. The client would be a windows application running on a computer my FEZ Spider is hooked into through an Ethernet cable. In order to help me out, I decided to look into .NETMF samples: SimpleService and SimpleServiceClient. This gave me a starting point to learn about WebServices on the device. Unfortunately, it was quite some time until I learned that a better example of what I was trying to achieve can be found in samples: HelloWorldServer_MF and HelloWorldClient_WCF. So for anybody following my footsteps, those are the samples you want to disect, along with their complimentary host-on-WCF and client-on-MF samples.

To ease creation of the Web Services, we can write a service definition file, or a WSDL file. This file is then fed into existing utilities that auto-generate code necessary for the service operation. Unfortunately, a different tool needs to be used for different .NET Frameworks. A tool used by .NETMF is called MFSvcUtil.exe and is found in the Tools folder of your current .NETMF installation. At the time of this writing, mine was installed in: C:\Program Files (x86)\Microsoft .NET Micro Framework\v4.2\Tools. Regular .NET framework tool is called SvcUtil.exe and can be found in the Windows SDK bin folder. At the time of this writing, mine was installed in: C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1\Bin. Be careful with the latter one. If you have multiple SDKs and/or development tools installed, your path variable may be pointing to a different SDK. In that case, the auto-generated code will potentially point to a wrong version of the framework.

Another tool that may eventually become useful is called SvcConfigEditor.exe. There is one in the same Bin directory as SvcUtil.exe, but I would suggest not using that one. In that Bin directory, there is a subdirectory called "NETFX 4.0 Tools" and within it is a newer, better version of the said tool. I'll get back to that tool when I talk about configuring the client application.

Ok, onto the business at hand. The first thing we need to do is define a WSDL file. I can't get into the specifics of it--it would take too long--but if you search for "WSDL tutorial" or some-such you'll be up and running in no time. One thing to keep in mind is: there are two versions of WSDL definitions. For what we are doing we need to use the older version. The one with <types/>, <message/>, <portType/>, and <binding/> required sections. Another note I picked up somewhere is that you should always define types for your operations. Even if you don't want to pass any data. This, the argument goes, serves as both the place holder if in the future you do wish to pass some data, and as a safety to make sure everything is standardized. Personally I subscribed to the second of these two sentiments. There is so much that can (and did) go wrong with this, that I don't need to wrestle such trivial matters of how do I define a parameterless message and why it doesn't work.

Alright, onto the actual code. To start my example WSDL file, I define a bunch of namespaces in the top level definitions element.
<definitions name=            "gadgeteerStatuses"
             targetNamespace= "GadgeteerReportingService/gadgeteerStatuses"
             xmlns:tns=       "GadgeteerReportingService/gadgeteerStatuses"
             xmlns=           "http://schemas.xmlsoap.org/wsdl/"
             xmlns:soap=      "http://schemas.xmlsoap.org/wsdl/soap12/"
             xmlns:xs=        "http://www.w3.org/2001/XMLSchema"
             xmlns:wsa=       "http://schemas.xmlsoap.org/ws/2004/08/addressing"
             xmlns:wsp=       "http://schemas.xmlsoap.org/ws/2004/09/policy">
Next come the type definitions. This is a normal XML based data schema for each of the data types you wish to communicate. Based upon some of the suggestions I encountered while researching that, it was suggested that all atomic data types like ints and strings be wrapped into complex types. I went with that suggestion, but cannot vouch for its merits. Since I only wish to return a status of a button, I just need a simple int return value. But based on all of the suggestions I covered so far, I have a place-holder type serving as a dummy value for my "parameterless" query. In addition, my button value integer is wrapped into a button value type.
  <types>
    <xs:schema targetNamespace= "GadgeteerReportingService/gadgeteerStatuses">

      <xs:element name="EmptyValue" type="tns:EmptyValueType"/>
      <xs:complexType name="EmptyValueType"/>

      <xs:element name="ButtonValue" type="tns:ButtonValueType"/>
      <xs:complexType name="ButtonValueType">
        <xs:sequence>
          <xs:element minOccurs="1" maxOccurs="1" name="Value"
                      nillable="false" type="xs:int"/>
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </types>
Once the data types are defined, we can define messages that use them.
  <message name="getButtonValueRequest">
    <part name="empty" element="tns:EmptyValue"/>
  </message>

  <message name="getButtonValueResponse">
    <part name="value" element="tns:ButtonValue"/>
  </message>
With the messages, we can use messages to define operations. In our case we have a two way operation, so we need an input and an output message. Operations are a function of a port. Therefore we define a portType, and an associated operation, with the required input and output messages. In addition, we assigned soap actions. To be quite honest, I'm not certain if those actions are necessary, or even used. In all my digging through this material, I haven't been able to figure out where exactly this definition comes into play. If you are reading this, and happen to know the answer, please share it in the comments.
  <portType name="GadgeteerStatuses">

    <operation name="getButtonValue">
      <input wsa:Action="GadgeteerReportingService/gadgeteerStatuses/getButtonValue"
             message="tns:getButtonValueRequest" />
      <output wsa:Action="GadgeteerReportingService/gadgeteerStatuses/getButtonValueResponse"
              message="tns:getButtonValueResponse" />
    </operation>
  </portType>
Once the portType is defined, we need to generate a binding. It's type is the name of the portType you defined above. You define the soap transport here as well as additional details of how messages are going to be passed through this port. In our case, we are trying to pass data as literal, rather than encoded, and as documents rather than RPCs. To be honest with you, I don't think this detail of information is used by the aforementioned tools, but it works, so I'll leave it in as is.
  <binding type="tns:GadgeteerStatuses" name="gadgeteerStatusesBinding">

    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />

    <operation name ="getButtonValue">
      <soap:operation soapAction="GadgeteerReportingService/gadgeteerStatuses/getButtonValue" style="document"/>
      <input>
        <soap:body use="literal"/>
      </input>
      <output>
        <soap:body use="literal"/>
      </output>
    </operation>
  </binding>
Finally, we can define our service information. I am not certain if this section is necessary. This sort of data will be defined in code, once we are setting up our service. I do know it doesn't hurt, so I'll put it here for completeness sake.
  <service name="gadgeteerStatusesService">
    <documentation>Service for querying gadgeteer hardware statuses.</documentation>

    <port name="gadgeteerStatusesPort" binding="tns:gadgeteerStatusesBinding">
      <soap:address location="GadgeteerReportingService/gadgeteerStatuses/"/>
    </port>
  </service>
Don't forget to close off definitions element if you were copy/pasting the above code.

Once the WSDL file is written, you generate the micro framework code by using the MFSvcUtil.exe utility. I opened Windows 7 SDK Command Prompt and executed the utility with only the GadgeteerReportingService.wsdl file as an argument. It auto-generated for me three additional files: GadgeteerReportingService.cs, GadgeteerReportingServiceClientProxy.cs, and GadgeteerReportingServiceHostedService.cs. ClientProxy file is not of interest for this example, so I added the remaining two to the VS project.

GadgeteerReportingService.cs file contains all of our data definitions, as well as the serializers necessary to serialize the complex data types we defined. It also contains all of the data and service contracts necessary for the hosted Web Service (WS). At this point, we hit our first snag. We are lacking some assembly references in our project. In order to be a DPWS host, we need to add references to: MFWsStack, MFDpwsDevice, and MFDpwsExtensions assemblies. In order to deal with XML serialization we need to add: System.XML assembly. If we were to implement client behaviour as well, we would need MFDpwsClient assembly as well.

We are almost done for the host set-up. We have to implement the actual code that will generate our response. We do this by implementing a new class that derives from auto-generated service contract interface IGadgeteerStatuses. It must implement one method as defined in the interface. The method getButtonValue takes a dummy argument and returns the status of a button (0 or 1) wrapped in ButtonValue object. In this particular example, I added a reference to the button in question to this class. This was purely for brevity of this example--in an actual system this would have to be handled much more elegantly.
namespace GadgeteerDpwsHostExample
{
    /// <summary>
    /// Implements Gadgeteer Reporting Service contract interface.
    /// </summary>
    class GadgeteerReportingServiceImplementation : IGadgeteerStatuses
    {
        Button externalButton;

        public Button ExternalButton
        {
            get { return externalButton; }
            set { externalButton = value; }
        }

        /// <summary>
        /// Fetch button value.
        /// </summary>
        /// <param name="req">dummy</param>
        /// <returns>1 if button pressed, 0 otherwise</returns>
        public ButtonValue getButtonValue( EmptyValue req )
        {
            ButtonValue bv = new ButtonValue();
            bv.Value = externalButton.IsPressed ? 1 : 0;

            return bv;
        }
    }
}
In essence those are all the necessary elements required to hook up and start a new service. But, as it turns out, a device host uses one service as a face to the world, while additional services then may be added to its repertoire. To keep things clean and add as much functionality to this example, while still keeping things clean, we'll define a new hosted service to do nothing but serve as a public face. So, we create a new class:
namespace GadgeteerDpwsHostExample
{
    class GadgeteerReportingServiceDeviceHost : DpwsHostedService
    {
        public GadgeteerReportingServiceDeviceHost( ProtocolVersion v )
            : base( v )
        {
            // Add ServiceNamespace. Set ServiceID and ServiceTypeName
            ServiceNamespace = new WsXmlNamespace( "gad", "GadgeteerReportingService/gadgeteerStatuses" );
            ServiceID = "urn:uuid:2CC239A5-78CA-4D5A-A310-FED281330010";
            ServiceTypeName = "GadgeteerDeviceService";
        }

        public GadgeteerReportingServiceDeviceHost()
            : this( new ProtocolVersion10() )
        {
        }
    }
}
If you look closely, you'll see that it is a simple version of the GadgeteerStatuses hosted service auto-generated in the GadgeteerReportingServiceHostedService.cs file. And this brings us to the final step of hosting our service: actually instantiating and started all of the elements. So, in the main Program object, I have the following initialization method:
private void InitializeDpwsStack()
{
    Debug.Print( "Initializing DPWS stack." );

    // Initialize the binding
    string urn = "urn:uuid:2CC239A5-78CA-4D5A-A310-FED281330000";
    ProtocolVersion version = new ProtocolVersion10();
    Device.Initialize( new WS2007HttpBinding( new HttpTransportBindingConfig( urn, 8084 ) ), version );

    // Set device information
    Device.ThisModel.Manufacturer = "Example Corporation";
    Device.ThisModel.ManufacturerUrl = "http://GadgeteerReportingService.org/manufacturer.html";
    Device.ThisModel.ModelName = "GadgeteerReportingService Test Device";
    Device.ThisModel.ModelNumber = "1.0";
    Device.ThisModel.ModelUrl = "http://GadgeteerReportingService.org/model.html";
    Device.ThisModel.PresentationUrl = "http://GadgeteerReportingService.org/device.html";

    Device.ThisDevice.FriendlyName = "Gadgeteer Device";
    Device.ThisDevice.FirmwareVersion = "0.0.0";
    Device.ThisDevice.SerialNumber = "12345678";

    // Add a Host service type
    Device.Host = new GadgeteerReportingServiceDeviceHost();

    // Add Dpws hosted service(s) to the device
    GadgeteerReportingServiceImplementation implementation = new GadgeteerReportingServiceImplementation();
    implementation.ExternalButton = button;
    Device.HostedServices.Add( new GadgeteerReportingService.gadgeteerStatuses.GadgeteerStatuses( implementation ) );

    // Set this device property if you want to ignore this clients request
    Device.IgnoreLocalClientRequest = true;

    Debug.Print( "Start DPWS device service with endpoint address: '" + Device.EndpointAddress + "'" );

    // Start the device
    ServerBindingContext ctx = new ServerBindingContext( version );
    Device.Start( ctx );
}
There is much to do about nothing in the above method. First step is to initialize the binding. We are using a WS2007HttpBinding. Don't ask me why or what alternatives there are. I picked this from an example and got it to work with the client. That's as far as I can justify that particular binding type. We are setting it up to use HTTP with the given urn and a port of 8084. Most of this won't matter for the client because it will all be auto-detected. Just make sure you don't conflict with any other ports you may have running on the device (e.g. web-server). Protocol version is also one of the things that I picked up from an example and got it to work. Not really sure what the difference between 10 and 11 really is.

Next block of code just sets up some human readable information for the hosted service. Once your service is up and running, your device will show up in the Networking tab of your Windows Explorer, and the data you enter here will pop up as Properties of that device. This is relevant if you are delivering production devices to customers, but completely moot for our example.

Next, we assign the world facing service host. Since, for this example, we are only running one meaningful service, we could assign *it* as the device host service, but to keep with what I said before, we'll assign the object we made for this purpose.

Then we add the actual useful service to the device. Before we added the service host object, we gave it a reference to the button we want to report on.

Finally, we ignore local requests since we are not intending to talk to ourselves. And then start the service itself. That's it. Compile. Deploy. And if you set up networking between the computer and the device properly, after a few seconds you should see your device pop up under "Other Devices" settings in the Networking pane.

The easy half of the job is done. I will continue the client talk in the next post.

2012-04-01

Run-time assembly loading from SD card

I always thought .NET reflection was cool. To expose knowledge of types and ability to manipulate code itself at run-time is one of the most amazing tools a code designer can be given. So, when a question was posed on how to use reflection to load different pieces of code from a storage device, at run-time, through an interface, I took it upon myself to figure it out.

In order to achieve the goal, I set up two separate solutions in VS2010. This ensures that the code from one of my solutions can only be distributed by me, by copying it to an SD card.

The main program solution was a Gadgeteer Application. In it, I added an additional Class Library project called CommonInterfaceLibrary. This project had only one file in it, containing only one interface declaration.
namespace CommonInterfaceLibrary
{
    public interface IDataStorage
    {
        string Data { get; }
    }
}
This interface is my "contract" for any types I load from an external assembly.

The bulk of the main application code is contained in the following method.
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;
        }
    }
}
That's it! We load an assembly. Fetch all types from it. For each one, we fetch all the interfaces they implement. Then compare each of those to the interface we previously declared. Once we found an object that implements our interface, we create an instance of it and use it.

The remote solution is also a definition of simplicity. It has a single project in it. The only requirement is that the project reference our CommonInterfaceLibrary class library. You do that by right clicking on References folder, select Add Reference, then Browse to the Debug (or Release) folder of the CommonInterfaceLibrary project. Make sure not to go into 'le' or 'be' folders. Once the reference to the assembly DLL file is created, you can declare the interface type in your remote code. In my test code, I created and implemented an additional interface, to better demonstrate reflection in the application code.
namespace TestLibrary
{
    public interface IConfusingInterface
    {
        int Data { get; }
    }

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

        string IDataStorage.Data { get { return data; } }

        int IConfusingInterface.Data { get { return 5; } }
    }
}
To test it, compile the main application project. Then compile the satellite class library. Copy the .pe file for the library (e.g. TestLibrary.pe) onto an SD card. Plug the SD card into the Gadgeteer SD slot and execute the above method.

If you wish to test the main application's agnosticism towards the loaded assembly, go back into the satellite assembly solution, change the data string to something else (e.g. "bar"). Make sure to change the assembly version number as well. Compile, copy onto and insert the SD card back into Gadgeteer. Execute the above function again. VoilĂ !

The only gotcha that I found, was the assembly version. If you don't change the assembly version, the running instance of the Gadgeteer will somehow cache the old assembly, internally. And even if you go through the process of loading a newly compiled version, it will end up using the old one. The only way you can ensure the new assembly is loaded fresh, is to change its version number. I would love to hear about alternative solutions to this problem (i.e. how to flush an assembly that is no longer used).

2012-03-30

First foray into RLP

Got around to speed testing the RLP code today. The C/C++ code used for testing computes average value for each of the colour channels, then combines them back into a single value.
int AverageColour_c(unsigned char *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
 // total number of pixels pass onto us
 unsigned int arraySize = *(unsigned int*)args[0];

 int i = 0, red = 0, green = 0, blue = 0;
 if( generalArray == 0)
  return -1;
 
 // iterate through colour values
 for(i = 54; i < arraySize;)
 {
  red += generalArray[i++];
  green += generalArray[i++];
  blue += generalArray[i++];
 }

 // extract how many pixels were there in total
 int total = (arraySize - 54) / 3;

 // compute average value for each colour
 red /= total;
 green /= total;
 blue /= total;

 // convert into final Color value
 total = (blue << 16) | (green << 8) | red;

 return total;
}
It assumes that the data passed into it is Gadgeteer.Picture.PictureData byte array. This byte array has colour data starting at the 54th byte location and stores colour data as BGRBGRBGR bytes.

The total running time of the aforementioned RLP call is 214ms. The exact same code, encapsulated in a NETMF function call runs for a total of 16335ms. In other words, approximately 76 times faster. For a very simple piece of code.

The NET side of the code is pretty simple in itself:

RLP.Procedure AverageColour;

// This method is run when the mainboard is powered up or reset.   
void ProgramStarted()
{
    // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
    Debug.Print( "Program Started" );

    InitializeRLP();

    // setup Gadgeteer modules
    button.ButtonReleased += new Button.ButtonEventHandler( button_ButtonReleased );
    camera.PictureCaptured += new Camera.PictureCapturedEventHandler( camera_PictureCaptured );
    camera.DebugPrintEnabled = false;
    camera.CurrentPictureResolution = Camera.PictureResolution.Resolution320x240;
}

void InitializeRLP()
{
    // personal unlock code
    RLP.Unlock( "...", new byte[] { ... } );

    // fetch, load and initialize our RLP
    byte[] elf_file = Resources.GetBytes( Resources.BinaryResources.RLP_test );
    RLP.LoadELF( elf_file );
    RLP.InitializeBSSRegion( elf_file );

    // extract the procedures
    AverageColour = RLP.GetProcedure( elf_file, "AverageColour_c" );

    // dispose of the loaded binary data we no longer need
    elf_file = null;
    Debug.GC( true );
}

void camera_PictureCaptured( Camera sender, GT.Picture picture )
{
    const int pixels = 320 * 240;

    int colour = AverageColour.InvokeEx( picture.PictureData, 54 + pixels * 3 );
    Color average = (Color)colour;
    Debug.Print( "Average colour: Red - " +
                 ColorUtility.GetRValue( average ) +
                 " Green - " +
                 ColorUtility.GetGValue( average ) +
                 " Blue - " +
                 ColorUtility.GetBValue( average ) );
}

void button_ButtonReleased( Button sender, Button.ButtonState state )
{
    camera.TakePicture();
}

2012-03-29

Gadgeteer timing concerns

Since my daily living involves image processing, it tickled my fancy to attempt to run some image processing algorithms on the camera output. Since attaching camera, and displaying its results on the screen are so easy, I was looking for a bit more challenge. My first test was going to involve simple thresholding. With that in mind, I wanted to compute an average colour value for the pixels in the image.

Upon executing my simple, double for-loop code, iterating over 320 colums and 240 rows, I had to wait for--what at the time seemed like--an astonishingly long time. In fact, when I first executed the algorithm, I thought that my board froze.

But it didn't. I was aware, on a theoretical level, that NETMF is a wholly interpreted language (unlike its bigger cousins). But I was not ready for the performance penalty this entailed. Becoming curious about how long it takes to execute some basic operations, I devised some time testing code. The essence of it looks like:

// Simple for loop

start = Microsoft.SPOT.Hardware.Utility.GetMachineTime();
for ( x = 0; x < iterations; x++ )
{
    // emtpy loop
}
data.SimpleForLoop = Microsoft.SPOT.Hardware.Utility.GetMachineTime().Ticks - start.Ticks;
data.SimpleForLoop /= iterations; // get single iteration value in ticks
data.SimpleForLoop /= 10; // get single iteration value in microseconds
accumulator.SimpleForLoop += data.SimpleForLoop;
data.SimpleForLoop = accumulator.SimpleForLoop / additions; // average over multiple runs

This basic empty loop test gave me a baseline for the overhead for all additional testing. Curiously enough, 'iteration' is declared as a 'const int' rather than a variable. As a result the speed of the loop was comparable to hard-coding a constant integer value, whereas a variable added approximately 30-40% extra time. The following table lists the results of the tests, in microseconds (rounded down):

Task Time
Simple for loop: 54
Assignment of const ( y = 5 ): 7
Assignment of var ( y = z ): 11
Multiply constants ( 3 * 5 ): 0
Multiply with var ( 3 * z ): 10
Compare two constants ( 3 > 5 ): 11
Compare with var ( y > 5 ): 41
Compare 2 vars ( y > z ): 45

Now, the interesting thing about these results is, that they are created with a 72MHz processor. That means that a simple empty for-loop iteration takes approximately 4000 cycles. Pretty hefty overhead if you need any sort of time relevant operation, or need to process data in excess of a few hundred elements.

As it turns out, not all is lost! In their infinite wisdom, GHI created a solution aptly named RLP (which stands for Runtime Loadable Procedures). In a nutshell, you can load a pre-compiled native code procedure into memory, at run-time, and execute it from NETMF environment. I'll let the coolness of that sink in for a second.

Generation of these pre-compiled procedures isn't very straight forward, but if you follow the instruction steps as found on GHI's website (there are a few How-To's available), you'll be running in no time. In fact, my next post may just demonstrate some neat image processing as performed on a Gadgeteer FEZ Spider board.

Gadgeteer introduction

I recently learned of existence of Microsoft Gadgeteer initiative. On paper, it sounded very exciting. Having a practical project in mind, I acquired a FEZ Spider Starter Kit from GHI Electronics. After waiting a few weeks for the back-ordered components, the kit arrived without any problems.

After unpacking it, I followed easy instructions on the GHI's support page, after installing VS 2010 Express (at work), and VS 2010 Pro (at home). With minimal guidance, I set up the first project. Plugging in a button and an LED, it took 5-7 mouse clicks and 14 keyboard presses to end up with:

void ProgramStarted()
{
    button.ButtonPressed += new Button.ButtonEventHandler( button_ButtonPressed );
}

void button_ButtonPressed( Button sender, Button.ButtonState state )
{
    led.TurnWhite();
}

F6 to compile. F5 to deploy. 10-20 seconds later, pushing the button turns on the LED! Holy smokes. This is even more amazing stuff than I hoped.