Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Using Google Maps in .NET Micro Framework

4.88/5 (9 votes)
29 May 2009CPOL2 min read 58.2K  
Using Google Maps in .NET Micro Framework

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 :

C#
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:

C#
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

C#
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;

            // Create a socket connection to the specified server and port.
            using (Socket serverSocket = ConnectSocket(_server, _port)) {
                // Send request to the server.
                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);

                // Reusable buffer for receiving chunks of the document.
                Byte[] buf = new Byte[1024];
                Byte[] imgData = null;
                

                // Wait up to 30 seconds for initial data to be available
                // Will throw exception if connection closed with no data sent
                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;

                // Poll for data until 30 second time out - 
                // Returns true for data and connection closed
                while (serverSocket.Poll(30 * c_microsecondsPerSecond, 
			SelectMode.SelectRead)) {
                    // If 0 bytes in buffer, then connection is closed, 
                    // or we have timed out
                    if (serverSocket.Available == 0)
                        break;

                    // Zero all bytes in the re-usable buffer
                    Array.Clear(buf, 0, size);

                    // Read a buffer-sized HTML chunk
                    Int32 bytesRead = serverSocket.Receive
			(buf, offset, size, SocketFlags.None);

                    // If 0 bytes in buffer, then connection is closed
                    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) {
            // Get server's IP address.
            IPHostEntry hostEntry = Dns.GetHostEntry(server);

            // Create socket and connect to the server's IP address and port
            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:

C#
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.

goog02.jpg

On TahoeII:

Image 2

We can use standard buttons for navigation. Also code like that:

C#
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:

C#
// Handle the stylus down event
void p_StylusDown(object sender, StylusEventArgs e)
{
    int StylusX;
    int StylusY;
    
    // Retrieve X/Y
    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.)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)