Creating A Custom Emulator: A Step-by-Step Example

In this walkthrough, you will create an emulator for a hypothetical massage chair unit, as well as a test application that runs on the emulator.

The following steps for creating a custom emulator are described.

  1. Creating the emulator project using the Emulator template in Visual Studio.
  2. Defining emulator components in code.
  3. Defining emulator components in an XML File.
  4. Writing the application software that will run on the emulator.

Hardware Description

The device you will emulate is a massage chair unit connected to a main board. The operation of the massage chair is controlled by a number of GPIO pins listed in the following table. The main mechanical part of the motor consists of two motors. The massaging unit can be moved up and down by the motor controlled by the signals UD_ONOFF and UD_FFREW, while the signal M_ONOFF_L, M_ONOFF_H, and M_FFREW control the motor in charge of massaging.

In this walkthrough, you will focus on two output signals, UD_ONOFF and UD_FFREW on the massage chair, and two inputs for two buttons connected to the main board via pin 20 and 21. The application will move the massaging unit up when the Up button is pressed, and down when the Down button is pressed.

Description Input/Output Pin
Up / Down motor power Output 61
Up / Down motor direction select Output 63
Up Button Input 20
Down Button Input 21

To Create the Emulator Project

  1. On the File menu in Visual Studio, point to New and then click Project. The New Project dialog box appears.

  2. In the Project types tree, expand the Visual C# node if it is not already expanded.

  3. In the expanded node, click Micro Framework.

  4. In the Templates pane, choose the Device Emulator templates.

  5. In the Name box near the bottom of the dialog box, type a name for your project. For this example, name your project MassageChairEmulator.

  6. In the Location box, specify the folder that will contain your project, and then click OK.

    The project you created includes the following files:

    • Program.cs – Contains the entry point of the emulator, and the Program class that extends the base Emulator class.
    • Form1.cs (and Form1.Designer.cs) – Contains the WinForm user interface for the emulator.
    • Emulator.config – the default XML configuration file for the emulator.

To Declare Input Pins in the Emulator Code

  1. Open Program.cs by double-clicking on Program.cs in Solution Explorer.

  2. Add the following using statement to the top of the file:

    using Microsoft.SPOT.Emulator.Gpio;
    

  3. Find the method SetupComponent, and replace it with the following code:

    public override void SetupComponent()
    {
    this.GpioPorts.MaxPorts = 128;

    GpioPort motorUp = new GpioPort(); motorUp.ComponentId = "MotorUpButton"; motorUp.Pin = (Microsoft.SPOT.Hardware.Cpu.Pin)20; motorUp.ModesAllowed = GpioPortMode.InputPort; motorUp.ModesExpected = GpioPortMode.InputPort;

    GpioPort motorDown = new GpioPort(); motorDown.ComponentId = "MotorDownButton"; motorDown.Pin = (Microsoft.SPOT.Hardware.Cpu.Pin)21; motorDown.ModesAllowed = GpioPortMode.InputPort; motorDown.ModesExpected = GpioPortMode.InputPort;

    this.RegisterComponent(motorUp); this.RegisterComponent(motorDown);

    base.SetupComponent(); }

To Create User Interface for Input Pins

  1. Create two buttons in the WinForm user interface, one for each of the input ports we created in the last step.

    1. Open the designer view of Form1.cs by double-clicking on Form1.cs in the Solution Explorer sidebar. The tab should read Form1.cs [Design].
    2. In the Toolbox sidebar, under Common Controls, select Button control. If the Toolbox sidebar is not present, select View | Toolbox
    3. In the form control, draw two buttons, one one above the other.
    4. Rename the buttons and change the text on them.
      1. Click on the top button. In the Properties sidebar, change the Name property to motorUpButton, and change the Text property to Up.
      2. Click on the other button. In the Properties sidebar, change the Name property to motorDownButton, and change the Text property to Down.
  2. Generate the stub methods for the OnMouseUp and OnMouseDown events.

    1. Click on the top button. In the Properties sidebar, click on the Events button.
    2. Double-click on the MouseUp event. A method named motorUpButton_MouseUp should be generated.
    3. Go back to the designer view of Form1.cs.
    4. Double-click on the MouseDown event in the Properties sidebar. A method named motorUpButton_MouseDown should be generated.
    5. Repeat the previous four steps on the button named MotorDownButton. >
  3. Populate the event handlers to send signals to the input ports.

    1. Open the code view of Form1.cs.

    2. Add the following statements to the top of the file:

      using Microsoft.SPOT.Emulator;
      using Microsoft.SPOT.Emulator.Gpio;
      

    3. Add the following private member variables to the class Form1.

      Emulator _emulator;
      GpioPort _motorUpButtonPort, _motorDownButtonPort;
      

    4. Modify the constructor of Form1 to retrieve the GpioPort components, as follows:

      public Form1(Emulator emulator)
      {
      _emulator = emulator;

    _motorUpButtonPort = _emulator.FindComponentById("MotorUpButton") as GpioPort; _motorDownButtonPort = _emulator.FindComponentById("MotorDownButton") as GpioPort;

    InitializeComponent(); }

    1. In Form1.cs, create a helper function, GpioPortSafeWrite, along with a delegate, GpioPortWriteDelegate, to marshal the GpioPort.Write calls to the system thread. Add the following code to the Form1 class.
      delegate void GpioPortWriteDelegate(bool state);

private void GpioPortSafeWrite(GpioPort port, bool value) { port.Invoke(new GpioPortWriteDelegate(port.Write), value); }

6.  Modify the event handlers in `Form1.cs` to match the following code, so that they respond to the button clicks by changing the values of the input ports. <pre IsFakePre="true" xmlns="http://www.w3.org/1999/xhtml">

private void motorUpButton_MouseDown(object sender, MouseEventArgs e) { GpioPortSafeWrite(_motorUpButtonPort, true); }

private void motorUpButton_MouseUp(object sender, MouseEventArgs e) { GpioPortSafeWrite(_motorUpButtonPort, false); }

private void motorDownButton_MouseDown(object sender, MouseEventArgs e) { GpioPortSafeWrite(_motorDownButtonPort, true); }

private void motorDownButton_MouseUp(object sender, MouseEventArgs e) { GpioPortSafeWrite(_motorDownButtonPort, false); }

7.  Build and run the emulator.
    1.  Build the solution by pressing the **F6** key or by selecting **Build | Build Solution**. As part of the build process, Visual Studio will register this new emulator with the system, so the Micro Framework applications will recognize this application as an emulator.
    
    2.  Run the emulator by pressing the **F5** key or by selecting **Debug | Start Debugging**. An error message containing the following text appears: `Error: No assembly file is found. Please specify at least one exe, dll, manifest, or pe file to load.`
        
        The emulator initialized successfully, but it failed as expected during the assembly loading stage of the start up process, since we have not yet created a Micro Framework application to run on it.

To Create an Application to Run on the Emulator

So far, we have created a simple emulator with two GPIO input ports that are controlled by the two buttons on the UI. Next, we’ll build a simple application that will interact with the input ports created by this simple emulator.

  1. Create a new .NET Micro Framework project in the current solution.
    1. Select File | New | Project
    2. Under Project types, select Micro Framework
    3. Under Templates, select Console Application
    4. Choose the name MassageChairApplication for your project.
    5. For the Solution drop down list, select Add to Solution
    6. Click OK
  2. Add a reference to Microsoft.SPOT.Hardware, so that the application can access the managed drivers, including GPIO.
    1. Select Project | Add Reference.
    2. In the Add Reference dialog box, under the .NET tab, select Microsoft.SPOT.Hardware
    3. Click OK.
  3. Create a simple program that prints messages in the debug output in when the value of either of the two input ports changes.
    1. Open Program.cs by double-clicking the filename Program.cs under MassageChairApplication in Solution Explorer.

    2. Add the following two using statements to the top of the file:

      using Microsoft.SPOT.Hardware;
      using System.Threading;
      

    3. Place the following member variable declaration in the Program class.

      InterruptPort _motorUpButton, _motorDownButton;
      

    4. Add a constructor for the Program class. Inside the constructor, add code as follow to instantiate the 2 InterruptPort objects, one for each of the two input ports. In addition, hook up the event handlers.

      public Program()
      {
      _motorUpButton = new InterruptPort((Cpu.Pin)20, false,
      Port.ResistorMode.PullDown,
      Port.InterruptMode.InterruptEdgeBoth);
      _motorDownButton = new InterruptPort((Cpu.Pin)21, false,
      Port.ResistorMode.PullDown,
      Port.InterruptMode.InterruptEdgeBoth);

_motorUpButton.OnInterrupt += new GPIOInterruptEventHandler(MotorUpButton_OnInterrupt); _motorDownButton.OnInterrupt += new GPIOInterruptEventHandler(MotorDownButton_OnInterrupt); }

5.  Create the event handlers, and populate them to print debug messages, as follows: <pre IsFakePre="true" xmlns="http://www.w3.org/1999/xhtml">

void MotorDownButton_OnInterrupt(Cpu.Pin port, bool state, TimeSpan time) { Debug.Print("MotorDownButton " + ((state) ? "Down" : "Up")); }

void MotorUpButton_OnInterrupt(Cpu.Pin port, bool state, TimeSpan time) { Debug.Print("MotorUpButton " + ((state) ? "Down" : "Up")); }

6.  Change the **Main** method to instantiate a **Program** object, and then to sleep forever, as follows: <pre IsFakePre="true" xmlns="http://www.w3.org/1999/xhtml">

public static void Main() { new Program(); Thread.Sleep(-1); }

7.  Set up the Micro Framework application to deploy to the emulator that we created earlier.
    1.  Open the project properties page for the Micro Framework application by right-clicking on the project name (**MassageChairApplication**) and select **Properties** in **Solution Explorer**.
    2.  Click on the **Micro Framework** tab.
    3.  In the **Transport** drop-down box, select **Emulator**.
    4.  In the **Device** drop-down box, select the name of the emulator.
8.  Run the Micro Framework application under the debugger.
    1.  Set the Micro Framework application as the startup project by right-clicking on the project name (**MassageChairApplication**) and select **Set as StartUp Project** in **Solution Explorer**.
    2.  Start the debugger by pressing the **F5** key or select **Debug | Start Debugging**. The emulator starts.
    3.  Inside Visual Studio, open the Output window by selecting **View | Output**
    4.  Click on the two buttons in the emulator and look for the debug messages in the output window. Since the debugger is attached to the Micro Framework application, we can also place breakpoints in the code and step through the program.
    5.  Close the debugger by either closing the emulator, or by pressing the stop button on the **Debug** toolbar.
  1. Add the two output ports that control the motor to the application, and update the interrupt handlers to produce the correct outputs.
    1. Open Program.cs in the Micro Framework application by double-clicking Program.cs under MassageChairApplication in Solution Explorer.

    2. Place the following member variable declaration in class Program.

      OutputPort _motorOnOff, _motorDirection;

    3. Inside the constructor of the class Program, add the following code to instantiate the two OutputPort objects, one for each of the two output ports. Set them to false initially.

      _motorOnOff = new OutputPort((Cpu.Pin)61, false);
      _motorDirection = new OutputPort((Cpu.Pin)63, false);
      

    4. Update the event handlers, so when the up button is pressed, the motor goes up, and the motor goes down when the down button is pressed. The code is as follows:

      void MotorDownButton_OnInterrupt(Cpu.Pin port, bool state, TimeSpan time)
      {
      if (state == true)
      {
      _motorDirection.Write(false);
      _motorOnOff.Write(true);
      }
      else
      {
      _motorOnOff.Write(false);
      }
      }

void MotorUpButton_OnInterrupt(Cpu.Pin port, bool state, TimeSpan time) { if (state == true) { _motorDirection.Write(true); _motorOnOff.Write(true); } else { _motorOnOff.Write(false); } }

5.  Build the solution by pressing the **F6** key or by selecting **Build | Build Solution**.

Adding Output Pins to the Emulator using Emulator.Config

In this step, we will return to the emulator, and create two GPIO output pins on GPIO port 61 and 63, one for each of the two buttons we will be creating to control the motor.

  1. Open Emulator.config under the emulator project by double clicking on Emulator.config in Solution Explorer.
  2. Create two GPIO output pins on port 61 and 63 by modifying the <Types> node and the <EmulatorComponents> node as follows:
    <?xml version="1.0" encoding="utf-8" ?>
    <Emulator>
    <Types>
    <GpioPort>Microsoft.SPOT.Emulator.Gpio.GpioPort</GpioPort>
    </Types>
    <EmulatorComponents>
    <GpioPort id="MotorOnOff">
    <Pin>61</Pin>
    <ModesAllowed>OutputPort</ModesAllowed>
    <ModesExpected>OutputPort</ModesExpected>
    </GpioPort>
    <GpioPort id="MotorDirection">
    <Pin>63</Pin>
    <ModesAllowed>OutputPort</ModesAllowed>
    <ModesExpected>OutputPort</ModesExpected>
    </GpioPort>
    </EmulatorComponents>
    </Emulator>
    

Connecting a Scroll Bar to the Output Pins

The following steps hook up the output pins defined in the previous step to a scroll bar control.

  1. Create a VScrollBar control in the WinForm user interface to represent the motor position.
    1. Open the designer view of Form1.cs by double-clicking on Form1.cs in Solution Explorer. The tab should read Form1.cs [Design].
    2. In the Toolbox, under All Windows Forms, select VScrollBar control. If the Toolbox sidebar is not visible, select View | Toolbox.
    3. In the form control, draw a vertical scroll bar.
    4. Rename the VScrollBar to motorPosScrollBar.
    5. Change the LargeChange and SmallChange properties to 0, to prevent user scrolling.
  2. Add code to listen to the newly created output port, and move the vertical scroll bar up and down accordingly to represent the motor position.
    1. Right-click on Form1.cs in Solution Explorer, and select View Code, to open the code view of Form1.cs.
    2. In class Form1, add the following member variables:
      GpioPort _motorOnOff, _motorDirection;
      System.Timers.Timer _motorTimer;
      
      The timer will be used to periodically move the motor when the _motorOnOff signal is continuously on.
    3. Add the following code in the constructor of the Form1 class to retrieve the output ports and create the timer object. In addition, register an event handler, _motorOnOff_OnGpioActivity, for the GpioActivity event on the _motorOnOff output port.
      _motorOnOff = _emulator.FindComponentById("MotorOnOff") as GpioPort;
      _motorDirection =
      _emulator.FindComponentById("MotorDirection") as GpioPort;

_motorOnOff.OnGpioActivity += new GpioActivity(_motorOnOff_OnGpioActivity);

_motorTimer = new System.Timers.Timer(); _motorTimer.Interval = 100; _motorTimer.Elapsed += new System.Timers.ElapsedEventHandler(_motorTimer_Elapsed); The timer callback function, _motorTimer_Elapsed, which we’ll create next, will move the motor position based on the signal on _motorDirection. 4. Create a helper function, MoveMotor, to move the motor position on the vertical scroll bar based on the direction. Note that since the MoveMotor function will always get called on a non-UI thread, we would need to call the Invoke method on the control to change the value. Also, create the event handler for the timer, _motorTimer_Elapsed, to call MoveMotor. The code is as follows:

delegate void SetMotorPosDelegate(int value);

void SetMotorPos(int value) { motorPosScrollBar.Value = value; }

void MoveMotor(bool direction) { // if the direction is up (true), we need to decrement, as the // vscrollbar value increases when it goes down int increment = (direction) ? -1 : 1; int newValue = motorPosScrollBar.Value + increment;

if (newValue <= motorPosScrollBar.Maximum && newValue >= motorPosScrollBar.Minimum) { motorPosScrollBar.Invoke( new SetMotorPosDelegate(SetMotorPos), newValue); } }

void _motorTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { MoveMotor(_motorDirection.Read()); }

5.  Add the event handler, **\_motorOnOff\_OnGpioActivity**, to turn the timer on and off, as follows. <pre IsFakePre="true" xmlns="http://www.w3.org/1999/xhtml">

void _motorOnOff_OnGpioActivity(GpioPort sender, bool edge) { if (edge) { MoveMotor(_motorDirection.Read()); _motorTimer.Start(); } else { _motorTimer.Stop(); } }

6.  Build the solution by pressing **F6** or by selecting **Build | Build Solution**.
  1. Run the emulator under the debugger.
    1. Set the startup project back to the emulator by right-clicking on the emulator project name (MassageChairEmulator) and select Set as StartUp Project in Solution Explorer.

    2. Open up the project properties page by right-clicking on the project name (MassageChairEmulator) and select Properties in Solution Explorer.

    3. Click on the Debug tab.

    4. Set the Command line arguments field to the path to the .NET Micro Framework application's executable. Include quotation marks if the path has spaces. The path will normally be in the following form, with Username replaced by your Windows user name:

      "C:\Documents and Settings\Username\My Documents\Visual Studio 2008\Projects\MassageChairEmulator\MassageChairApplication\bin\Debug\MassageChairApplication.exe"

      This will let the emulator know to load our .NET Micro Framework application when it runs.

  2. Run the emulator by pressing the F5 key or by selecting Debug | Start Debugging.
  3. Press and hold the Up and Down buttons, and see the motor position move.