Chapter 9: Developing with the Emulator


The Extensible Emulator

Emulation is a technique for running a model of your hardware device and application purely in software on a Windows personal computer (PC). Emulation allows you to work within the rich desktop environment throughout your entire development process. At the beginning stages of development, working with the emulator provides an ideal mechanism for rapid prototyping and experimentation, likely far in advance of having physical hardware to work with. The things you discover while working in this mode may actually influence the hardware design. It also allows you to concentrate on the application logic and spend less time on the additional complications of working with hardware. When you do start working with hardware, your emulator can be a useful debugging aid, separating expected behavior from actual behavior.

Note 

Despite its name of Extensible Emulator, this facility is technically a simulator, as we don't emulate the actual CPU. It is safe to say that this is a simulation of your target hardware.

In the code examples we have been through thus far in the book, we have been implicitly using the default .NET Micro Framework emulator. As this chapter will illustrate, the emulator is fully programmable and extensible.

Note 

If you have previous experience with Smart Device development using other Microsoft Windows Embedded and Windows Mobile products, such as Windows Embedded CE, Windows-powered Smartphone, or Windows Mobile powered Pocket PC, you are already aware of the benefits of emulation. However, you should also be aware that things work a little differently when developing for the .NET Micro Framework because you are operating at a much lower level and have much more control over the hardware.

Design of the Extensible Emulator

The Extensible Emulator consists of a set of classes and tools, accessible from within Microsoft Visual Studio, that allow your managed-code application to run on a model of your target hardware.

Figure 9-1 depicts the logical arrangement of the components involved.

image from book
Figure 9-1: Logical structure of the Extensible Emulator.

The Managed Application is your program; the same program you intend to run on physical hardware. There is rarely a need for you to do anything differently in your application to run under the emulator.

The Emulator is a version of the .NET Micro Framework common language runtime (CLR) hosted by Windows and tailored specifically for emulation. The core of the runtime (execution engine, type system, and Garbage Collector) and Framework Libraries are identical to those that will be running on the device. The primary difference is at the low-level hardware abstraction layer (HAL), where instead of the device drivers supplied with your actual hardware, substitute Windows drivers are supplied. We designed the runtime with very clear isolation between layers to ensure that as much of the code as possible would run on both Windows and the device, making for a highly accurate simulation.

Emulator Components are ready-made classes for you to use and extend in developing your custom hardware emulators. This component emulation can take many forms. If the component being emulated is a simple switch, the emulation may provide a form with a button that can be pressed to simulate the switch being closed. If the component being emulated is a more complex device, perhaps a Global Positioning System receiver on a serial port, the simulation may provide a sequence of test data from a file or even connect directly to a real position-data source, which is passed into your program.

The software development kit (SDK) includes a set of commonly used peripheral and interconnect classes for you to directly use in your emulator project (described in the section titled "Built-in Emulator Components" later in this chapter). If these don't suit your needs, you can use them as starting points for developing your own and extend them accordingly, or you may also develop (and share) your own from-scratch emulator components.

More Info 

We have created a special download section for the sharing of emulator components on the companion Web page for this book:

  • http://www.microsoft.com/mspress/companion/9780735623651

The Configuration Engine is the glue that binds all preceding pieces together at run time. The Configuration Engine uses an Extensible Markup Language (XML) description of the hardware model (components), including the various configuration parameters. This description allows the Configuration Engine to initialize the emulator and all emulator components (built-in, extended, or custom) properly at system boot.

Emulating Your Device

Before going into detail on each of the facilities offered by the .NET Micro Framework Extensible Emulator, let us build a simple example to get some working knowledge of the emulator.

We are going to create an emulator for our Flashlight program. We will also create emulations of the input switch and output lamp components so that we can run our Flashlight programs on a PC and test them without any need for real hardware.

Application Development Using Emulation

The first thing we will do is create a workspace for our application development. Then we will add an emulator to the development workspace. Then we can begin to connect emulated components to our emulator. In broad terms, this means that we are going to start by creating a Visual Studio 2005 Solution that contains two projects. One will hold the program that we are creating; the other will hold the emulator that we will use to execute that program on a PC rather than the target hardware. The following sections describe the precise step-by-step sequence.

Creating the Application Project

First, we must create a .NET Micro Framework project. .NET Micro Framework projects can be found in the Micro Framework part of the New Project menu in Visual Studio 2005. If you do not have this section on your system, you must install the .NET Micro Framework SDK. The project you create should be a console application at this stage. Figure 9-2 shows the new project dialogue we will use to create our new workspace. This project will hold the actual software that we will be creating for our target device.

image from book
Figure 9-2: Creating the application project.

We will send the output of this project to either an emulator or a physical device. We can call our project MicroFlashlight, because that is what we are building.

Creating the Emulator Project

Next, we create a .NET Micro Framework Device Emulator project in the same workspace. This will be the emulator that we are going to use. If you have already created your emulator, you do not need to include it in the workspace; you can just select it as a place where your program will execute. However, we will create our first custom emulator.

We find the Device Emulator projects in the Micro Framework part of the New Project menu. We need to give this project a distinctive name because the name of the emulator we are about to create will be shared among all .NET Micro Framework projects on this machine. We can call our project MicroFlashlightEmulator. As soon as we have created this Device Emulator project, we must build it. This places a few values in the Windows registry so that your project can be picked up as a target for the deployment of a .NET Micro Framework project. Figure 9-3 shows the dialog used to create the emulation project.

image from book
Figure 9-3: Creating the emulation project.

This dialog is accessed by right-clicking on the solution in the Solution Explorer and selecting New Project. At this point, we have a workspace that contains two projects.

Now we need to tell our development project that it needs to target our emulator when it is run. To do this, we return to the application .NET Micro Framework project (which we called MicroFlashlight) and open the Project Properties page by right-clicking on the Project in the Solution Explorer and selecting Properties). Now we select the Micro Framework tab on the left of this page. The bottom part of this page gives the deployment options for the project, with a combo box for the device that is to receive the assembly output from your project. Expanding this combo box, we find that one of the entries is the emulator we have just made. Select MicroFlashlightEmulator as the target device.

Note 

Visual Studio does not examine the list of registered emulators every time this page is accessed. So for example, if you were to try this step before you built the emulator for the first time, you'd find that the emulator would not be there. After you build the emulator, this list will not automatically be refreshed. So it may be necessary (only the first time) to unload/reload your .NET Micro Framework application in order to target your new emulator.

image from book
Figure 9-4: Selecting our emulator as the target device.

If we build and run our program, the custom emulator will run it, resulting in an empty form appearing on the screen. This form will then disappear when our program finishes and we stop the emulator.

We now have a custom emulator that receives the output from our project. We can prove this by changing the Text property of the form displayed when creating the emulator. When we run our program, the text on the form will reflect the changed Text property.

Adding Emulated Components

At the moment, the custom emulator is not very useful to us because it does not have any components connected to it. It is analogous to a processor chip on a computer. It can run programs, but it has no connection to the outside world. What we need to do now is connect some components to the emulator.

The emulator's Configuration Engine determines the components connected to a given emulator by reading an XML configuration file.

Warning 

The XML configuration file is a rather advanced feature of the emulator. If you have used pre-RTM versions of the SDK, you know that it used to be necessary. Not anymore. Any new emulator components you wish to add can be done in code. That is not to say that we don't think this is a good feature-it can enable you, for example, to add a logger in a data-driven way without you needing to have access to source code, and to recompile the emulator. If you're just starting out, you can safely skip this section and return to it when you need a deeper understanding of how this works.

The configuration file is called Emulator.config and is held in the emulator project. It is a proper, well-formed XML 1.0 file and must contain a root tag of <Emulator>. This root should, at a minimum, have two children: <Types> and <EmulatorComponents>. The first tag, <Types>, contains one entry for each type of component that your device requires. A type entry consists of a friendly name (for example, MemoryManager) and a fully qualified .NET type specification (for example, Microsoft.SPOT.Emulator.Memory.MemoryManager). The second tag, <EmulatorComponents>, contains at least one entry for each type entry you specified in the <Types> section. These entries are labeled using the friendly name you specified in the <Types> section, must have an ID attribute, and contain (as descendant nodes) configuration information needed by the components, which vary accordingly. (See the section titled "Built-in Emulator Components" for a thorough treatment.)

Note 

There must be one configuration entry per component type, even if the component requires no configuration. If there is no configuration, just create a stand-alone tag using the friendly name (for example, <MyComponent/>).

Following is the properly formatted configuration file we will use, specifying two general-purpose input/output (Gpio) ports: one for the torch button and the other for the lamp output.

 <?xml version="1.0" encoding="utf-8" ?>   <Emulator>     <Types>       <GpioPort>Microsoft.SPOT.Emulator.Gpio.GpioPort</GpioPort>     </Types>   <EmulatorComponents>     <GpioPort >       <Pin>0</Pin>       <ModesExpected>InputPort</ModesExpected>       <ModesAllowed>InputPort</ModesAllowed>     </GpioPort>     <GpioPort >       <Pin>1</Pin>       <ModesExpected>OutputPort</ModesExpected>       <ModesAllowed>OutputPort</ModesAllowed>     </GpioPort>   </EmulatorComponents>   </Emulator> 

Note that we have used two instances of the GpioPort type but configured the components to use different physical resources and have different capabilities. Should we accidentally include two entries with the same name in the Types (for example, specify LcdDisplay twice), we will get a run-time exception thrown from the emulator stating "Error: An item with the same key has already been added."

Note 

The ID attribute is needed only if it is later referenced. In addition to the ID attribute, an EmulatorComponents entry may contain an additional attribute that updates, replaces, or removes (for example, updates="originalId") a previously configured component. This is an advanced configuration technique.

When the emulator starts, the Configuration Engine reads the <Types> section to discover what component emulator types to create. This section may contain either one of the built-in types (for a complete list, see the section titled "Built-in Emulator Components" later in this chapter) or one of your own. For the flashlight, we are using a built-in GpioPort component configured as an input on pin 0 for the button and another GpioPort configured as an output on pin 1 for the lamp control. The <EmulatorComponents> section of the configuration file describes the configuration of these items.

Note 

Because we specified these ports as inputs or outputs, the emulator will throw an ArgumentException if the .NET Micro Framework application attempts to use them incorrectly (for example, it tries to configure pin 0 as an output). There is a third port option, InputOutputPort, which allows a port to be configured as input or output.

For each component in the <EmulatorComponents> section, the emulator will create an instance of the component configured as specified. The emulator maintains a list of the components that it has created according to the configuration file, and provides a means to locate a particular component instance. What we now require is some code that will provide us with a user interface to send values to the button GpioPort and respond to changes in the state of the lamp GpioPort.

Creating an Emulator User Interface

The emulator user interface for our flashlight will use a check box to simulate the input button and a display area to show the state of the lamp. Figure 9-5 shows the flashlight user interface.

image from book
Figure 9-5: The flashlight user interface.

When the button is pressed (that is, the Flashlight Button check box is checked), the value on input pin Gpio 0 must be set to true. When the output of the pin Gpio 1 is set to true, the color of the lamp panel must be set to yellow.

The FlashlightForm class produces the user interface for the flashlight. It calls a method in the parent emulator when the user changes the state of the flashlight check box. It also provides a method to update the lamp display.

 public partial class FlashlightForm : Form {    private FlashlightEmul parent;    public FlashlightForm(FlashlightEmul inParent)    {       parent = inParent;       InitializeComponent();    }    private void buttonCheckBox_CheckedChanged(object sender, EventArgs e)    {       parent.SetButtonState(buttonCheckBox.Checked);    }    public void SetLampState(bool state)    {       if (state)       {          lampPanel.BackColor = Color.Yellow;       }       else       {          lampPanel.BackColor = Color.Gray;       }    } } 

The previous code shows how the FlashlightForm works. When an instance of the form is constructed, it receives a reference to the emulator that is its parent. It stores this in a member variable so that it can inform the emulator of changes to the input. The code calls the method SetLampState to set the state of the lamp panel. A change in the state of the FlashlightButton check box causes a call to the SetButtonState method in the parent emulator, which will update the state of the pin.

Binding a User Interface to the Emulator

Now that we have our user interface form, we need to connect it to the emulated components inside the emulator. We can do this during the initialization of the emulator class.

When an emulator is starting up, several methods are called to handle configuration and make it ready for use. We discuss the sequence of method calls in the following paragraphs.

The first method called has the signature Configure(System.Xml.XmlReader reader)and is responsible for performing configuration using the XML file. We do not need to do anything with this method at this point, although you could override it if you wanted to create a specialized emulator with additional configuration behavior. The Configure method is also useful if we create some custom components of our own, and we would like access to the XML stream to allow elements in it to configure them.

Once configuration is complete, the method SetupComponent() is called by the emulator to set up this emulator component.

 private FlashlightForm form; public override void SetupComponent() {    form = new FlashlightForm(this);    base.SetupComponent(); } 

The previous code shows how our emulator uses the SetupComponent method. It creates an instance of the FlashlightForm and sets the member variable form to refer to it.

Once this method is complete, all components connected to the emulator have been set up and are ready for use; now the emulator can bind the form behaviors to these components and display the user interface form.

The method InitializeComponent() is where a component initializes itself. It displays the form and binds the port components to it.

 private GpioPort lampPort; private GpioPort buttonPort; public override void InitializeComponent() {    base.InitializeComponent();    // Start the UI in its own thread.    Thread uiThread = new Thread(StartForm);    uiThread.Start();    buttonPort = this.FindComponentById("Push_Button") as GpioPort;    lampPort = this.FindComponentById("Lamp") as GpioPort;    lampPort.OnGpioActivity += new GpioActivity(lampPort_OnGpioActivity); } 

The previous code shows the entire InitalizeComponent method for our application. It displays the user interface form first.

Note 

The method FindComponentById was used because all of our configuration was done through the XML file. However, because you are creating the entire emulator, this is probably overkill. You could, if you want, create the lampPort GPIO pin in code and not have to find it by ID and so on.

StartForm is a method that we call on a separate thread to display the form we have already created.

 [STAThread] private void StartForm() {    // Some initial setup for the WinForm UI    Application.EnableVisualStyles();    Application.SetCompatibleTextRenderingDefault(false);    // Start the WinForm UI. Run() returns when the form is closed.    Application.Run(form);    // When the user closes the WinForm UI, stop the emulator.    Stop(); } 

Once the program has displayed the form, the next initialization task is to set the buttonPort value to refer to the Push_Button GpioPort specified in the XML configuration file.

 buttonPort = this.FindComponentById("Push_Button") as GpioPort; 

Note that the program uses the ID of the component, as given in the XML, to locate the comsponent in the emulator. Finally, the program locates the lampPort by name in the same way.

 lampPort = this.FindComponentById("Lamp") as GpioPort; 

The program running in the emulator will use this port to control the state of the flashlight lamp. This means that our display has to have a mechanism by which it can be told when the Flashlight program turns the lamp on or off. The GpioPort class provides a delegate called OnGpioActivity to deliver these messages. We need to bind a method to this delegate so that a method is called when the port changes state.

 lampPort.OnGpioActivity += new GpioActivity(lampPort_OnGpioActivity); 

In the case of the lamp port, we want to update our form display when the state of the port controlling it changes. The method to do this has the following form:

 delegate void SetLampStateDelegate(bool edge); void lampPort_OnGpioActivity(GpioPort sender, bool edge) {    form.BeginInvoke(new SetLampStateDelegate(form.SetLampState), edge); } 

The method receives a reference to the port that originated the state change and also the value of the transition, and the method then passes the transition value into a call of SetLampState on our form, to cause it to update to reflect the new state. This logic is complicated slightly by having two different threading contexts: one for the emulator and one for the WinForms application. In order to safely communicate between the two threads, calls must be marshaled. To accomplish this, a delegate is declared above the method. When the method executes, it calls the SetLampState method on the form on the UI thread of the form.

The final link in the chain is the method that sets the state of the buttonPort when the user changes the state of the button check box in the form. The program calls the method SetButtonState in the emulator when the user does this.

 private void buttonCheckBox_CheckedChanged(object sender, EventArgs e) {    parent.SetButtonState(buttonCheckBox.Checked); } 

SetButtonState receives the value of the check box. The program sets the parent reference, which refers to the emulator in use, when constructing the form.

 delegate void PortWriteDelegate(bool fState); public void SetButtonState(bool state) {    this.BeginInvoke(new PortWriteDelegate(buttonPort.Write), state); } 

This method takes the supplied state and fires off a delegate to perform the write action on the GpioPort (buttonPort). Note that we used the same cross-thread method invocation mechanism that we used with SetLampState. If the input port on the device has been configured as an interrupt port, the effect of this write may be to cause an interrupt handler to run on the device.

Creating a Test Program

The very last thing we need to do is create, in the target device, a test program that will make use of our emulator and the components connected to it.

 public static void Main() {    Cpu.Pin buttonPin = Cpu.Pin.GPIO_Pin0;    InputPort buttonInputPort =    new InputPort(buttonPin, true, Port.ResistorMode.PullDown);    Cpu.Pin lampPin = Cpu.Pin.GPIO_Pin1;    OutputPort lampOutputPort = new OutputPort(lampPin, true);    // NOTE: We are polling here and wouldn't normally do this;    // if this were actual device code, we'd use an InterruptPort    while (true)    {       lampOutputPort.Write(buttonInputPort.Read());    } } 

When this program is running, we can turn the lamp on and off using the check box on the user interface form.

The configuration of the various options and the linkage between the component parts is a rather complex business, but it does give you a great amount of control. We provide a complete implementation of the preceding system as one of the sample projects found on the companion Web page.

Using Other Built-in Components

The previous example only uses the GpioPort component. The .NET Micro Framework supplies a full range of components, including devices such as liquid crystal displays (LCDs), serial ports, and Inter-Integrated Circuit (I2C) bus drivers. You can use these components in exactly the same way: request and configure them in the XML file, initialize and bind them in the emulator, and then drive them from appropriate user interface components.

Creating Your Own Components

The previous example used the built-in emulator components, but it is also possible to create your own components that can emulate specialized hardware. A project that contains the program file for the device emulation in question will implement each component. You create a custom component of your own by extending one of the existing component classes, for example, the GpioPort class, or by extending EmulatorComponent, which is the base class of all the components.

Square-Wave Signal Generator

As an example, we will develop a custom component that generates a square wave at a particular frequency. Rather than operating under the control of a user, this component will simply toggle an input pin up and down at a particular rate. We could use this as a "watchdog" source (a commonly used mechanism for detecting system hangs) to provide a heartbeat to our device or as a clock signal.

Note 

This example is intended to illustrate the key concepts involved in developing your own custom component, which is likely to be much more sophisticated than this trivial example. The functionality of the Square-Wave Generator could be implemented much more simply by just manipulating a GPIO pin.

We will create the component based on the GpioPort component. It is important to remember that the component will run on the PC host, not as part of the embedded program. From the point of view of the embedded program, the component will appear to be an input pin that changes state at a particular rate.

Creating the Component Project

We will package the component that we create as an assembly file containing the compiled class that implements the component behavior. We will make an entry in the emulator XML configuration file to represent this new component and must then make sure that the emulator can load the assembly.

The component itself will be a .NET Micro Framework Class Library output from a Visual Studio 2005 project. It will not be an executable file; instead, we will add it as a library to the emulator. We can call the project GpioSquareWave. Figure 9-6 shows our new project.

image from book
Figure 9-6: Creating the new component project.

Once we have our project, we need to add a reference to the .NET Micro Framework Emulator libraries so that we can obtain the component that we want to extend. The required dynamic-link library (DLL) file is held in the Tools directory of the .NET Micro Framework installation. On the author's system, the files are held here:

 C:\Program Files\Microsoft .NET Micro Framework\v2.0.2749\Tools 

The directory that you use might be different, depending on where you have placed the framework and the precise version of the .NET Micro Framework installed on your machine.

Figure 9-7 shows the references for the project, with the emulator added. Note that we also added the Windows Forms libraries so that we can create windows for diagnostic displays and user input, if any.

image from book
Figure 9-7: Adding the emulator reference.

Now that we have the libraries available, we can create the basis of our new component.

 using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using Microsoft.SPOT.Emulator; using Microsoft.SPOT.Emulator.Gpio; using Microsoft.SPOT.Hardware; namespace GpioSquareWave {    public class GpioSquareWaveComponent : GpioPort    {    } } 

We place the component in the namespace GpioSquareWave. The component class is called GpioSquareWaveComponent, and it extends the GpioPort. At the moment, the custom component doesn't do anything; later we must override the behavior methods to make it do what we want.

Making the Component Available to the Emulator

As you have already seen, the <Types> section of the XML file, which configures the emulator, allows us to specify each of the assemblies that the emulator loads.

 <Types> <LcdDisplay>Microsoft.SPOT.Emulator.Lcd.LcdDisplay</LcdDisplay> <SquareWave>GpioSquareWave.GpioSquareWaveComponent, GpioSquareWave </SquareWave> </Types> 

This XML configures the emulator to use the built-in LCD panel component and our Square-Wave component. Note that this does not actually create any instances of these components; it just establishes the range of components from which the <EmulatorComponents> section can draw.

The full syntax for each entry is:

 <Name>Assembly-qualified name</Name> 

Where Assembly-qualified name conforms to the standard .NET definition found for Type.AssemblyQualifiedName. The most common forms of this we are likely to encounter are either <Name>Namespace.Type</Name> or <Name>Namespace.Type, Assembly</Name>. We use the first form when the default (internal) assembly (Microsoft.SPOT.Emulator.dll) contains the type we are referencing. We use the second form when the type resides within a different (external) assembly.

External assemblies specified in the <Types> section must be accessible to the emulator's Configuration Engine at runtime. Because the emulator uses the standard .NET method of Type.GetType for locating, loading, and returning type information for the custom types we specify, the physical location of our assembly must follow the standard .NET loading rules.

We can locate the assembly in the same folder as the emulator executable. We do this by modifying the component project to direct the build output to the same directory as the output from our emulator project, that is, by configuring the Output Path of the Build tab in the Project Properties of our component project.

The settings in Figure 9-8 show the project build properties for the GpioSquareWave project. We set the output path for this project to the same directory as the MicroFlashlightEmulator project.

image from book
Figure 9-8: Placing the component output in the emulator directory.

Alternatively, the assembly can be registered with the Global Assembly Cache using Gacutil.exe. This would make it available to all other projects and would be useful if you wanted to make a given component widely available.

Registering your assembly in the GAC requires that it have a strong name. This involves using the strong name utility (sn.exe) to generate a public/private key pair and signing the assembly using attributes (or one of the other methods), such as:

 [assembly:AssemblyKeyFileAttribute(@"keys.snk")] 

Note that this method requires you to specify the fully qualified assembly name in the configuration file, such as:

 <MyTypeName>MyNamespace.MyType, MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9ac465c7ee16c2e6, processorArchitecture=MSIL</MyTypeName> 

More Info 

For more information about strong names and the GAC, please refer to MSDN.

In general, it is usually easiest simply to specify the emulator directory as the emulator components' Output Path in the Project Build Properties.

There are several differences when compiling for Debug versus Release mode. The output from Visual Studio and the C# compiler for both is Microsoft intermediate language (MSIL), which the .NET Micro Framework then post-processes before executing it. In Release mode, a few optimizations are made, such as dead code removal and removing any Debug.Print calls.

If the Configuration Engine is unable to locate your custom assembly, custom type, or type in the default assembly, you will get a runtime exception, thrown from the emulator, of the form "Error: Cannot resolve type type name."

Configuring a Custom Component

We have seen how the <EmulatorComponents> section of the configuration file controls the creation of an instance of a component. In the case of the square-wave component, we will need to provide information that the component instance can read to configure itself. The required information is the pin number and the interval between state changes of the square wave.

 <SquareWave >    <Width>1000</Width>    <Pin>2</Pin> </SquareWave> 

This XML shows the configuration information for our SquareWave pin. The Width element sets the interval in milliseconds between state transitions, and the Pin element identifies the pin number. In the previous example, pin 2 will change state every second.

A component configures itself according to the XML placed in the emulator configuration file. The Configure method in the component obtains the configuration information from an XML stream.

 private int width; public override void Configure(System.Xml.XmlReader reader) {    XmlDataDocument d = new XmlDataDocument();    d.Load(reader);    this.Pin = (Cpu.Pin) int.Parse(d.FirstChild["Pin"].FirstChild.Value);    width = int.Parse(d.FirstChild["Width"].FirstChild.Value);    this.ModesAllowed = GpioPortMode.InputPort;    this.ModesExpected = GpioPortMode.InputPort;    MessageBox.Show ("GpioPin " + this.Pin + "Width " + width); } 

This method overrides the Configure method of the parent GpioPin class. It creates an XML document from the supplied reader and extracts the pin and width information. It also configures the pin as an input-only port.

Note 

The preceding method has no error handling and will throw an exception if an XML node is missing or has an invalid format. When creating your own components, you should ensure that the code displays an appropriate message if the configuration information is invalid.

Setting Up the Custom Component

Once the emulator has identified and configured all custom components, it makes a second pass through the components and calls their Setup methods. The components can use this method call to create and configure their user interface items. In the case of our square-wave component, there is no need for a user interface, so there is no need for us to provide a version of this method, or we can provide one that simply calls the base method:

 public override void SetupComponent() {    base.SetupComponent(); } 

The setup phase is useful if a number of component emulators need to interact. It ensures that every component has been set up before it is initialized (the final pass) for use by the emulator.

Initializing the Custom Component

Once all the components have been set up, they are then all initialized.

 public override void InitializeComponent() {    base.InitializeComponent();    Microsoft.SPOT.Emulator.Time.TimingServices.Timer waveTimer =       new Microsoft.SPOT.Emulator.Time.TimingServices.Timer(       this.Emulator, new TimerCallback(Transition), null, width, width); } 

The method performs the initialization of our SquareWave component. It creates a timer that will run at the required rate and call the Transition method for us.

Note 

The .NET Micro Framework provides its own timing services, which you should use in preference to the Windows timers. This timer does two things. First, it calls you back in the correct thread context, that is, on the CLR thread, where it is safe to access any of the emulator's object model. Second, it accounts for debugging the MF application. While debugging an application, if the device is stopped, time is stopped as well, so this can be (hopefully) helpful while debugging (for example, you don't queue up a thousand interrupts for MF while stopped at a breakpoint).

The Transition method simply inverts the state and then writes the new value to the GpioPort.

 bool state = false; private void Transition (object o) {    state = !state;    this.Write(state); } 

A .NET Micro Framework program reading from Gpio pin 2 (which is the one we have connected our square wave to) would notice that it changed state every second.

Note 

You could create further square-wave inputs, running at different speeds and connected to different Gpio pins, by adding more <SquareWave> elements to the emulator configuration file. Of course, this means creating unique IDs for each of them.

In this way, you can create software emulations of components and then configure and connect them to programs running in the emulator.

Built-in Emulator Components

A variety of ready-made components, chosen to provide a basic foundation that the majority of embedded devices will likely be built upon, are available for use in your emulator applications. (See the section titled "Emulator Namespaces" later in this chapter for a cross-referenced list of types used here.) This section is intended purely as a reference for you to come back to when creating your custom XML configurations.

Note 

Several of these entries are considered advanced, such as Memory Manager, and will be useful only if you are creating a device with a custom memory layout (most development kits will have a predefined memory layout). Use caution when editing your XML configuration files.

MemoryManager

All devices possess some form of memory, often several different types. This section defines the types of memory and their layouts.

  • Type Microsoft.SPOT.Emulator.Memory.MemoryManager

  • Configuration The memory manager has a complex configuration in that it is a container-it consists of other configurable components, such as random access memory (RAM) and flash. Being a container also affects the configuration entries for those components because they must explicitly specify the types they refer to in an attribute. The following example illustrates this relationship:

     <MemoryManager >    <RamManager type="RamManager" >       <Size format="HexNumber">1000000</Size>    </RamManager>    <FlashManager type="FlashManager" >      <Size format="HexNumber">32000</Size>       <FlashSectors>        <FlashSector>         <Length format="HexNumber">1000</Length>         <Usage>Bootstrap</Usage>         <Partition>Start</Partition>         <Block>Start</Block>        </FlashSector>        ... 

    Note how the example nests <RamManager > within <MemoryManager > and that Ram-Manager and FlashManager both specify the type attribute (which refers to the Types section of the configuration file).

RamManager

RamManager contains the driver name and configuration for managing RAM.

  • Type Microsoft.SPOT.Emulator.Memory.RamManager

  • Configuration Size: a value specifying the size, in bytes, of the RAM.

  • Notes You may specify sizes in hexadecimal notation by using the format attribute, for example, <Size format="HexNumber">1000000</Size>.

FlashManager

FlashManager contains the driver name and configuration for managing flash memory. Flash memory is divided into sectors, partitions, and blocks. Each block has a designated usage. (A full description of flash memory technology is beyond the scope of this chapter.) The emulator uses the following configuration information to configure flash memory for your device by specifying the ranges and usage of these concepts.

  • Type Microsoft.SPOT.Emulator.Memory.FlashManager

  • Configuration The FlashManager section is a container (of FlashSector entries) but also has a configuration item.

    The Size element, as with RamManager, describes the overall size, in bytes, of the flash memory.

  • Example

     <FlashManager type="FlashManager" >   <Size format="HexNumber">32000</Size>     <FlashSectors> 

FlashSectors

FlashSectors contains a list of FlashSector entries describing the layout and usage of the flash memory.

FlashSector

Each FlashSector entry contains the configuration for a sector of flash memory, that is, it defines a span of memory (specified by the Length element) for the containing FlashManager entry. The sector definitions must be consecutive and must cover the entire flash memory.

  • Type Microsoft.SPOT.Emulator.Memory.FlashSector

  • Configuration Length: the length, in bytes, of this span of flash memory.

    Usage: An enumerated type that determines the use of this sector. The driver uses this for policy enforcement and optimization. Permitted values are: Application, Bootstrap, Code, Config, Log, Deployment, StorageA,StorageB.

    Partition: An enumerated value that determines how to treat the current partition. Permitted values are:

    • None: The entry applies to the current partition.

    • Start: The entry defines the start of a new partition.

    • End: The entry defines the end of the current partition.

    • StartEnd: The entry defines an entire partition.

    Block: An enumerated value that determines how this entry relates to the current block. Permitted values are:

    • None: The entry applies to the current block.

    • Start: The entry defines the start of a new block.

    • End: The entry defines the end of the current block.

    • StartEnd: The entry defines an entire block.

  • Notes The first sector defined for your flash memory must have both Partition and Block set to Start (or StartEnd, if it is the only definition).

    The last sector defined for your flash memory must have both Partition and Block set to End (or StartEnd, if it is the only definition).

    An End must not occur before a Start, and a Start must be paired with an End (before a new Start). These are all fairly obvious rules, and the system will validate these entries and generate exceptions if you violate the rules.

    Sector usage types must be consecutive, for example, it is not possible to mix spans of Code with spans of StorageA. The only exception to this rule is Log, which can appear in multiple (discontinuous) locations.

  • Example

      <FlashSector> <Length format="HexNumber">1000</Length>   <Usage>Log</Usage>   <Partition>None</Partition>   <Block>None</Block> </FlashSector> 

GpioCollection

GpioCollection specifies and configures the object used to manage groups of Gpio ports.

  • Type Microsoft.SPOT.Emulator.Gpio.GpioCollection

GpioPort

GpioPort specifies and configures the object used to manage a Gpio port.

  • Type Microsoft.SPOT.Emulator.Gpio.GpioPort

  • Configuration Pin: A number from zero through the central processing unit-defined maximum.

ModesExpected: InputPort, OutputPort, InputOutputPort

ModesAllowed: Same as ModesExpected

  • Notes ModesAllowed must include the values specified for ModesExpected.

  • Example

     <GpioPort>Microsoft.SPOT.Emulator.Gpio.GpioPort</GpioPort> <GpioPort >    <Pin>1</Pin>    <ModesExpected>InputOutputPort</ModesExpected>    <ModesAllowed>InputOutputPort</ModesAllowed> </GpioPort> 

LcdDisplay

LcdDisplay specifies and configures the object used to manage the LCD.

  • Type Microsoft.SPOT.Emulator.LCD.LcdDisplay.

  • Configuration Width: Width, in pixels, of the display.

    Height: Height, in pixels, of the display.

    BitsPerPixel: Color depth of display; permitted values are 1, 4, 8, and 16.

  • Example

     <LcdDisplay>Microsoft.SPOT.Emulator.Lcd.LcdDisplay</LcdDisplay> <LcdDisplay >    <Width>320</Width>    <Height>240</Height>    <BitsPerPixel>16</BitsPerPixel> </LcdDisplay> 

ComPort

ComPort contains the driver name and configuration for the serial port manager object.

  • Types Microsoft.SPOT.Emulator.Com.ComPortToMemoryStream

     Microsoft.SPOT.Emulator.Com.ComPortToNamedPipe 

  • Configuration ComPortHandle: This identifies the system transport type and port number you wish to use; usart is the only allowed type, and your system limits the port number.

  • Example

      <ComPort>Microsoft.SPOT.Emulator.Com.ComPortToMemoryStream</ComPort> <ComPort >   <ComPortHandle>Usart1</ComPortHandle>  </ComPort> 

TimingServices

TimingServices contains the driver name and configuration for the timing services manager object.

  • Type Microsoft.SPOT.Emulator.Time.TimingServices

  • Configuration SystemClockFrequency: Sets the number of ticks per second on the system clock.

  • Example

     <TimingServices>Microsoft.SPOT.Emulator.Time.TimingServices</TimingServices>  <TimingServices >     <SystemClockFrequency>27000000</SystemClockFrequency>  </TimingServices> 

Importing Configurations

In addition to the basic tags <Types> and <EmulatorComponents> that appear within <Emulator>, mentioned in the section titled "Adding Emulated Components" earlier in this chapter, the configuration file also allows the use of the <Import> tag, which allows you to specify the immediate loading of another XML configuration file.

Advanced Emulator Techniques

This section discusses emulator command-line arguments and emulator namespaces. This section is not for the faint of heart and care should be used when customizing the emulator through these arguments.

Emulator Command-Line Arguments

This section documents the available command-line arguments that you can pass into the emulator at startup.

Note 

Only a Windows console window can pass emulator command-line arguments. It is not possible at this time to pass custom arguments to the emulator from within Visual Studio.

/config

The argument /config specifies the path and file name to a configuration file for the Configuration Engine to use. It may appear multiple times and the Configuration Engine will load and apply each configuration file. This technique is useful for modularizing your configurations (that is, having one configuration file specify a baseline device setting and several others that define peripheral sets for, say, different models or SKUs of your product).

 "/config:C:\MyProject\Baseline.Config" "/config:C:\MyProject\Deluxe.Config" 

When running under Visual Studio, the Device drop-down menu (located on the Micro Framework tab of Project\Properties) determines which emulator to run (when Transport is set to Emulator). The name of the emulator found here corresponds to the registry entry you created for your custom emulator design, as described in the section titled "Title" earlier in this chapter. A registry key Config specifies the proper configuration file and is automatically added to the command line when debugging under Visual Studio. Using this technique, you can load only one configuration file at a time, but you can use the <Import> directive within the configuration file to load additional files.

/load

You can use the switch /load to specify additional assemblies to load. These must be standard compatible assemblies of type .pe, .exe, .dll, .dat, or .manifest. If you launch the emulator from Visual Studio, all references will automatically be resolved; otherwise, you will need to resolve them yourself.

Note 

Only the .pe assembly type is officially documented and supported, so use the other types at your own risk.

/waitfordebugger

The argument /waitfordebugger is a Boolean value that determines whether the execution engine should wait for a debugger before starting execution. The default for this setting is false. When you start the emulator from within Visual Studio, it is set to true.

 /waitfordebugger:true 

/commandlinearguments

If you specified command-line arguments on the Debug tab of your Visual Studio project Properties, they will appear here. Alternatively, you can specify this setting directly from the Windows console when starting the emulator, which will pass the value of this setting to your application's entry point, if you define it to take an array of Strings.

 /commandlinearguments="tea" 

And, in your program:

 public class BeverageDispenser {    public static void Main(String[] args)    {       if (args != null && args.Length != 0)       {          if (args[0] == "coffee")             //... 

Because this functionality is not available for your device startup (in other words, this functionality is only available to the emulator), this is really only useful for debugging or unit testing, for example, your application.

/nodefaultconfig

The presence of the switch /nodefaultconfig will cause the emulator to not load the default components and to only use the components specified in your configuration file. The default components are: HAL, Com Port Collection, Gpio Collection, SPI Bus, Memory Manager, Timing Services, I2C Bus, Serial Port Collection, and Named Pipe Server.

Note 

This is definitely an advanced command-line option. As you can see from the long list of default components that are loaded, specifying this option will require a lot of work on your part.

/verbose

The presence of the switch /verbose determines if the emulator should generate diagnostic messages during its operation, such as warnings from drivers regarding out-of-bounds configuration settings.

/nomessagebox

The argument /nomessagebox is a Boolean value that, when set to true, will suppress any pop-up messages from appearing as a result of an emulator exception. This is useful for automation tasks involving the emulator, such as performing unit tests as part of your automated build process. The default value is false (that is, show pop-up messages) and is useful for interactive debugging.

 /nomessagebox:true 

Emulator Namespaces

This section provides a brief description of each of the .NET Micro Framework emulator namespaces purely for reference.

Microsoft.SPOT.Emulator

The Microsoft.SPOT.Emulator namespace provides application programming interface (API) elements you can use to emulate a microprocessor system.

Microsoft.SPOT.Emulator.Com

The Microsoft.SPOT.Emulator.Com namespace provides API elements that emulate serial communications ports, also known as COM ports.

Microsoft.SPOT.Emulator.Gpio

The Microsoft.SPOT.Emulator.Gpio namespace provides API elements you can use when working with general-purpose input/output ports in your .NET Micro Framework hardware emulator.

Microsoft.SPOT.Emulator.I2c

The Microsoft.SPOT.Emulator.I2c namespace provides emulation for I2C busses and devices that you can connect to I2C busses.

Microsoft.SPOT.Emulator.Lcd

The Microsoft.SPOT.Emulator.Lcd namespace contains API elements you can use to work with LCDs in your. NET Micro Framework hardware emulator.

Microsoft.SPOT.Emulator.Memory

The Microsoft.SPOT.Emulator.Memory namespace contains API elements you can use to configure and manage RAM and flash memory in your .NET Micro Framework hardware emulator.

Microsoft.SPOT.Emulator.Serial

The Microsoft.SPOT.Emulator.Serial namespace contains API elements you can use to simulate serial ports in your .NET Micro Framework hardware emulator.

Microsoft.SPOT.Emulator.Spi

The Microsoft.SPOT.Emulator.Spi namespace provides API elements you can use to emulate serial peripheral interface (SPI) devices.

Microsoft.SPOT.Emulator.Time

The Microsoft.SPOT.Emulator.Time namespace provides API elements you can use to emulate timing services.




Embedded Programming with the Microsoft .Net Micro Framework
Embedded Programming with the Microsoft .NET Micro Framework
ISBN: 0735623651
EAN: 2147483647
Year: 2007
Pages: 118

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net