Introduction
As you know, Google Maps is the most popular application. Every one of us who uses the internet has seen this application. In this article, I am going to share a technique to show your maps on Micro Framework device.
Background
First of all, I am using a TahoeII Developing Kit for this application. This device has been developed by Device Solution. You must set the IP address of your device.
All of the data download is from map.google.com.
You have 2 options. Y you can set your IP static, using this :
foreach (NetworkInterface nic in nics)
{
nic.EnableStaticIP("192.168.2.8", "255.255.255.0", "192.168.2.254");
}
Or you can use your DHCP server:
foreach (NetworkInterface nic in nics)
{
nic.EnableDhcp();
}
In my opinion, you must use the static
method. Sometimes, DHCP option creates problems.
Using the Code
When our device has an IP address, we need a web client. It must download the content from a URL. You can write your own class or you can use this. I found this class and use it. I think Elze Kool has got one like this.
WebClient.cs
using System;
using Microsoft.SPOT;
using System.Net.Sockets;
using System.Net;
using Microsoft.SPOT.Presentation;
using System.Text;
using System.Collections;
namespace GoogleEarthMF
{
public class WebClient {
public WebClient(String server, Int32 port) {
this._server = server;
this._port = port;
}
public enum ContentType {
Text,
Image
}
public enum HttpVersion {
V_10,
V_11
}
String _server;
Int32 _port;
public object GetContent(String request, ContentType type, HttpVersion version) {
const Int32 c_microsecondsPerSecond = 1000000;
using (Socket serverSocket = ConnectSocket(_server, _port)) {
Byte[] bytesToSend = Encoding.UTF8.GetBytes
("GET " + request + " HTTP/1." +
(version == HttpVersion.V_10 ? "0":"1") + "\r\n" +
"Host: " + _server + "\r\n" +
"Connection: Close\r\n\r\n");
serverSocket.Send(bytesToSend, bytesToSend.Length, 0);
Byte[] buf = new Byte[1024];
Byte[] imgData = null;
DateTime timeoutAt = DateTime.Now.AddSeconds(30);
while (serverSocket.Available == 0 && DateTime.Now < timeoutAt) {
System.Threading.Thread.Sleep(100);
}
string header = String.Empty;
string page = String.Empty;
bool bHeaderReceived = false;
int offset = 0;
int size = 1;
int index = 0;
while (serverSocket.Poll(30 * c_microsecondsPerSecond,
SelectMode.SelectRead)) {
if (serverSocket.Available == 0)
break;
Array.Clear(buf, 0, size);
Int32 bytesRead = serverSocket.Receive
(buf, offset, size, SocketFlags.None);
if (bytesRead == 0)
break;
if (bHeaderReceived == false) {
header = header + new String(Encoding.UTF8.GetChars(buf));
if (buf[0] == '\n' && header.IndexOf("\r\n\r\n") > 0) {
bHeaderReceived = true;
size = buf.Length;
Debug.Print(header);
if (type == ContentType.Image) {
string tag = "Content-Length:";
int lenIndex = header.IndexOf(tag);
if (lenIndex > 0) {
int len = Int32.Parse(
header.Substring(
lenIndex + tag.Length,
header.IndexOf("\r\n",
lenIndex) - lenIndex - tag.Length));
Debug.Print("len = " + len.ToString());
imgData = new byte[len];
}
}
}
} else {
switch (type) {
case ContentType.Text:
page = page + new String(Encoding.UTF8.GetChars(buf));
break;
case ContentType.Image:
Array.Copy(buf, 0, imgData, index, bytesRead);
index += bytesRead;
break;
}
}
}
return type == ContentType.Text ?
(object)page :
(object)new Bitmap(imgData, Bitmap.BitmapImageType.Gif);
}
}
Socket ConnectSocket(String server, Int32 port) {
IPHostEntry hostEntry = Dns.GetHostEntry(server);
Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(hostEntry.AddressList[0], port));
return socket;
}
}
}
Getting Maps
We create a Windows Application using MF and adding WebClient.cs to our project. Now our method is this:
double lat = 37.060383;
double lot=37.374287;
int zoom = 12;
public void ciz(double lat, double lot, int zoom)
{
string size = "320x240";
Bitmap screen = new Bitmap(SystemMetrics.ScreenWidth,
SystemMetrics.ScreenHeight);
try
{
WebClient client = new WebClient("maps.google.com", 80);
Bitmap map = client.GetContent(
"/staticmap?center=" + lat.ToString() + "," +
lot.ToString() + "&zoom=" + zoom + "&size=" +
size + "&maptype=mobile",
WebClient.ContentType.Image, WebClient.HttpVersion.V_11) as Bitmap;
screen.DrawImage(0, 0, map, 0, 0, map.Width, map.Height);
screen.Flush();
}
catch (SocketException se)
{
}
}
All of this creates a request from maps.google.com using WebClient.cs getting data like a Bitmap image and displaying it on screen. Easy! This is a WPF example.
On TahoeII:
We can use standard buttons for navigation. Also code like that:
private void OnButtonUp(object sender, ButtonEventArgs e)
{
double factor = 18 - (double)zoom;
switch (e.Button)
{
case Button.VK_DOWN:
ciz(lat -= 0.0003F * factor, lot, zoom);
break;
case Button.VK_RIGHT:
ciz(lat, lot += 0.0003F * factor, zoom);
break;
case Button.VK_LEFT:
ciz(lat, lot -= 0.0003F * factor, zoom);
break;
case Button.VK_UP:
ciz(lat += 0.0003F * factor, lot, zoom);
break;
case Button.VK_SELECT:
zoom++;
ciz(lat, lot, zoom);
break;
}
}
And for zoom in and zoom out buttons, I use this:
void p_StylusDown(object sender, StylusEventArgs e)
{
int StylusX;
int StylusY;
e.GetPosition((UIElement)sender, out StylusX, out StylusY);
if ((StylusX <= 31) & ((StylusY >= 50) & (StylusY <= 81)))
{
if (zoom > 4)
{
ciz(lat, lot, --zoom);
}
}
if ((StylusX <= 31) & ((StylusY >= 20) & (StylusY <= 51)))
{
if (zoom < 18)
{
ciz(lat, lot, ++zoom);
}
}
}
If reading longitude and langitude data from a GPS device over a serial port, we can make a navigation device using .NET Micro Framework. We must also use a GPRS modem for getting map information or we can use an offline version. All of the maps can be saved in an SD card and we can reach them.
Thank you for reading. Have a wonderful day and happy .NET coding everyone!
(I used some functions from
Elze Kool's blog.)