Department of InformatiX
Microsoft .NET Micro Framework Tools & Resources

.NET Micro Framework přichází s propracovanou a hlavně rozšířitelnou architekturou emulátoru. Bohužel projekty k vytváření emulátorů ve Visual Studiu nás nutí používat poněkud překonanou technologii - Windows Forms. Steve již naznačil, že se v sérii článků bude věnovat vyvíjení emulátoru pro Windows Presentation Foundation. Přesto jsem se rozhodl, že svůj již napsaný článek publikuji, pro případ, že někdo z vás nemůže již déle čekat. :-)

Projekty emulátorů

Emulátory jsou .NET aplikace jako každá jiná. Proto by teoreticky neměl být problém vytvořit emulátor jako např. windowsovskou službu, nebo třeba v rámci Windows Workflow Foundation. :-)

.NET Micro Framework SDK pro vás připravilo nový typ projektu Device Emulator, určený speciálně pro tvorbu emulátorů. Přináší tři hlavní funkce, které si budeme v případě vlastního projektu muset obstarat sami. Tou první je registrace emulátoru do Visual Studia. Díky tomu se hned po té, co váš nový emulátor prvně zkompilujete, objeví v seznamu emulátorů ve vlastnostech .NET Micro Framework aplikace. Dále tento emulatorový projekt vygeneruje prázdný konfigurační soubor Emulator.config, a zajišťuje jeho automatické načtení při spuštění emulátoru. Nakonec samozřejmě vygeneruje vlastní šablonu emulátoru, třídu dědící Microsoft.SPOT.Emulator.Emulator.

Zakopaný pes

V čem je tedy potíž? Proč jednoduše nepoužít tento projekt a nevytvořit např. okno Windows Presentation Foundation místo Windows Forms? Problém je, že WPF aplikace, stejně jako některé ostatní, je speciální typ projektu. Dokud váš emulátor nebude označen jako projekt tohoto typu, budete mít na výběr pouze standardní typy souborů (a to mám ještě podezření, že User Control (WPF) je nabízen omylem):

Dialog přidání nového souboru

Cokoliv Emulátor

Prvním řešením je vytvořit ten typ projektu, který potřebujete, a funkcionalitu emulátoru do něj prostě nějak protlačit. Tím samozřejmě přijdete o výhody uvedené výše. Pokusme si je nyní nahradit.

Registrace emulátoru

Registrace do Visual Studia není nijak obtížná - jedná se o krátký zápis do registrů:

string keyBase = @"HKEY_CURRENT_USER\Software\Microsoft\.NETMicroFramework\v3.0\Emulators\MyEmulator"; Microsoft.Win32.Registry.SetValue(keyBase, "Name", "My Emulator"); Microsoft.Win32.Registry.SetValue(keyBase, "Path", @"C:\Path\To\MyEmulator.exe"));

To samozřejmě není příliš univerzální cesta - musíte si hlídat verzi frameworku, a pokud se tým rozhodně změnit strukturu v registrech, nebo přidá další kroky nutné k registraci emulátoru, stěží se to dozvíte. Na druhou stranu je toto nejspíš jediná distribuovatelná možnost. Visual Studio ve skutečnosti používá třídu RegisterEmulator v assembly Microsoft.SPOT.Tasks.dll, kterou najdete v SDK složce Tools. Pokud se spolehnete na to, že uživatel má nainstalovaný .NET Micro Framework SDK (což není úplně nerozumný předpoklad), můžete ji využít také. K registraci pak stačí:

new Microsoft.SPOT.Tasks.RegisterEmulator { SubkeyName = "MyEmulator", Name = "My Emulator", Path = @"C:\Path\To\MyEmulator.exe" }.Execute();

Emulator.config

Standardní projekt emulátoru obsahuje soubor prázdný Emulator.config, kterým je možné měnit konfiguraci emulátoru, aniž by jej bylo třeba znovu kompilovat. Během kompilace se pak tento soubor kopíruje do složky s emulátorem, se stejným názvem jako spustitelný soubor a příponou .emulatorconfig. Tento luxus lze nahradit následujícím postupem:

  1. Přidejte do projektu nový XML soubor. Nazvěte jej jako název assembly a přidejte příponu. Např. při výchozím nastavení se projekt jmenuje MFEmulator1. Konfigurační XML tedy nazvěte MFEmulator1.exe.emulatorconfig
  2. Změňte jeho vlastnost Copy to Output Directory z Do not copy na Copy if newer, případně Copy always.
  3. Příklad XML konfigurace, kterou používá emulátor Microsoftu najdete v SDK adresáři Tools\Microsoft.SPOT.Emulator.Sample.SampleEmulator.exe.emulatorconfig. Jako prázdná šablona s typy může posloužit například:
    <Emulator> <Types> <GpioPort>Microsoft.SPOT.Emulator.Gpio.GpioPort</GpioPort> <LcdDisplay>Microsoft.SPOT.Emulator.Lcd.LcdDisplay</LcdDisplay> <WinFS>Microsoft.SPOT.Emulator.FS.WindowsFileSystem</WinFS> <AsyncWinFS>Microsoft.SPOT.Emulator.FS.AsyncWindowsFileSystem</AsyncWinFS> <BSRegion>Microsoft.SPOT.Emulator.BlockStorage.Region</BSRegion> <BSBlock>Microsoft.SPOT.Emulator.BlockStorage.Block</BSBlock> <BSDevice>Microsoft.SPOT.Emulator.BlockStorage.EmulatorBlockStorageDevice</BSDevice> <RemovableBSD>Microsoft.SPOT.Emulator.BlockStorage.EmulatorRemovableBlockStorageDevice</RemovableBSD> <NativeFS>Microsoft.SPOT.Emulator.FS.NativeFileSystem</NativeFS> <RamManager>Microsoft.SPOT.Emulator.Memory.RamManager</RamManager> </Types> <EmulatorComponents> </EmulatorComponents> </Emulator>

Úprava projektu

Nyní zbývá přidat do projektu odkaz na Mirosoft.SPOT.Emulator assembly a při spuštění aplikace spustit i třídu emulátoru zavoláním metody MyEmulator.Start(), můžete emulátor spustit i v jiném vlákně. Výchozí projekt emulátoru funguje tak, že se v metodě Main vytvoří a spustí emulátor, a vše ostatní co ke spuštění vaší aplikace potřebujete se odehrává v metodě emulátoru InitializeComponent():

namespace MyEmulators { public class MyEmulator : Microsoft.SPOT.Emulator.Emulator { public override void InitializeComponent() { base.InitializeComponent(); // Zde spusťe WPF aplikaci, službu, (ev. WinForms aplikaci, jste-li tací) nebo cokoliv jiného. // Jedná-li se o blokující volání (např. Application.Run()), zajistěte zde její spuštění v jiném vlákně. } public override void UninitializeComponent() { base.UninitializeComponent(); // Zde ukončete vaši aplikaci, zastavte službu nebo zavřete cokoliv je třeba. } // Entry point assembly: static void Main() { new MyEmulator().Start(); } } }

Samozřejmě není problém udělát to obráceně, a spustit instanci emulátoru až z vaší služby nebo aplikace.

Příklad: konzolový emulátor

Udělejme z obyčejné konzolové aplikace emulátor.

  1. Vytvořte novou konzolovou aplikaci.
  2. Přidejte referenci na Microsoft.SPOT.Emulator.dll v SDK adresáři Tools.
  3. Vygenerovanou třídu Program nechte dědit Microsoft.SPOT.Emulator.Emulator.
  4. Nyní má aplikace plnou funkcionalitu emulátoru. Do metody Main vložte new Program().Start(); a když program spustíte, zobrazí se vám známá hláška No assembly file is found. Please specify at least one exe, dll, manifest or pe file to load.
  5. Abychom měli na čem emulátor zkoušet, založte si .NET Micro Framework aplikaci, stačí konzolovou. Pro jednoduchost zkusíme slavné blikání, přidejte referenci na Microsoft.SPOT.Hardware.dll a mějme např.:
    using System.Threading; using Microsoft.SPOT.Hardware; namespace MFConsoleApplication1 { public class Program { public static void Main() { OutputPort port = new OutputPort(Cpu.Pin.GPIO_Pin3, false); while (true) { Thread.Sleep(1000); port.Write(!port.Read()); } } } }
  6. Blikání spusťte - nejspíše se tak stane pomocí Microsoft emulátoru. V okně Output ve Visual Studiu přepněte na Micro Framework Device Deployment:
    okno Output
  7. V okně se objeví jediný řádek, začínající na Launching emulator with command line. Zkopírujte vše od prvního "/load až do konce kromě poslední jednoduché uvozovky. Přepněte do Visual Studia s emulátorem - totiž konzolí, a ve vlastnostech projektu, v záložce Debug, vložte text do políčka Command line arguments. Můžete také už zastavit Microsoftí emulátor.
  8. Zbývá udělat připojit konfigurační soubor. Vložte do projektu nový soubor XML. V naší ukázce potřebujeme jen GPIO_Pin3, takže jeho obsah může vypadat následovně:
    <?xml version="1.0" encoding="utf-8" ?> <Emulator> <Types> <GpioPort>Microsoft.SPOT.Emulator.Gpio.GpioPort</GpioPort> </Types> <EmulatorComponents> <GpioPort id="Pin_Select"> <Pin>3</Pin> <ModesExpected>InputOutputPort</ModesExpected> <ModesAllowed>InputOutputPort</ModesAllowed> </GpioPort> </EmulatorComponents> </Emulator>
  9. Jak již bylo uvedeno výše, přejmenujte XML soubor na název vaší assembly + .emulatorconfig, v našem případě to je ConsoleApplication1.exe.emulatorconfig, a v jeho vlastnostech (F4) nastavte Copy to Output Directory na Copy if newer.
  10. Poslední co chybí našemu konzolovému emulátoru k užitečnosti, je trochu funkcionality. Něco málo informací o stavu a kontrolování pinu:
    using System; using Microsoft.SPOT.Emulator; using Microsoft.SPOT.Emulator.Gpio; namespace ConsoleApplication1 { class Program : Emulator { private static void Main() { new Program().Start(); } public override void Start(string[] args) { Console.WriteLine("Emulator loaded."); base.Start(args); } public override void Run() { (FindComponentById("Pin_Select") as GpioPort).OnGpioActivity += delegate(GpioPort sender, bool edge) { Console.WriteLine(edge); }; Console.WriteLine("Emulator running..."); base.Run(); Console.WriteLine("Emulator exited. Press any key to continue."); Console.ReadKey(); } } }
  11. Tak a je to. Vytvořili jsme emulátor z běžné konzolové aplikace. Podobným způsobem lze protlačit funkčnost emulátoru do projektu libovolného typu a technologie. Jak již bylo zmíněno, nejvhodnější místo pro inicializaci vámi vybrané technologie bude většinou metoda InitializeComponent(), kterou ostatně k tomuto účelu využívá i generovaný kód s Windows Forms. Pokud to vaše technologie vyžaduje, nezapomeňte ji také ukončit v metodě UnitializeComponents().
    Běžící konzolový emulátor
  12. Případnou registraci emulátoru do Visual Studia lze provést způsobem popsaným výše.

Emulátor Cokoliv

Druhou možností je využít nabízený emulátorový projekt se vším všudy, a propašovat do něj vámi požadovanou technologii. Visual Studio rozlišuje typy projektů (např. Windows Forms Application × WPF Application × ASP.NET Web Application × Word 2007 Add-in atd.), a podle toho upravuje chování projektu a zpřístupňuje patřičné typy souborů (Windows Form × WPF Window × Web Form × Word Document atd.). Typ každého projektu je uložen v souboru .csproj ve formě GUID. Pokud například vytvoříte projekt typu WPF Application a podívate se třeba poznámkovým blokem na soubor projektu, uvidíte
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <AssemblyName>WpfApplication1</AssemblyName> <OutputType>WinExe</OutputType> <RootNamespace>WpfApplication1</RootNamespace> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProductVersion>9.0.30729</ProductVersion> <ProjectGuid>{34895117-845f-4fef-9ea4-26211b9c3d15} </ProjectGuid> ... </PropertyGroup> ...

Element ProjectTypeGuids určuje, o jaký projekt se jedná. {60dc8134-eba5-43b8-bcc9-bb4bc16c2548} znamená WPF aplikaci, {FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} znamená jazyk C#. Jak již asi tušíte, stačí tyto GUID vzít a vložit do projektového souboru vašeho emulátoru. Pokud již element ProjectTypeGuids obsahuje, vložte do něj tyto GUID oddělené středníkem, pokud ne, založte jej, tak jako je v předchozí ukázce, do prvního elementu /Project/PropertyGroup. Uložte, a projekt znovu otevřete ve Visual Studiu. A když teď budete chtít přidat soubor, čeká na vás pestrá nabídka:

Dialog přidání nového souboru do upraveného projektu emulátoru

Cokoliv Emulátor, po druhé

Pokud máte nainstalovaný .NET Micro Framework SDK, dočetli jste až sem a chcete aby se váš projekt libovolného typu choval jako emulátor aniž byste museli tuto funkčnost nějak složitě a ručně nahrazovat tak, jak jsme činili výše, mám pro vás sladké překvapení - nemusíte. Stačí si v projektovém souboru emulátoru všimnout některých nápadných částí:

<Project DefaultTargets="Build" ToolsVersion="3.5" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProductVersion>9.0.30729</ProductVersion> <SchemaVersion>2.0</SchemaVersion> <ProjectGuid>{439094ED-505C-476E-B005-90F5719E1044}</ProjectGuid> <OutputType>WinExe</OutputType> <AppDesignerFolder>Properties</AppDesignerFolder> <RootNamespace>MFEmulator1</RootNamespace> <AssemblyName>MFEmulator1</AssemblyName> <EmulatorId>{a11fd6cd-1bf7-46f7-987d-c7129ddcd11a}</EmulatorId> <TargetFrameworkVersion>v3.0</TargetFrameworkVersion> <NetMfTargetsBaseDir Condition="'$(NetMfTargetsBaseDir)'==''">$(MSBuildExtensionsPath)\Microsoft\.NET Micro Framework\</NetMfTargetsBaseDir> </PropertyGroup> ... <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(NetMfTargetsBaseDir)\v3.0\Emulator.Targets" /> <ItemGroup> <Reference Include="Microsoft.SPOT.Emulator, Version=3.0.7186.0, Culture=neutral, PublicKeyToken=2670f5f21e7f4192, processorArchitecture=x86" /> ... </ItemGroup> ... </Project>

Vložte vyznačené řádky do projektu vašeho typu, a rázem získají funkčnost emulátoru. Připomínám, že se jedná o pomoc při tvorbě emulátorů, bez které se lze obejít (např. pokud vám nevyhovuje automatická reistrace). Bez .NET Micro Framework SDK nebude tento trik ani funkční. Pokročilí vývojáři mohou nahlédnout a upravit si zmíněné soubory typu .targets ke své libosti (např. jen vypnout onu registraci) - ale běda jestli někoho uvidim v diskusní skupině že si rozhodil studio a neví co s tím... :-)

Comments
Comment 11.03.2012 1:28:38
I think that "User Control (WPF)" is not mistake since as you know you can host WPF conrol in WinForms. I have created WPF user control which accepts a reference to the Emulator: public Form1(Emulator emulator) { InitializeComponent(); ((UserControl1) this.elementHost1.Child).Emulator = emulator; } and the whole implementation is kept by UserControl1 class.
Sign in using Live ID to be able to post comments.