Jarred Capellman
Putting 1s and 0s to work since 1995
RSS
Twitter
LinkedIn

Friday, October 03, 2014

Mono on Windows IoT with an Intel Galileo

Posted By Jarred Capellman

After a failed attempt earlier this week (see my post from Tuesday night) to utilize the CLR that is bundled with Windows IoT, I started digging around for an alternative. Fortunately I was on Twitter later that night and Erik Medina had posted:



Not having any time Wednesday night to dive in, I spent a few hours Thursday night digging around for the Mono for Windows IoT. Fortunately, it was pretty easy to find Jeremiah Morrill's Mono on Windows IoT Blog post, download his binaries and get going.

For those wanting to use Xamarin Studio or MonoDevelop instead of Visual Studio after downloading the binary from Jeremiah, you'll need to add mcs.bat to your bin folder, with the following line (assuming you've extract the zip file to mono_iot in the root of your C drive):
@"C:\mono_iot\bin\mono.exe" %MONO_OPTIONS% "C:\mono_iot\lib\mono\4.5\mcs.exe" %*
For whatever reason this wasn't included and without it, you'll receive:
Could not obtain a C# compiler. C# compiler not found for Mono / .NET 4.5.
Inside of Xamarin Studio, goto Tools -> Options and then scroll down to Projects -> .NET Runtimes and click add to the root of the mono_iot folder. After you've added it, it should look like the following (ignoring the Mono 3.3.0 that I installed separately):

Xamarin Studio with Mono for Windows IoT setup

In addition you'll need to copy the lib folder to your Galileo and at least mono.exe and mono-2.0.dll, both found in the bin folder from Jeremiah's zip file to the folder where you intend to copy your C# executable. You could alternatively after copying over the entire mono_iot folder structure add it to the path like so (assuming once again you've extracted to c:\mono_iot) over a Telnet session:
C:\mono_iot\bin>setx PATH "%PATH%;c:\mono_iot\bin"

SUCCESS: Specified value was saved.
In order for the path variable to update, issue a shutdown /r.

If you want to see the existing variables and their values you can issue a set p which will list the following after you've rebooted your Galileo:
Path=C:\windows\system32;C:\windows;C:\wtt;;c:\mono_iot\bin
PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC
PROCESSOR_ARCHITECTURE=x86
PROCESSOR_LEVEL=5
PROCESSOR_REVISION=0900
ProgramData=C:\ProgramData
ProgramFiles=C:\Program Files
PROMPT=$P$G
PUBLIC=C:\Users\Public
With the environment variable updated, you'll no longer have to either copy the mono executable to the folder of your app nor include the full path over Telnet - definitely a time saver in my opinion.

Now back to deploying my little WebClient test from Tuesday with Mono...

From Visual Studio you don't need set anything up differently, however I was running into issues with the app.config when compiling from Visual Studio and deploying a little test app to my Galileo:
System.AggregateException: One or more errors occurred ---> 
System.TypeInitializationException: An exception was thrown by the type initializer for
System.Net.HttpWebRequest ---> System.Configuration.ConfigurationErrorsException: 
Error Initializing the configuration system. ---> 
System.Configuration.ConfigurationErrorsException: Unrecognized configuration section 
So I went back to using Xamarin Studio, but received the following:
System.Net.WebException: An error occurred performing a WebClient request. ---> System.NotSupportedException: http://www.bing.com
  at System.Net.WebRequest.GetCreator (System.String prefix) [0x00000] in :0 
  at System.Net.WebRequest.Create (System.Uri requestUri) [0x00000] in :0 
  at System.Net.WebClient.GetWebRequest (System.Uri address) [0x00000] in :0 
  at System.Net.WebClient.SetupRequest (System.Uri uri) [0x00000] in :0 
  at System.Net.WebClient.OpenRead (System.Uri address) [0x00000] in :0 
  --- End of inner exception stack trace ---
  at System.Net.WebClient.OpenRead (System.Uri address) [0x00000] in :0 
  at System.Net.WebClient.OpenRead (System.String address) [0x00000] in :0 
  at (wrapper remoting-invoke-with-check) System.Net.WebClient:OpenRead (string)
Not a good sign - essentially saying WebClient isn't supported. Got me thinking to verify the version of Mono from Jeremiah:
C:\>mono -V
Mono JIT compiler version 2.11 (Visual Studio built mono)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
	TLS:           normal
	SIGSEGV:       normal
	Notification:  Thread + polling
	Architecture:  x86
	Disabled:      none
	Misc:          softdebug 
	LLVM:          supported, not enabled.
	GC:            Included Boehm (with typed GC)
From the 2.x branch not the newer 3.x branch like what I utilize at work for my iOS and Android development, but not wanting to go down the path of creating my own 3.x port I kept diving in - attempting to try the HttpClient that I knew wasn't supported by Windows IoT's CLR. I threw together a quick sample to pull down the compare results from jcBENCH to the console:
public async Task < T > Get < T > (string url) {
	using (var client = new HttpClient()) {
		var result = await client.GetStringAsync(url);

		return JsonConvert.DeserializeObject < T > (result);
	}
}

public async void RunHttpTest() {
	var result = await Get < List < string > > ("http://www.jcbench.com/api/CompareResults");

	foreach (var item in result) {
		Console.WriteLine (item);
	}
}
As far the project was concerned I added the .NET 4.5 version of Newtonsoft.Json.dll to the solution via NuGet and made sure it was copied over during deployment. With a bit of a surprise:
C:\winiottest>mono winiottest.exe
AMD A10-4600M APU with Radeon(tm) HD Graphics  
AMD A10-7850K Radeon R7, 12 Compute Cores 4C 8G
AMD A6-3500 APU with Radeon(tm) HD Graphics
AMD A6-5200 APU with Radeon(TM) HD Graphics    
AMD Athlon(tm) 5150 APU with Radeon(tm) R3
AMD Athlon(tm) 5350 APU with Radeon(tm) R3
AMD C-60 APU with Radeon(tm) HD Graphics
AMD E-350D APU with Radeon(tm) HD Graphics
AMD E2-1800 APU with Radeon(tm) HD Graphics
AMD FX(tm)-8350 Eight-Core Processor
AMD Opteron(tm) Processor 6176 SE
ARMv7 Processor rev 0 (v7l)
ARMv7 Processor rev 1 (v7l)
ARMv7 Processor rev 2 (v7l)
ARMv7 Processor rev 3 (v7l)
ARMv7 Processor rev 4 (v7l)
ARMv7 Processor rev 9 (v7l)
Cobalt Qube 2
Intel Core 2 Duo
Intel Core i5-4300U
Intel(R) Atom(TM) CPU  Z3740  @ 1.33GHz
Intel(R) Core(TM) i3-2367M CPU @ 1.40GHz
Intel(R) Core(TM) i7-4650
Intel(R) Quartz X1000
Intel(R) Xeon(R) CPU E5-2695 v2 @ 2.40GHz
Intel(R) Xeon(R) CPU E5440 @ 2.83GHz
PowerPC G5 (1.1)
R14000
UltraSPARC-IIIi
I should note even with the newly added Sandisk Extreme Pro SDHC card, the total time from execution to returning the results was around 10 seconds, where as on my AMD FX-8350 also hard wired it returns in less than a second. Given that also the Galileo itself is only 400mhz - you definitely won't be running a major WebAPI service on this device, but there are some definite applications (including one I will be announcing in the coming weeks).

More to come with the Galileo - I received my Intel Centrino 6235 mPCI WiFi/Bluetooth card yesterday and am just awaiting the half->full length mPCIe adapter so I can mount it properly. With any luck I will receive that today and will post on how to get WiFi working on the Galileo under Windows IoT.