Department of InformatiX
Microsoft .NET Micro Framework Tools & Resources

During development of my first bigger .NET Micro Framework project, I needed to test the program on emulator at home, my colleague was using the Tahoe board and finally we were also deploying it directly to the Meridian in the final product. You cannot test everything on the emulator, neither on the development board, and wiring was different in the device than on the development board. In order to avoid changing the project settings all the time, where to deploy, update pin declaractions etc. - or even keeping three separate projects, we have used the following feature of the Visual Studio to do the dirty work for us.

Directives

Directives are lines of codes containing some information for the compiler. They allow to skip pieces of code during compilation, generate warnings or errors, group code into regions and other things. For details with examples, I suggest to take a look into the C# Language Specification.

The most familiar for most of you will probably be the #region and #endregion ones. These are in fact exceptional a bit, because the compiler practically ignores them (actually it treats them as #if true and #endif). However, Visual Studio uses them to make the region collapsible:

Sreenshot of expanded and collapsed region

But today we are going to use conditional compilation directives, which are #if, #elif, #else and #endif. Their task is to mark a part of a file, which either should or should not be compiled, depending on whether conditional symbols are defined. You can think about them as a boolean variables, with a true value if defined, or false if they are not. There are two ways how to define such symbol: either at the beginning of a file using #define directive (no user code is allowed before), or using the /define compiler parameter. The latter is available in the Visual Studio UI, which we will see later.

The #if and #elif must be followed by a boolean expression; whereas the standard operators like && and || are allowed. The expression is evaluated during compilation and if it results in true, the code surrounded is compiled, otherwise it is completely skipped - it can even contain errors. For example:

#define SATURDAY #if SATURDAY || SUNDAY #define WEEKEND #endif using Microsoft.SPOT; // no code is allowed before #define class Program { public static void Main() { #if WEEKEND Debug.Print("Hurray! It's weekend!"); // this row gets compiled, #else Debug.Print("Okay, just another working day..."); // but you won't find this one even using Reflector #endif } }

Visual Studio

A solution in Visual Studio can have several configurations. For all projects, two default ones are created: Debug, and Release. You can see them in the Standard toolbar and switch between them in a single click any time:

Screenshot of Standard toolbar

The trick is, that each configuration keeps its own project settings and compilation parameters. We will use this to define different conditional symbols, as well as the deployment target, by selecting a configuration. In the list of configurations, select Configuration Manager....

Screenshot of Configuration Manager

In the Active solution configuration: list select New... and create one eg. named Emulator and one named Tahoe. Now we will apply the desired settings in project properties. You can define the conditional symbols on the Build tab, which will become defined across the whole project (the #define directive works only for single file).

Screenshot of the Build tab

The symbols are to be written in the Conditional compilation symbols text box. If you want to define more symbols, you can separate them by space. I've chosen TAHOE symbol for the Tahoe configuration and TAHOE and EMULATOR for the Emulator one (I'm using the Tahoe emulator, so code intended for Tahoe does apply). The Debug configuration, for example, defines the DEBUG symbol by default.

On the Micro Framework tab, select the development board as a target for the Tahoe configuration, and for the Emulator one, choose the Tahoe emulator. You can choose the configuration to which your settings are applied in the Configuration combo box:

Screenshot of the Micro Framework tab

Let's say we have the Debug configuration for deploying into the production module. You can then choose eg. proper port declaration by switching the configurations in the toolbar (even the whole TahoePins enum can by conditional):

Code with Debug configuration applied Code with Tahoe configuration applied

When you pres F5, the application runs on device, if you choose Emulator in the toolbar, hit F5 and it runs in emulator. No complicated settings anymore.

By the way, you can freely nest the directives in themselves:

#if TAHOE public static readonly Cpu.Pin Relay1 = TahoePins.PB12; public static readonly Cpu.Pin Relay2 = TahoePins.PA8; public static readonly Cpu.Pin Relay3 = TahoePins.PB13; #if EMULATOR public static readonly Cpu.Pin Relay4 = TahoePins.PA9; #else public static readonly Cpu.Pin Relay4 = TahoePins.PB14; #endif #else public static readonly Cpu.Pin Relay1 = Meridian.Pins.GPIO4; public static readonly Cpu.Pin Relay2 = Meridian.Pins.GPIO12; public static readonly Cpu.Pin Relay3 = Meridian.Pins.GPIO5; public static readonly Cpu.Pin Relay4 = Meridian.Pins.GPIO6; #endif

I hope this tip will save you some time. ;-)

Comments
Sign in using Live ID to be able to post comments.